// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef NET_DISK_CACHE_SQL_SQL_BACKEND_IMPL_H_
#define NET_DISK_CACHE_SQL_SQL_BACKEND_IMPL_H_

#include <list>
#include <map>
#include <queue>
#include <set>
#include <variant>
#include <vector>

#include "base/byte_size.h"
#include "base/files/file_path.h"
#include "base/functional/callback_helpers.h"
#include "base/memory/raw_ref.h"
#include "base/memory/ref_counted.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "base/timer/elapsed_timer.h"
#include "base/types/expected.h"
#include "base/types/strong_alias.h"
#include "net/base/net_errors.h"
#include "net/base/net_export.h"
#include "net/disk_cache/backend_cleanup_tracker.h"
#include "net/disk_cache/buildflags.h"
#include "net/disk_cache/disk_cache.h"
#include "net/disk_cache/sql/cache_entry_key.h"
#include "net/disk_cache/sql/entry_db_handle.h"
#include "net/disk_cache/sql/entry_write_buffer.h"
#include "net/disk_cache/sql/exclusive_operation_coordinator.h"
#include "net/disk_cache/sql/sql_async_task_manager.h"
#include "net/disk_cache/sql/sql_persistent_store.h"
#include "net/disk_cache/sql/sql_shared_cache_manager.h"
#include "net/disk_cache/sql/sql_write_buffer_memory_monitor.h"
#include "third_party/abseil-cpp/absl/container/flat_hash_map.h"

// This backend is experimental and only available when the build flag is set.
static_assert(BUILDFLAG(ENABLE_DISK_CACHE_SQL_BACKEND));

namespace base {
class SequencedTaskRunner;
}  // namespace base

namespace disk_cache {

class BackendCleanupTracker;
class SharedCacheClientRemote;
class SqlEntryImpl;

// Provides a concrete implementation of the disk cache backend that stores
// entries in a SQLite database. This class is responsible for all operations
// related to creating, opening, dooming, and enumerating cache entries.
//
// NOTE: This is currently a skeleton implementation, and some methods are not
// yet implemented, returning `net::ERR_NOT_IMPLEMENTED`.
class NET_EXPORT_PRIVATE SqlBackendImpl final : public Backend {
 public:
  // An enumeration of errors that can occur during the fake index file check.
  // These values are persisted to logs. Entries should not be renumbered and
  // numeric values should never be reused.
  //
  // LINT.IfChange(FakeIndexFileError)
  enum class FakeIndexFileError {
    kOkNew = 0,
    kOkExisting = 1,
    kCreateFileFailed = 2,
    kWriteFileFailed = 3,
    kWrongFileSize = 4,
    kOpenFileFailed = 5,
    kReadFileFailed = 6,
    kWrongMagicNumber = 7,
    kFailedToCreateDirectory = 8,
    kMaxValue = kFailedToCreateDirectory,
  };
  // LINT.ThenChange(//tools/metrics/histograms/metadata/net/enums.xml:SqlDiskCacheFakeIndexFileError)

  SqlBackendImpl(const base::FilePath& path,
                 int64_t max_bytes,
                 net::CacheType cache_type,
                 scoped_refptr<BackendCleanupTracker> cleanup_tracker);

  SqlBackendImpl(const SqlBackendImpl&) = delete;
  SqlBackendImpl& operator=(const SqlBackendImpl&) = delete;

  ~SqlBackendImpl() override;

  // Initializes the backend, which includes initializing the persistent store
  // and checking for a fake index file. These two operations are performed in
  // parallel.
  void Init(CompletionOnceCallback callback);

