chromium/components/sqlite_proto/key_value_data.h

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

#ifndef COMPONENTS_SQLITE_PROTO_KEY_VALUE_DATA_H_
#define COMPONENTS_SQLITE_PROTO_KEY_VALUE_DATA_H_

#include <algorithm>
#include <map>
#include <memory>
#include <optional>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

#include "base/functional/bind.h"
#include "base/functional/callback.h"
#include "base/functional/callback_helpers.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/ref_counted.h"
#include "base/sequence_checker.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "components/sqlite_proto/key_value_table.h"
#include "components/sqlite_proto/table_manager.h"

namespace sqlite_proto {

namespace internal {
// FakeCompare is a dummy comparator provided so that clients using
// KeyValueData<T> objects with unbounded-size caches need not
// specify the Compare template parameter, which is used exclusively
// for pruning the cache when it would exceed its size bound.
template <typename T>
struct FakeCompare {};
}  // namespace internal

// The class provides a synchronous access to the data backed by
// KeyValueTable<T>. The current implementation caches all the
// data in the memory. The cache size is limited by the |max_num_entries|
// parameter, using the Compare function to decide which entries should
// be evicted. The data is written back to disk periodically and some updates
// might be lost on shutdown. To prevent this data loss, one can call
// `FlushDataToDisk()` before shutting down.
//
// NOTE: If the data store is larger than the maximum cache size, it
// will be pruned on construction to satisfy the size invariant specified
// by |max_num_entries|. If this is undesirable, set a sufficiently high
// |max_num_entries| (or pass |max_num_entries| = std::nullopt for
// unbounded size).
//
// InitializeOnDBSequence() must be called on the DB sequence of the
// TableManager. All other methods must be called on UI thread.
template <typename T, typename Compare = internal::FakeCompare<T>>
class KeyValueData {
 public:
  // Constructor. Parameters:
  // - |manager| provides an interface for scheduling database tasks for
  // execution on the database thread.
  // - |backend| provides the operations for updating and querying the
  // backing database (to be scheduled and executed using |manager|).
  // - |max_num_entries|, if given, caps the size of the in-memory cache;
  // the Compare template parameter requires a meaningful (in particular,
  // non-default) value iff max_num_entries is non-nullopt.
  // - |flush_delay| is the interval for which to gather writes and deletes
  // passing them through to the backing store; a value of zero will
  // pass writes and deletes through immediately.
  KeyValueData(scoped_refptr<TableManager> manager,
               KeyValueTable<T>* backend,
               std::optional<size_t> max_num_entries,
               base::TimeDelta flush_delay);

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

  // Must be called on the provided TableManager's DB sequence
  // before calling all other methods.
  void InitializeOnDBSequence();

  // Assigns data associated with the |key| to |data|. Returns true iff the
  // |key| exists, false otherwise. |data| pointer may be nullptr to get the
  // return value only.
  bool TryGetData(const std::string& key, T* data) const;

  // Returns a view of all the cached data. (The next write or delete may
  // invalidate this reference.)
  const std::map<std::string, T>& GetAllCached() {}

  // Assigns data associated with the |key| to |data|.
  void UpdateData(const std::string& key, const T& data);

  // Deletes data associated with the |keys| from the database.
  void DeleteData(const std::vector<std::string>& keys);

  // Deletes all entries from the database.
  void DeleteAllData();

  // Force cached updates to be immediately flushed to disk.
  void FlushDataToDisk();

  // As above, but runs `on_done` when all tasks have finished flushing to disk,
  // including any previously posted tasks.
  void FlushDataToDisk(base::OnceClosure on_done);

 private:
  struct EntryCompare : private Compare {
    bool operator()(const std::pair<std::string, T>& lhs,
                    const std::pair<std::string, T>& rhs) {
      return Compare::operator()(lhs.second, rhs.second);
    }
  };

  enum class DeferredOperation { kUpdate, kDelete };

  scoped_refptr<TableManager> manager_;
  base::WeakPtr<KeyValueTable<T>> backend_table_;
  std::unique_ptr<std::map<std::string, T>> data_cache_;
  std::unordered_map<std::string, DeferredOperation> deferred_updates_;
  base::RepeatingTimer flush_timer_;
  const base::TimeDelta flush_delay_;
  const std::optional<size_t> max_num_entries_;
  EntryCompare entry_compare_;

  SEQUENCE_CHECKER(sequence_checker_);
};

template <typename T, typename Compare>
KeyValueData<T, Compare>::KeyValueData(scoped_refptr<TableManager> manager,
                                       KeyValueTable<T>* backend,
                                       std::optional<size_t> max_num_entries,
                                       base::TimeDelta flush_delay)
    :{}

template <typename T, typename Compare>
void KeyValueData<T, Compare>::InitializeOnDBSequence() {}

template <typename T, typename Compare>
bool KeyValueData<T, Compare>::TryGetData(const std::string& key,
                                          T* data) const {}

template <typename T, typename Compare>
void KeyValueData<T, Compare>::UpdateData(const std::string& key,
                                          const T& data) {}

template <typename T, typename Compare>
void KeyValueData<T, Compare>::DeleteData(
    const std::vector<std::string>& keys) {}

template <typename T, typename Compare>
void KeyValueData<T, Compare>::DeleteAllData() {}

template <typename T, typename Compare>
void KeyValueData<T, Compare>::FlushDataToDisk() {}

template <typename T, typename Compare>
void KeyValueData<T, Compare>::FlushDataToDisk(base::OnceClosure on_done) {}

}  // namespace sqlite_proto

#endif  // COMPONENTS_SQLITE_PROTO_KEY_VALUE_DATA_H_