blob: fa57de93e3e7111b077dcb95cd3a9dc666d5be75 [file] [log] [blame]
// Copyright 2012 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.
#ifndef COMPONENTS_SYNC_SYNCABLE_ENTRY_KERNEL_H_
#define COMPONENTS_SYNC_SYNCABLE_ENTRY_KERNEL_H_
#include <stdint.h>
#include <algorithm>
#include <map>
#include <memory>
#include <set>
#include <string>
#include "base/time/time.h"
#include "base/values.h"
#include "components/sync/base/immutable.h"
#include "components/sync/base/model_type.h"
#include "components/sync/base/proto_value_ptr.h"
#include "components/sync/base/time.h"
#include "components/sync/base/unique_position.h"
#include "components/sync/protocol/attachments.pb.h"
#include "components/sync/protocol/sync.pb.h"
#include "components/sync/syncable/metahandle_set.h"
#include "components/sync/syncable/syncable_id.h"
namespace syncer {
class Cryptographer;
namespace syncable {
// Things you need to update if you change any of the fields below:
// - EntryKernel struct in this file
// - syncable_columns.h
// - syncable_enum_conversions{.h,.cc,_unittest.cc}
// - EntryKernel::EntryKernel(), EntryKernel::ToValue() in entry_kernel.cc
// - operator<< in Entry.cc
// - BindFields() and UnpackEntry() in directory_backing_store.cc
// - kCurrentDBVersion, DirectoryBackingStore::InitializeTables in
// directory_backing_store.cc
// - TestSimpleFieldsPreservedDuringSaveChanges in syncable_unittest.cc
static const int64_t kInvalidMetaHandle = 0;
enum { BEGIN_FIELDS = 0, INT64_FIELDS_BEGIN = BEGIN_FIELDS };
enum MetahandleField {
// Primary key into the table. Keep this as a handle to the meta entry
// across transactions.
META_HANDLE = INT64_FIELDS_BEGIN
};
enum BaseVersion {
// After initial upload, the version is controlled by the server, and is
// increased whenever the data or metadata changes on the server.
BASE_VERSION = META_HANDLE + 1,
};
enum Int64Field {
SERVER_VERSION = BASE_VERSION + 1,
LOCAL_EXTERNAL_ID, // ID of an item in the external local storage that this
// entry is associated with. (such as bookmarks.js)
TRANSACTION_VERSION,
INT64_FIELDS_END
};
enum {
INT64_FIELDS_COUNT = INT64_FIELDS_END - INT64_FIELDS_BEGIN,
TIME_FIELDS_BEGIN = INT64_FIELDS_END,
};
enum TimeField {
MTIME = TIME_FIELDS_BEGIN,
SERVER_MTIME,
CTIME,
SERVER_CTIME,
TIME_FIELDS_END,
};
enum {
TIME_FIELDS_COUNT = TIME_FIELDS_END - TIME_FIELDS_BEGIN,
ID_FIELDS_BEGIN = TIME_FIELDS_END,
};
enum IdField {
// Code in InitializeTables relies on ID being the first IdField value.
ID = ID_FIELDS_BEGIN,
PARENT_ID,
SERVER_PARENT_ID,
ID_FIELDS_END
};
enum {
ID_FIELDS_COUNT = ID_FIELDS_END - ID_FIELDS_BEGIN,
BIT_FIELDS_BEGIN = ID_FIELDS_END
};
enum IndexedBitField {
IS_UNSYNCED = BIT_FIELDS_BEGIN,
IS_UNAPPLIED_UPDATE,
INDEXED_BIT_FIELDS_END,
};
enum IsDelField {
IS_DEL = INDEXED_BIT_FIELDS_END,
};
enum BitField {
IS_DIR = IS_DEL + 1,
SERVER_IS_DIR,
SERVER_IS_DEL,
BIT_FIELDS_END
};
enum {
BIT_FIELDS_COUNT = BIT_FIELDS_END - BIT_FIELDS_BEGIN,
STRING_FIELDS_BEGIN = BIT_FIELDS_END
};
enum StringField {
// Name, will be truncated by server. Can be duplicated in a folder.
NON_UNIQUE_NAME = STRING_FIELDS_BEGIN,
// The server version of |NON_UNIQUE_NAME|.
SERVER_NON_UNIQUE_NAME,
// A tag string which identifies this node as a particular top-level
// permanent object. The tag can be thought of as a unique key that
// identifies a singleton instance.
UNIQUE_SERVER_TAG, // Tagged by the server
UNIQUE_CLIENT_TAG, // Tagged by the client
UNIQUE_BOOKMARK_TAG, // Client tags for bookmark items
STRING_FIELDS_END,
};
enum {
STRING_FIELDS_COUNT = STRING_FIELDS_END - STRING_FIELDS_BEGIN,
PROTO_FIELDS_BEGIN = STRING_FIELDS_END
};
// From looking at the sqlite3 docs, it's not directly stated, but it
// seems the overhead for storing a null blob is very small.
enum ProtoField {
SPECIFICS = PROTO_FIELDS_BEGIN,
SERVER_SPECIFICS,
BASE_SERVER_SPECIFICS,
PROTO_FIELDS_END,
};
enum {
PROTO_FIELDS_COUNT = PROTO_FIELDS_END - PROTO_FIELDS_BEGIN,
UNIQUE_POSITION_FIELDS_BEGIN = PROTO_FIELDS_END
};
enum UniquePositionField {
SERVER_UNIQUE_POSITION = UNIQUE_POSITION_FIELDS_BEGIN,
UNIQUE_POSITION,
UNIQUE_POSITION_FIELDS_END
};
enum {
UNIQUE_POSITION_FIELDS_COUNT =
UNIQUE_POSITION_FIELDS_END - UNIQUE_POSITION_FIELDS_BEGIN,
ATTACHMENT_METADATA_FIELDS_BEGIN = UNIQUE_POSITION_FIELDS_END
};
enum AttachmentMetadataField {
ATTACHMENT_METADATA = ATTACHMENT_METADATA_FIELDS_BEGIN,
SERVER_ATTACHMENT_METADATA,
ATTACHMENT_METADATA_FIELDS_END
};
enum {
ATTACHMENT_METADATA_FIELDS_COUNT =
ATTACHMENT_METADATA_FIELDS_END - ATTACHMENT_METADATA_FIELDS_BEGIN,
FIELD_COUNT = ATTACHMENT_METADATA_FIELDS_END - BEGIN_FIELDS,
// Past this point we have temporaries, stored in memory only.
BEGIN_TEMPS = ATTACHMENT_METADATA_FIELDS_END,
BIT_TEMPS_BEGIN = BEGIN_TEMPS,
};
enum BitTemp {
// Whether a server commit operation was started and has not yet completed
// for this entity.
SYNCING = BIT_TEMPS_BEGIN,
// Whether a local change was made to an entity that had SYNCING set to true,
// and was therefore in the middle of a commit operation.
// Note: must only be set if SYNCING is true.
DIRTY_SYNC,
BIT_TEMPS_END,
};
enum { BIT_TEMPS_COUNT = BIT_TEMPS_END - BIT_TEMPS_BEGIN };
struct EntryKernel {
private:
using EntitySpecificsPtr = ProtoValuePtr<sync_pb::EntitySpecifics>;
using AttachmentMetadataPtr = ProtoValuePtr<sync_pb::AttachmentMetadata>;
std::string string_fields[STRING_FIELDS_COUNT];
EntitySpecificsPtr specifics_fields[PROTO_FIELDS_COUNT];
int64_t int64_fields[INT64_FIELDS_COUNT];
base::Time time_fields[TIME_FIELDS_COUNT];
Id id_fields[ID_FIELDS_COUNT];
UniquePosition unique_position_fields[UNIQUE_POSITION_FIELDS_COUNT];
AttachmentMetadataPtr
attachment_metadata_fields[ATTACHMENT_METADATA_FIELDS_COUNT];
std::bitset<BIT_FIELDS_COUNT> bit_fields;
std::bitset<BIT_TEMPS_COUNT> bit_temps;
friend std::ostream& operator<<(std::ostream& s, const EntryKernel& e);
public:
EntryKernel();
EntryKernel(const EntryKernel& other);
~EntryKernel();
// Set the dirty bit, and optionally add this entry's metahandle to
// a provided index on dirty bits in |dirty_index|. Parameter may be null,
// and will result only in setting the dirty bit of this entry.
inline void mark_dirty(syncable::MetahandleSet* dirty_index) {
if (!dirty_ && dirty_index) {
DCHECK_NE(0, ref(META_HANDLE));
dirty_index->insert(ref(META_HANDLE));
}
dirty_ = true;
memory_usage_ = kMemoryUsageUnknown;
}
// Clear the dirty bit, and optionally remove this entry's metahandle from
// a provided index on dirty bits in |dirty_index|. Parameter may be null,
// and will result only in clearing dirty bit of this entry.
inline void clear_dirty(syncable::MetahandleSet* dirty_index) {
if (dirty_ && dirty_index) {
DCHECK_NE(0, ref(META_HANDLE));
dirty_index->erase(ref(META_HANDLE));
}
dirty_ = false;
}
inline bool is_dirty() const { return dirty_; }
// Setters.
inline void put(MetahandleField field, int64_t value) {
int64_fields[field - INT64_FIELDS_BEGIN] = value;
}
inline void put(Int64Field field, int64_t value) {
int64_fields[field - INT64_FIELDS_BEGIN] = value;
}
inline void put(TimeField field, const base::Time& value) {
// Round-trip to proto time format and back so that we have
// consistent time resolutions (ms).
time_fields[field - TIME_FIELDS_BEGIN] =
ProtoTimeToTime(TimeToProtoTime(value));
}
inline void put(IdField field, const Id& value) {
id_fields[field - ID_FIELDS_BEGIN] = value;
}
inline void put(BaseVersion field, int64_t value) {
int64_fields[field - INT64_FIELDS_BEGIN] = value;
}
inline void put(IndexedBitField field, bool value) {
bit_fields[field - BIT_FIELDS_BEGIN] = value;
}
inline void put(IsDelField field, bool value) {
bit_fields[field - BIT_FIELDS_BEGIN] = value;
}
inline void put(BitField field, bool value) {
bit_fields[field - BIT_FIELDS_BEGIN] = value;
}
inline void put(StringField field, const std::string& value) {
string_fields[field - STRING_FIELDS_BEGIN] = value;
}
inline void put(ProtoField field, const sync_pb::EntitySpecifics& value) {
specifics_fields[field - PROTO_FIELDS_BEGIN].set_value(value);
}
inline void put(UniquePositionField field, const UniquePosition& value) {
unique_position_fields[field - UNIQUE_POSITION_FIELDS_BEGIN] = value;
}
inline void put(AttachmentMetadataField field,
const sync_pb::AttachmentMetadata& value) {
attachment_metadata_fields[field - ATTACHMENT_METADATA_FIELDS_BEGIN]
.set_value(value);
}
inline void put(BitTemp field, bool value) {
bit_temps[field - BIT_TEMPS_BEGIN] = value;
}
// Const ref getters.
inline int64_t ref(MetahandleField field) const {
return int64_fields[field - INT64_FIELDS_BEGIN];
}
inline int64_t ref(Int64Field field) const {
return int64_fields[field - INT64_FIELDS_BEGIN];
}
inline const base::Time& ref(TimeField field) const {
return time_fields[field - TIME_FIELDS_BEGIN];
}
inline const Id& ref(IdField field) const {
return id_fields[field - ID_FIELDS_BEGIN];
}
inline int64_t ref(BaseVersion field) const {
return int64_fields[field - INT64_FIELDS_BEGIN];
}
inline bool ref(IndexedBitField field) const {
return bit_fields[field - BIT_FIELDS_BEGIN];
}
inline bool ref(IsDelField field) const {
return bit_fields[field - BIT_FIELDS_BEGIN];
}
inline bool ref(BitField field) const {
return bit_fields[field - BIT_FIELDS_BEGIN];
}
inline const std::string& ref(StringField field) const {
return string_fields[field - STRING_FIELDS_BEGIN];
}
inline const sync_pb::EntitySpecifics& ref(ProtoField field) const {
return specifics_fields[field - PROTO_FIELDS_BEGIN].value();
}
inline const UniquePosition& ref(UniquePositionField field) const {
return unique_position_fields[field - UNIQUE_POSITION_FIELDS_BEGIN];
}
inline const sync_pb::AttachmentMetadata& ref(
AttachmentMetadataField field) const {
return attachment_metadata_fields[field - ATTACHMENT_METADATA_FIELDS_BEGIN]
.value();
}
inline bool ref(BitTemp field) const {
return bit_temps[field - BIT_TEMPS_BEGIN];
}
// Non-const, mutable ref getters for object types only.
inline std::string& mutable_ref(StringField field) {
return string_fields[field - STRING_FIELDS_BEGIN];
}
inline Id& mutable_ref(IdField field) {
return id_fields[field - ID_FIELDS_BEGIN];
}
inline UniquePosition& mutable_ref(UniquePositionField field) {
return unique_position_fields[field - UNIQUE_POSITION_FIELDS_BEGIN];
}
// Deserialization methods for ::google::protobuf::MessageLite derived types.
inline void load(ProtoField field, const void* blob, int length) {
specifics_fields[field - PROTO_FIELDS_BEGIN].load(blob, length);
}
inline void load(AttachmentMetadataField field,
const void* blob,
int length) {
attachment_metadata_fields[field - ATTACHMENT_METADATA_FIELDS_BEGIN].load(
blob, length);
}
// Sharing data methods for ::google::protobuf::MessageLite derived types.
inline void copy(ProtoField src, ProtoField dest) {
DCHECK_NE(src, dest);
specifics_fields[dest - PROTO_FIELDS_BEGIN] =
specifics_fields[src - PROTO_FIELDS_BEGIN];
}
inline void copy(AttachmentMetadataField src, AttachmentMetadataField dest) {
DCHECK_NE(src, dest);
attachment_metadata_fields[dest - ATTACHMENT_METADATA_FIELDS_BEGIN] =
attachment_metadata_fields[src - ATTACHMENT_METADATA_FIELDS_BEGIN];
}
ModelType GetModelType() const;
ModelType GetServerModelType() const;
bool ShouldMaintainPosition() const;
bool ShouldMaintainHierarchy() const;
// Dumps all kernel info into a DictionaryValue and returns it.
// Note: |cryptographer| is an optional parameter for use in decrypting
// encrypted specifics. If it is null or the specifics are not decryptsble,
// they will be serialized as empty proto's.
std::unique_ptr<base::DictionaryValue> ToValue(
Cryptographer* cryptographer) const;
size_t EstimateMemoryUsage() const;
private:
// Tracks whether this entry needs to be saved to the database.
bool dirty_;
mutable size_t memory_usage_;
constexpr static size_t kMemoryUsageUnknown = size_t(-1);
};
template <typename T>
class EntryKernelLessByMetaHandle {
public:
inline bool operator()(T a, T b) const {
return a->ref(META_HANDLE) < b->ref(META_HANDLE);
}
};
using EntryKernelSet =
std::set<const EntryKernel*,
EntryKernelLessByMetaHandle<const EntryKernel*>>;
using OwnedEntryKernelSet =
std::set<std::unique_ptr<EntryKernel>,
EntryKernelLessByMetaHandle<const std::unique_ptr<EntryKernel>&>>;
struct EntryKernelMutation {
EntryKernel original, mutated;
};
using EntryKernelMutationMap = std::map<int64_t, EntryKernelMutation>;
using ImmutableEntryKernelMutationMap = Immutable<EntryKernelMutationMap>;
std::unique_ptr<base::DictionaryValue> EntryKernelMutationToValue(
const EntryKernelMutation& mutation);
std::unique_ptr<base::ListValue> EntryKernelMutationMapToValue(
const EntryKernelMutationMap& mutations);
std::ostream& operator<<(std::ostream& os, const EntryKernel& entry_kernel);
} // namespace syncable
} // namespace syncer
#endif // COMPONENTS_SYNC_SYNCABLE_ENTRY_KERNEL_H_