  // Backend interface.
  int64_t MaxFileSize() const override;
  base::expected<int32_t, net::Error> GetEntryCount(
      GetEntryCountCallback callback) const override;
  void SetMaxBytes(base::ByteSize max_bytes) override;
  base::ByteSize GetMaxBytesForTesting() const override;
  EntryResult OpenOrCreateEntry(const std::string& key,
                                net::RequestPriority priority,
                                EntryResultCallback callback) override;
  EntryResult OpenEntry(const std::string& key,
                        net::RequestPriority priority,
                        EntryResultCallback callback) override;
  EntryResult CreateEntry(const std::string& key,
                          net::RequestPriority priority,
                          EntryResultCallback callback) override;
  net::Error DoomEntry(const std::string& key,
                       net::RequestPriority priority,
                       CompletionOnceCallback callback) override;
  net::Error DoomAllEntries(CompletionOnceCallback callback) override;
  net::Error DoomEntriesBetween(base::Time initial_time,
                                base::Time end_time,
                                CompletionOnceCallback callback) override;
  net::Error DoomEntriesSince(base::Time initial_time,
                              CompletionOnceCallback callback) override;
  int64_t CalculateSizeOfAllEntries(
      Int64CompletionOnceCallback callback) override;
  int64_t CalculateSizeOfEntriesBetween(
      base::Time initial_time,
      base::Time end_time,
      Int64CompletionOnceCallback callback) override;
  std::unique_ptr<Iterator> CreateIterator() override;
  void GetStats(base::StringPairs* stats) override;
  void OnExternalCacheHit(const std::string& key) override;
  uint8_t GetEntryInMemoryData(const std::string& key) override;
  void OnBrowserIdle() override;

  bool SupportsSharedCache() const;
  void RegisterSharedCacheClientRemote(
      const net::NetworkIsolationKey& network_isolation_key,
      std::unique_ptr<SharedCacheClientRemote> client);
  void OnEntryEligibleForSharedCache(
      const std::string& key,
      const GURL& url,
      std::unique_ptr<net::HttpResponseInfo> response_info,
      const net::NetworkIsolationKey& network_isolation_key);

  // Called by SqlEntryImpl when it's being closed and is not doomed.
  // Removes the entry from `active_entries_`.
  void ReleaseActiveEntry(SqlEntryImpl& entry);
  // Called by SqlEntryImpl when it's being closed and is doomed.
  // Removes the entry from `doomed_entries_`.
  void ReleaseDoomedEntry(SqlEntryImpl& entry);

  // Marks an active entry as doomed and initiates its removal from the store.
  void DoomActiveEntry(SqlEntryImpl& entry);

  // Writes data and updates metadata (header and last_used) for an entry in a
  // single operation.
  void WriteEntryDataAndMetadata(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      std::optional<int64_t> old_body_end,
      int64_t body_end,
      EntryWriteBuffer buffer,
      base::Time last_used,
      const std::optional<MemoryEntryDataHints>& new_hints,
      scoped_refptr<net::GrowableIOBuffer> head_buffer,
      int64_t header_size_delta,
      CompletionOnceCallback callback);

  // Writes data to an entry's body (stream 1). This can be used to write new
  // data, overwrite existing data, or append to the entry. The operation is
  // scheduled via the `ExclusiveOperationCoordinator` to ensure proper
  // serialization.
  // If `db_handle` is in the initial state, creates entry information in the
  // DB. `last_used` is used only in that case.
  // If the backend is deleted during execution, the callback will be called
  // with net::ERR_ABORTED.
  int WriteEntryData(const CacheEntryKey& key,
                     const scoped_refptr<EntryDbHandle>& db_handle,
                     int64_t old_body_end,
                     int64_t body_end,
                     EntryWriteBuffer buffer,
                     bool truncate,
                     base::Time last_used,
                     bool sparse_write,
                     int64_t header_size,
                     bool copy_buffer_for_optimistic_write,
                     CompletionOnceCallback callback);

  // Reads data from an entry's body (stream 1). The operation is scheduled via
  // the `ExclusiveOperationCoordinator`. `sparse_reading` controls whether
  // gaps in the data are filled with zeros or cause the read to stop.
  // If the backend is deleted during execution, the callback will be called
  // with net::ERR_ABORTED.
  int ReadEntryData(const CacheEntryKey& key,
                    const scoped_refptr<EntryDbHandle>& db_handle,
                    int64_t offset,
                    scoped_refptr<net::IOBuffer> buffer,
                    int buf_len,
                    int64_t body_end,
                    bool sparse_reading,
                    SqlPersistentStore::ReadResultOrErrorCallback callback);

