blob: 71c33c9346c20dec6162e51912e236bb5f155e42 [file] [log] [blame]
// Copyright 2018 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <map>
#include <memory>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "base/time/time.h"
#include "components/sync/model/data_batch.h"
#include "components/sync/model/model_error.h"
#include "components/sync/model/model_type_store.h"
#include "components/sync_sessions/synced_session_tracker.h"
namespace sync_sessions {
// Class responsible for maintaining an in-memory representation of sync
// sessions (by owning a SyncedSessionTracker) with the capability to persist
// state to disk and restore (data and metadata). The API enforces a valid and
// consistent state of the model, e.g. by making sure there is at most one sync
// entity per client tag.
class SessionStore {
struct SessionInfo {
std::string session_tag;
std::string client_name;
sync_pb::SyncEnums::DeviceType device_type = sync_pb::SyncEnums::TYPE_UNSET;
using OpenCallback = base::OnceCallback<void(
const base::Optional<syncer::ModelError>& error,
std::unique_ptr<SessionStore> store,
std::unique_ptr<syncer::MetadataBatch> metadata_batch)>;
// Mimics signature of FaviconCache::UpdateMappingsFromForeignTab().
using RestoredForeignTabCallback =
base::RepeatingCallback<void(const sync_pb::SessionTab&, base::Time)>;
// Opens a SessionStore instance, which involves IO to load previous state
// from disk. |sessions_client| must not be null and must outlive the
// SessionStore instance returned via |callback|, or until the callback is
// cancelled.
static void Open(
const std::string& cache_guid,
const RestoredForeignTabCallback& restored_foreign_tab_callback,
SyncSessionsClient* sessions_client,
OpenCallback callback);
// Verifies whether a proto is malformed (e.g. required fields are missing).
static bool AreValidSpecifics(const sync_pb::SessionSpecifics& specifics);
// |specifics| must be valid, see AreValidSpecifics().
static std::string GetClientTag(const sync_pb::SessionSpecifics& specifics);
// |specifics| must be valid, see AreValidSpecifics().
static std::string GetStorageKey(const sync_pb::SessionSpecifics& specifics);
static std::string GetHeaderStorageKey(const std::string& session_tag);
static std::string GetTabStorageKey(const std::string& session_tag,
int tab_node_id);
// Verifies if |storage_key| corresponds to an entity in the local session,
// identified by the session tag.
bool StorageKeyMatchesLocalSession(const std::string& storage_key) const;
// Various equivalents for testing.
static std::string GetTabClientTagForTest(const std::string& session_tag,
int tab_node_id);
// Similar to ModelTypeStore::WriteBatch but enforces a consistent state. In
// the current implementation, some functions do *NOT* update the tracker, so
// callers are responsible for doing so.
// TODO( Enforce consistency between in-memory and persisted
// data by always updating the tracker.
class WriteBatch {
// Callback that mimics the signature of ModelTypeStore::CommitWriteBatch().
using CommitCallback = base::OnceCallback<void(
// Raw pointers must not be nullptr and must outlive this object.
WriteBatch(std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch,
CommitCallback commit_cb,
syncer::OnceModelErrorHandler error_handler,
SyncedSessionTracker* session_tracker);
// Most mutations below return storage keys.
std::string PutAndUpdateTracker(const sync_pb::SessionSpecifics& specifics,
base::Time modification_time);
// Returns all deleted storage keys, which may be more than one if
// |storage_key| refers to a header entity.
std::vector<std::string> DeleteForeignEntityAndUpdateTracker(
const std::string& storage_key);
// The functions below do not update SyncedSessionTracker and hence it is
// the caller's responsibility to do so *before* calling these functions.
std::string PutWithoutUpdatingTracker(
const sync_pb::SessionSpecifics& specifics);
std::string DeleteLocalTabWithoutUpdatingTracker(int tab_node_id);
syncer::MetadataChangeList* GetMetadataChangeList();
static void Commit(std::unique_ptr<WriteBatch> batch);
std::unique_ptr<syncer::ModelTypeStore::WriteBatch> batch_;
CommitCallback commit_cb_;
syncer::OnceModelErrorHandler error_handler_;
SyncedSessionTracker* const session_tracker_;
const SessionInfo& local_session_info() const { return local_session_info_; }
// Converts the in-memory model (SyncedSessionTracker) of sessions to sync
// protos.
std::unique_ptr<syncer::DataBatch> GetSessionDataForKeys(
const std::vector<std::string>& storage_keys) const;
// Returns all known session entities, local and foreign, generated from the
// in-memory model (SyncedSessionTracker).
std::unique_ptr<syncer::DataBatch> GetAllSessionData() const;
// Write API. WriteBatch instances must not outlive this store and must be
// committed prior to destruction. Besides, more than one uncommitted
// instance must not exist at any time.
std::unique_ptr<WriteBatch> CreateWriteBatch(
syncer::OnceModelErrorHandler error_handler);
void DeleteAllDataAndMetadata();
// TODO( Avoid exposing a mutable tracker, because that
// bypasses the consistency-enforcing API.
SyncedSessionTracker* mutable_tracker() { return &session_tracker_; }
const SyncedSessionTracker* tracker() const { return &session_tracker_; }
// Helper class used to collect all parameters needed by the constructor.
struct Builder;
static void OnStoreCreated(
std::unique_ptr<Builder> builder,
const base::Optional<syncer::ModelError>& error,
std::unique_ptr<syncer::ModelTypeStore> underlying_store);
static void OnReadAllMetadata(
std::unique_ptr<Builder> builder,
const base::Optional<syncer::ModelError>& error,
std::unique_ptr<syncer::MetadataBatch> metadata_batch);
static void OnReadAllData(std::unique_ptr<Builder> builder,
const base::Optional<syncer::ModelError>& error);
// |sessions_client| must not be null and must outlive this object.
SessionStore(const SessionInfo& local_session_info,
const RestoredForeignTabCallback& restored_foreign_tab_callback,
std::unique_ptr<syncer::ModelTypeStore> underlying_store,
std::map<std::string, sync_pb::SessionSpecifics> initial_data,
const syncer::EntityMetadataMap& initial_metadata,
SyncSessionsClient* sessions_client);
const SessionInfo local_session_info_;
const RestoredForeignTabCallback restored_foreign_tab_callback_;
// In charge of actually persisting changes to disk.
const std::unique_ptr<syncer::ModelTypeStore> store_;
SyncedSessionTracker session_tracker_;
base::WeakPtrFactory<SessionStore> weak_ptr_factory_{this};
} // namespace sync_sessions