chromium/chrome/browser/ash/file_system_provider/content_cache/cache_file_context.h

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

#ifndef CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_CACHE_FILE_CONTEXT_H_
#define CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_CACHE_FILE_CONTEXT_H_

#include <functional>
#include <map>
#include <utility>

#include "base/files/file_path.h"
#include "base/time/time.h"
#include "chrome/browser/ash/file_system_provider/content_cache/local_fd.h"
#include "chrome/browser/ash/file_system_provider/opened_cloud_file.h"

namespace ash::file_system_provider {

// Helper to explain the "-1" that is used to denote an unknown ID.
inline constexpr int kUnknownId = -1;

// Context relating to a file that is cached on disk. Used to make decisions
// around evicting files from the cache (e.g. until N bytes have been evicted)
// and guard against multiple writers to a single file.
class CacheFileContext {
 public:
  // When repopulating the context on session startup with the file information
  // that is already cached on disk, use the `bytes_on_disk`, `id` and
  // `path_on_disk` fields. Otherwise leave the default values.
  explicit CacheFileContext(
      const std::string& version_tag,
      int64_t bytes_on_disk = 0,
      int64_t id = kUnknownId,
      const base::FilePath& path_on_disk = base::FilePath());

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

  ~CacheFileContext();

  bool HasLocalFDs() const { return !open_fds_.empty(); }
  bool CanGetLocalFD(const OpenedCloudFile& file) const;
  LocalFD& GetLocalFD(const OpenedCloudFile& file,
                      scoped_refptr<base::SequencedTaskRunner> io_task_runner);
  bool CloseLocalFD(int request_id) { return open_fds_.erase(request_id) == 1; }

  int64_t bytes_on_disk() const { return bytes_on_disk_; }
  void set_bytes_on_disk(int64_t bytes_on_disk) {
    bytes_on_disk_ = bytes_on_disk;
  }

  base::Time accessed_time() const { return accessed_time_; }
  void set_accessed_time(base::Time accessed_time) {
    accessed_time_ = accessed_time;
  }

  const std::string& version_tag() const { return version_tag_; }

  int64_t id() const { return id_; }
  void set_id(int64_t id) { id_ = id; }

  const base::FilePath& path_on_disk() const { return path_on_disk_; }
  void set_path_on_disk(const base::FilePath& path_on_disk) {
    path_on_disk_ = path_on_disk;
  }

  bool has_writer() const { return has_writer_; }
  void set_has_writer(bool has_writer) { has_writer_ = has_writer; }

  bool evicted() const { return evicted_; }
  void set_evicted(bool evicted) { evicted_ = evicted; }

  bool removal_in_progress() const { return removal_in_progress_; }
  void set_removal_in_progress(bool removal_in_progress) {
    removal_in_progress_ = removal_in_progress;
  }

 private:
  // The number of contiguous bytes that are written to this file currently. If
  // a file write is in progress, this might not represent the entire size of
  // the file on disk.
  int64_t bytes_on_disk_;

  // The latest access time, cryptohome is mounted with MS_NOATIME so we need to
  // keep track of this separately.
  base::Time accessed_time_ = base::Time::Now();

  // The version tag for this specific file. This is read-only as the version
  // can never be changed without deleting the context for the file and
  // replacing it with an updated version.
  const std::string version_tag_;

  // A unique ID associated with this file that is used to write the file on
  // disk.
  int64_t id_;

  // The path of the cached file on disk.
  base::FilePath path_on_disk_;

  // True if there is an open writer to this file, multiple writers at
  // disjoint offset ranges is currently not supported.
  bool has_writer_ = false;

  // Evicted items are scheduled to be removed from disk and the database, so
  // any further use should be disallowed.
  bool evicted_ = false;

  // True if the removal of this item has started.
  bool removal_in_progress_ = false;

  // A map (keyed by request ID) that represents any open file descriptors for
  // this specific file.
  std::map<int, LocalFD> open_fds_;
};

using PathContextPair = std::pair<base::FilePath, CacheFileContext>;

}  // namespace ash::file_system_provider

template <>
struct std::hash<ash::file_system_provider::CacheFileContext> {
  // Enables the key to be retrieved from the std::pair that represents the
  // key-value pair in the LRU cache.
  constexpr const base::FilePath& operator()(
      const ash::file_system_provider::PathContextPair& pair) {
    return pair.first;
  }

  // Returns a hash for the std::pair to enable O(1) lookup in the
  // base::HashingLRUCache (hashes the std::string representation of the
  // base::FilePath key).
  constexpr size_t operator()(
      const ash::file_system_provider::PathContextPair& pair) const {
    return std::hash<std::string>{}(pair.first.value());
  }
};

#endif  // CHROME_BROWSER_ASH_FILE_SYSTEM_PROVIDER_CONTENT_CACHE_CACHE_FILE_CONTEXT_H_