  // Copies data from Shared Cache to the main database blob table and then
  // executes the write operation for `buffer`. Scheduled as a normal operation
  // via `ExclusiveOperationCoordinator`.
  int CopySharedCacheToBlobTableAndWrite(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t offset,
      scoped_refptr<net::IOBuffer> buffer,
      int buf_len,
      int64_t old_body_end,
      bool truncate,
      base::Time last_used,
      bool sparse_write,
      size_t header_size,
      CompletionOnceCallback callback);

  // Finds the available contiguous range of data for a given entry. The
  // operation is scheduled via the `ExclusiveOperationCoordinator` to ensure
  // proper serialization.
  // If the backend is deleted during execution, the callback will be called
  // with net::ERR_ABORTED.
  RangeResult GetEntryAvailableRange(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t offset,
      int len,
      RangeResultCallback callback);

  // Sets the in-memory hints for the entry identified by `key` and
  // `db_handle`. This schedules an operation to update the in-memory
  // index.
  void SetEntryDataHints(const CacheEntryKey& key,
                         const scoped_refptr<EntryDbHandle>& db_handle,
                         MemoryEntryDataHints hints);

  // Returns the memory monitor for write buffers.
  SqlWriteBufferMemoryMonitor& write_buffer_monitor() {
    return write_buffer_monitor_;
  }

  // Runs the message loop until all tracked tasks are complete, for unit tests.
  void RunUntilAllTasksCompleteForTest();

  std::vector<scoped_refptr<base::SequencedTaskRunner>>&
  GetBackgroundTaskRunnersForTest() {
    return background_task_runners_;
  }

  SqlPersistentStore* GetSqlStoreForTest() { return store_.get(); }

  SqlAsyncTaskManager& async_task_manager() { return async_task_manager_; }

  SqlSharedCacheManager* GetSharedCacheManager() const {
    return store_ ? store_->GetSharedCacheManager() : nullptr;
  }

  // Enables a strict corruption checking mode for testing purposes. When
  // enabled, any detected database corruption will cause an immediate crash
  // via a `CHECK` failure. This is primarily useful for fuzzers, which can more
  // easily identify problematic inputs if the process fails fast, rather than
  // silently recovering.
  void EnableStrictCorruptionCheckForTesting();

  // Returns the current size of the `in_flight_entry_modifications_` map.
  // This is for testing purposes only.
  size_t GetSizeOfInFlightEntryModificationsMapForTesting() {
    return in_flight_entry_modifications_.size();
  }

  int64_t GetOptimisticWriteBufferTotalSizeForTesting() {
    return optimistic_write_buffer_monitor_.CurrentSize();
  }

  int64_t GetWriteBufferTotalSizeForTesting() {
    return write_buffer_monitor_.CurrentSize();
  }

  // Triggers a single pass of processing for currently eligible entries for
  // shared cache. If processing is interrupted or aborted by pending normal
  // operations, unprocessed entries are re-inserted into
  // `shared_cache_eligible_entries_`, and `scoped_closure_runner` runs when
  // this single pass completes (even if some entries remain unprocessed).
  void ProcessSharedCacheEligibleEntriesForTest(
      base::ScopedClosureRunner scoped_closure_runner,
      base::RepeatingCallback<void(const CacheEntryKey&)>
          on_entry_copied_callback);

  // Continuously triggers processing of eligible entries in a loop until
  // `shared_cache_eligible_entries_` becomes empty. Unlike
  // `ProcessSharedCacheEligibleEntriesForTest`, if any pass is interrupted or
  // aborted, remaining entries are automatically re-triggered for processing
  // until no eligible entries remain. `scoped_closure_runner` runs only after
  // all eligible entries have been processed.
  void ProcessAllSharedCacheEligibleEntriesForTest(
      base::ScopedClosureRunner scoped_closure_runner,
      base::RepeatingCallback<void(const CacheEntryKey&)>
          on_entry_copied_callback);

  size_t GetSharedCacheEligibleEntriesCountForTest() {
    return shared_cache_eligible_entries_.size();
  }

  const absl::flat_hash_map<CacheEntryKey,
                            SqlPersistentStore::SharedCacheEligibleEntry>&
  GetSharedCacheEligibleEntriesForTest() {
    return shared_cache_eligible_entries_;
  }

  ExclusiveOperationCoordinator* GetExclusiveOperationCoordinatorForTest() {
    return &exclusive_operation_coordinator_;
  }

  base::WeakPtr<SqlBackendImpl> GetWeakPtr();

 private:
  class IteratorImpl;

  // A RAII helper that ensures `PopInFlightEntryModification` is called when
  // it goes out of scope. This guarantees that an in-flight modification is
  // removed from `in_flight_entry_modifications_` once the associated operation
  // completes or is aborted.
  using PopInFlightEntryModificationRunner =
      base::StrongAlias<class PopInFlightEntryModificationRunnerTag,
                        base::ScopedClosureRunner>;

  // Identifies the type of a entry operation.
  enum class OpenOrCreateEntryOperationType {
    kCreateEntry,
    kOpenEntry,
    kOpenOrCreateEntry,
  };

  // Represents an in-flight modification to an entry's metadata (e.g.,
  // last_used, header). These modifications are queued and applied when the
  // entry is re-activated by `Iterator::OpenNextEntry()`.
  struct InFlightEntryModification {
    InFlightEntryModification(const scoped_refptr<EntryDbHandle>& db_handle,
                              base::Time last_used);
    InFlightEntryModification(const scoped_refptr<EntryDbHandle>& db_handle,
                              base::Time last_used,
                              scoped_refptr<net::GrowableIOBuffer> head);
    InFlightEntryModification(const scoped_refptr<EntryDbHandle>& db_handle,
                              base::Time last_used,
                              const std::optional<MemoryEntryDataHints>& hints,
                              scoped_refptr<net::GrowableIOBuffer> head,
                              int64_t body_end);
    InFlightEntryModification(const scoped_refptr<EntryDbHandle>& db_handle,
                              int64_t body_end);
    ~InFlightEntryModification();
    InFlightEntryModification(InFlightEntryModification&&);

    scoped_refptr<EntryDbHandle> db_handle;
    std::optional<base::Time> last_used;
    std::optional<MemoryEntryDataHints> hints;
    std::optional<scoped_refptr<net::GrowableIOBuffer>> head;
    std::optional<int64_t> body_end;
  };

  void OnInitialized(CompletionOnceCallback callback,
                     base::ElapsedTimer init_start_time,
                     const std::vector<bool>& results);
  void OnCheckFakeIndexFileFinished(CompletionOnceCallback callback,
                                    base::ElapsedTimer init_start_time,
                                    bool success);
  void OnStoreInitialized(CompletionOnceCallback callback,
                          base::ElapsedTimer init_start_time,
                          SqlPersistentStore::Error error);
  void RunDelayedPostInitializationTasks();

  SqlEntryImpl* GetActiveEntry(const CacheEntryKey& key);

  // Flushes the write buffers of all active entries.
  // This is primarily used to ensure that lazy entry creations and pending
  // writes are visible to subsequent asynchronous database operations.
  void FlushActiveEntriesBuffers() const;

  // Checks if the cache size has exceeded the high watermark and, if so,
  // schedules an eviction task. This is typically called after operations that
  // might increase the cache size. The eviction itself is run as an exclusive
  // operation to prevent conflicts with other cache activities.
  void MaybeTriggerEviction(bool is_idle_time_eviction);

  // Internal helper for Open/Create/OpenOrCreate operations. It uses
  // `ExclusiveOperationCoordinator` to serialize operations on the same key and
  // to correctly handle synchronous vs. asynchronous returns.
  EntryResult OpenOrCreateEntryInternal(OpenOrCreateEntryOperationType type,
                                        const std::string& key,
                                        EntryResultCallback callback);

  // Handles the backend logic for Open/Create/OpenOrCreate operations. This
  // method is scheduled as a normal operation via the
  // `ExclusiveOperationCoordinator` to ensure proper serialization against
  // other operations on the same key.
  void HandleOpenOrCreateEntryOperation(
      OpenOrCreateEntryOperationType type,
      const CacheEntryKey& entry_key,
      EntryResultCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Callback for store operations that return an EntryInfo (`OpenOrCreate()`,
  // `Create()`).
  void OnEntryOperationFinished(
      const CacheEntryKey& key,
      EntryResultCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle,
      SqlPersistentStore::EntryInfoOrError result);

  // Creates a new entry speculatively and returns it immediately. The actual
  // database insertion is performed in the background.
  EntryResult SpeculativeCreateEntry(
      const CacheEntryKey& entry_key,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for `DoomActiveEntry()`. This method is scheduled
  // as a normal operation via the `ExclusiveOperationCoordinator`.
  void HandleDoomActiveEntryOperation(
      scoped_refptr<SqlEntryImpl> entry,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Dooms an active entry. This method must be called while holding an
  // `ExclusiveOperationCoordinator::OperationHandle` to ensure proper
  // serialization of operations on the entry.
  void DoomActiveEntryInternal(SqlEntryImpl& entry,
                               CompletionOnceCallback callback);

  // Handles the backend logic for `ReleaseDoomedEntry()`. This method is
  // scheduled as a normal operation via the `ExclusiveOperationCoordinator`.
  void HandleDeleteDoomedEntry(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for `DoomEntry()`. This method is scheduled as a
  // normal operation via the `ExclusiveOperationCoordinator`.
  void HandleDoomEntryOperation(
      const CacheEntryKey& key,
      net::RequestPriority priority,
      CompletionOnceCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for `DoomEntriesBetween()`. This method is
  // scheduled as an exclusive operation via the
  // `ExclusiveOperationCoordinator`.
  void HandleDoomEntriesBetweenOperation(
      base::Time initial_time,
      base::Time end_time,
      CompletionOnceCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for `CalculateSizeOfEntriesBetween()`. This
  // method is scheduled as an exclusive operation via the
  // `ExclusiveOperationCoordinator`.
  void HandleCalculateSizeOfEntriesBetweenOperation(
      base::Time initial_time,
      base::Time end_time,
      Int64CompletionOnceCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for `WriteEntryDataAndMetadata()`. This method is
  // scheduled as a normal operation via the `ExclusiveOperationCoordinator`.
  void HandleWriteEntryDataAndMetadataOperation(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      std::optional<int64_t> old_body_end,
      EntryWriteBuffer buffer,
      base::Time last_used,
      const std::optional<MemoryEntryDataHints>& new_hints,
      scoped_refptr<net::GrowableIOBuffer> head_buffer,
      int64_t header_size_delta,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      SqlPersistentStore::ResIdOrErrorCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for a non-optimistic write operation. This method
  // is scheduled as a normal operation via the `ExclusiveOperationCoordinator`
  // and forwards the call to the persistent store.
  void HandleWriteEntryDataOperation(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t old_body_end,
      EntryWriteBuffer buffer,
      bool truncate,
      base::Time last_used,
      bool sparse_write,
      int64_t header_size,
      SqlPersistentStore::ResIdOrErrorCallback callback,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for an optimistic write operation. This method is
  // scheduled as a normal operation via the `ExclusiveOperationCoordinator` and
  // forwards the write to the persistent store.
  void HandleOptimisticWriteEntryDataOperation(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t old_body_end,
      EntryWriteBuffer buffer,
      bool truncate,
      base::Time last_used,
      bool sparse_write,
      int64_t header_size,
      SqlPersistentStore::ResIdOrErrorCallback callback,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Called when an optimistic write is finished.
  void OnOptimisticWriteFinished(
      const CacheEntryKey& key,
      std::optional<SqlPersistentStore::ResId> res_id,
      SqlPersistentStore::ResIdOrErrorCallback callback,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle,
      SqlPersistentStore::ResIdOrError result);

  // Handles the backend logic for `ReadEntryData()`. This method is scheduled
  // as a normal operation via the `ExclusiveOperationCoordinator` and forwards
  // the call to the persistent store.
  void HandleReadEntryDataOperation(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t offset,
      scoped_refptr<net::IOBuffer> buffer,
      int buf_len,
      int64_t body_end,
      bool sparse_reading,
      SqlPersistentStore::ReadResultOrErrorCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  void HandleCopySharedCacheToBlobTableOperation(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t offset,
      scoped_refptr<net::IOBuffer> buffer,
      int buf_len,
      int64_t old_body_end,
      bool truncate,
      base::Time last_used,
      bool sparse_write,
      size_t header_size,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      CompletionOnceCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  void DoCopySharedCacheToBlobTableStep(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t offset,
      scoped_refptr<net::IOBuffer> buffer,
      int buf_len,
      int64_t old_body_end,
      bool truncate,
      base::Time last_used,
      bool sparse_write,
      size_t header_size,
      int64_t copy_offset,
      scoped_refptr<net::IOBuffer> copy_buffer,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      CompletionOnceCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  void OnReadFromSharedCacheForCopy(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t offset,
      scoped_refptr<net::IOBuffer> buffer,
      int buf_len,
      int64_t old_body_end,
      bool truncate,
      base::Time last_used,
      bool sparse_write,
      size_t header_size,
      int64_t copy_offset,
      scoped_refptr<net::IOBuffer> copy_buffer,
      int bytes_to_read,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      CompletionOnceCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle,
      SqlPersistentStore::ReadResultOrError result);

  void OnWriteToBlobTableForCopy(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t offset,
      scoped_refptr<net::IOBuffer> buffer,
      int buf_len,
      int64_t old_body_end,
      bool truncate,
      base::Time last_used,
      bool sparse_write,
      size_t header_size,
      int64_t copy_offset,
      scoped_refptr<net::IOBuffer> copy_buffer,
      int bytes_written,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      CompletionOnceCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle,
      SqlPersistentStore::ResIdOrError result);

  // Handles the backend logic for `GetEntryAvailableRange()`. This method is
  // scheduled as a normal operation via the `ExclusiveOperationCoordinator`
  // and forwards the call to the persistent store.
  void HandleGetEntryAvailableRangeOperation(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      int64_t offset,
      int len,
      RangeResultCallback callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the operation to set in-memory hints. This is called by the
  // `ExclusiveOperationCoordinator` to ensure that `db_handle` is
  // properly set (e.g., if the entry creation is still in progress).
  void HandleSetEntryDataHintsOperation(
      const CacheEntryKey& key,
      const scoped_refptr<EntryDbHandle>& db_handle,
      MemoryEntryDataHints hints,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for cache eviction. This method is scheduled as
  // an exclusive operation to ensure no other cache activities are running. It
  // gathers the keys of all active entries to prevent them from being evicted
  // and then delegates the actual eviction logic to the persistent store.
  void HandleTriggerEvictionOperation(
      bool is_idle_time_eviction,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Handles the backend logic for `OnExternalCacheHit()`. This method is
  // scheduled as a normal operation via the `ExclusiveOperationCoordinator`.
  void HandleOnExternalCacheHitOperation(
      const CacheEntryKey& key,
      base::Time now,
      PopInFlightEntryModificationRunner pop_in_flight_entry_modification,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  // Adds an `InFlightEntryModification` to the queue for `entry_key` and
  // returns a `PopInFlightEntryModificationRunner`. The returned runner ensures
  // that the modification is removed from the queue when the runner goes out of
  // scope, guaranteeing proper cleanup even in error paths.
  PopInFlightEntryModificationRunner PushInFlightEntryModification(
      const CacheEntryKey& entry_key,
      InFlightEntryModification in_flight_entry_modification);

  // Removes the oldest `InFlightEntryModification` from the queue for
  // `entry_key`. This is called by `PopInFlightEntryModificationRunner` when
  // an operation completes or is aborted.
  void PopInFlightEntryModification(const CacheEntryKey& entry_key);

  // Applies in-flight modifications to an entry's info.
  void ApplyInFlightEntryModifications(
      const CacheEntryKey& key,
      SqlPersistentStore::EntryInfo& entry_info);

  void ProcessSharedCacheEligibleEntries(
      base::ScopedClosureRunner scoped_closure_runner,
      base::RepeatingCallback<void(const CacheEntryKey&)>
          on_entry_copied_callback);

  void HandleProcessSharedCacheEligibleEntries(
      base::ScopedClosureRunner scoped_closure_runner,
      base::RepeatingCallback<void(const CacheEntryKey&)>
          on_entry_copied_callback,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle);

  void OnProcessSharedCacheEligibleEntriesComplete(
      base::ScopedClosureRunner scoped_closure_runner,
      std::unique_ptr<ExclusiveOperationCoordinator::OperationHandle> handle,
      std::vector<SqlPersistentStore::SharedCacheEligibleEntry>
          unprocessed_entries);

  SqlAsyncTaskManager async_task_manager_;

  scoped_refptr<BackendCleanupTracker> cleanup_tracker_;

  const base::FilePath path_;

  // Task runners for background SQLite operations.
  std::vector<scoped_refptr<base::SequencedTaskRunner>>
      background_task_runners_;

  // The persistent store that manages the SQLite database.
  std::unique_ptr<SqlPersistentStore> store_;

  // Coordinates exclusive and normal operations to ensure that exclusive
  // operations have exclusive access. This must be declared before
  // `active_entries_` and `doomed_entries_` to ensure it is destroyed after
  // them. This is critical because `exclusive_operation_coordinator_` may hold
  // the last `scoped_refptr` to a `SqlEntryImpl`.
  ExclusiveOperationCoordinator exclusive_operation_coordinator_;

  // Map of cache keys to currently active (opened) entries.
  // `raw_ref` is used because the SqlEntryImpl objects are ref-counted and
  // their lifetime is managed by their ref_count. This map only holds
  // non-owning references to them.
  std::map<CacheEntryKey, raw_ref<SqlEntryImpl>> active_entries_;

  // Set of entries that have been marked as doomed but are still active
  // (i.e., have outstanding references).
  std::set<raw_ref<const SqlEntryImpl>> doomed_entries_;

  // Queue of in-flight entry modifications that need to be applied.
  // These are typically updates to `last_used` or header data that occur
  // while an entry is not actively open.
  std::map<CacheEntryKey, std::list<InFlightEntryModification>>
      in_flight_entry_modifications_;

  // A flag to prevent queuing multiple eviction operations. It is set to true
  // when an eviction operation is posted to the `ExclusiveOperationCoordinator`
  // and reset to false when the operation begins execution. This ensures that
  // even if `MaybeTriggerEviction()` is called multiple times while an eviction
  // task is pending, only one will be in the queue at any time.
  bool eviction_operation_queued_ = false;

  // Monitors and limits the memory usage for optimistic writes to stream 1.
  // Optimistic writes allow the backend to complete write operations
  // immediately by posting the operation to a background sequence and returning
  // the result synchronously, assuming success. This monitor ensures that the
  // total size of data pending in these operations does not exceed
  // `kSqlDiskCacheOptimisticWriteBufferSize`.
  SqlWriteBufferMemoryMonitor optimistic_write_buffer_monitor_;

  // Monitors and limits the total memory usage of write buffers across all
  // open entries. Entries buffer sequential writes to stream 1 up to
  // `kSqlDiskCacheMaxWriteBufferSizePerEntry` before flushing to the backend.
  // This monitor limits the aggregate size of these buffers to
  // `kSqlDiskCacheMaxWriteBufferTotalSize`. When a buffer is flushed, the
  // reservation is released. If the flush is handled as an optimistic write,
  // the reservation is effectively transferred to
  // `optimistic_write_buffer_monitor_`.
  SqlWriteBufferMemoryMonitor write_buffer_monitor_;

  // Cached value of `net::features::kSqlDiskCacheReduceUma`.
  const bool reduce_uma_;

  // Entries that are eligible for the shared cache and pending processing.
  // Entries are registered via `OnEntryEligibleForSharedCache` and processed
  // asynchronously during browser idle time or via explicit test calls.
  // Unprocessed entries (e.g., due to aborts from concurrent operations) are
  // re-inserted here for subsequent processing.
  absl::flat_hash_map<CacheEntryKey,
                      SqlPersistentStore::SharedCacheEligibleEntry>
      shared_cache_eligible_entries_;

  // Weak pointer factory for this class.
  base::WeakPtrFactory<SqlBackendImpl> weak_factory_{this};
};

}  // namespace disk_cache

#endif  // NET_DISK_CACHE_SQL_SQL_BACKEND_IMPL_H_
