1// Copyright 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef SYNC_SYNCABLE_ENTRY_KERNEL_H_
6#define SYNC_SYNCABLE_ENTRY_KERNEL_H_
7
8#include <set>
9
10#include "base/time/time.h"
11#include "base/values.h"
12#include "sync/base/sync_export.h"
13#include "sync/internal_api/public/base/model_type.h"
14#include "sync/internal_api/public/base/unique_position.h"
15#include "sync/internal_api/public/util/immutable.h"
16#include "sync/protocol/sync.pb.h"
17#include "sync/syncable/metahandle_set.h"
18#include "sync/syncable/syncable_id.h"
19#include "sync/util/time.h"
20
21namespace syncer {
22
23class Cryptographer;
24
25namespace syncable {
26
27// Things you need to update if you change any of the fields below:
28//  - EntryKernel struct in this file
29//  - syncable_columns.h
30//  - syncable_enum_conversions{.h,.cc,_unittest.cc}
31//  - EntryKernel::EntryKernel(), EntryKernel::ToValue() in entry_kernel.cc
32//  - operator<< in Entry.cc
33//  - BindFields() and UnpackEntry() in directory_backing_store.cc
34//  - TestSimpleFieldsPreservedDuringSaveChanges in syncable_unittest.cc
35
36static const int64 kInvalidMetaHandle = 0;
37
38enum {
39  BEGIN_FIELDS = 0,
40  INT64_FIELDS_BEGIN = BEGIN_FIELDS
41};
42
43enum MetahandleField {
44  // Primary key into the table.  Keep this as a handle to the meta entry
45  // across transactions.
46  META_HANDLE = INT64_FIELDS_BEGIN
47};
48
49enum BaseVersion {
50  // After initial upload, the version is controlled by the server, and is
51  // increased whenever the data or metadata changes on the server.
52  BASE_VERSION = META_HANDLE + 1,
53};
54
55enum Int64Field {
56  SERVER_VERSION = BASE_VERSION + 1,
57  LOCAL_EXTERNAL_ID,  // ID of an item in the external local storage that this
58                      // entry is associated with. (such as bookmarks.js)
59  TRANSACTION_VERSION,
60  INT64_FIELDS_END
61};
62
63enum {
64  INT64_FIELDS_COUNT = INT64_FIELDS_END - INT64_FIELDS_BEGIN,
65  TIME_FIELDS_BEGIN = INT64_FIELDS_END,
66};
67
68enum TimeField {
69  MTIME = TIME_FIELDS_BEGIN,
70  SERVER_MTIME,
71  CTIME,
72  SERVER_CTIME,
73  TIME_FIELDS_END,
74};
75
76enum {
77  TIME_FIELDS_COUNT = TIME_FIELDS_END - TIME_FIELDS_BEGIN,
78  ID_FIELDS_BEGIN = TIME_FIELDS_END,
79};
80
81enum IdField {
82  // Code in InitializeTables relies on ID being the first IdField value.
83  ID = ID_FIELDS_BEGIN,
84  PARENT_ID,
85  SERVER_PARENT_ID,
86  ID_FIELDS_END
87};
88
89enum {
90  ID_FIELDS_COUNT = ID_FIELDS_END - ID_FIELDS_BEGIN,
91  BIT_FIELDS_BEGIN = ID_FIELDS_END
92};
93
94enum IndexedBitField {
95  IS_UNSYNCED = BIT_FIELDS_BEGIN,
96  IS_UNAPPLIED_UPDATE,
97  INDEXED_BIT_FIELDS_END,
98};
99
100enum IsDelField {
101  IS_DEL = INDEXED_BIT_FIELDS_END,
102};
103
104enum BitField {
105  IS_DIR = IS_DEL + 1,
106  SERVER_IS_DIR,
107  SERVER_IS_DEL,
108  BIT_FIELDS_END
109};
110
111enum {
112  BIT_FIELDS_COUNT = BIT_FIELDS_END - BIT_FIELDS_BEGIN,
113  STRING_FIELDS_BEGIN = BIT_FIELDS_END
114};
115
116enum StringField {
117  // Name, will be truncated by server. Can be duplicated in a folder.
118  NON_UNIQUE_NAME = STRING_FIELDS_BEGIN,
119  // The server version of |NON_UNIQUE_NAME|.
120  SERVER_NON_UNIQUE_NAME,
121
122  // A tag string which identifies this node as a particular top-level
123  // permanent object.  The tag can be thought of as a unique key that
124  // identifies a singleton instance.
125  UNIQUE_SERVER_TAG,  // Tagged by the server
126  UNIQUE_CLIENT_TAG,  // Tagged by the client
127  UNIQUE_BOOKMARK_TAG,  // Client tags for bookmark items
128  STRING_FIELDS_END,
129};
130
131enum {
132  STRING_FIELDS_COUNT = STRING_FIELDS_END - STRING_FIELDS_BEGIN,
133  PROTO_FIELDS_BEGIN = STRING_FIELDS_END
134};
135
136// From looking at the sqlite3 docs, it's not directly stated, but it
137// seems the overhead for storing a NULL blob is very small.
138enum ProtoField {
139  SPECIFICS = PROTO_FIELDS_BEGIN,
140  SERVER_SPECIFICS,
141  BASE_SERVER_SPECIFICS,
142  PROTO_FIELDS_END,
143};
144
145enum {
146  PROTO_FIELDS_COUNT = PROTO_FIELDS_END - PROTO_FIELDS_BEGIN,
147  UNIQUE_POSITION_FIELDS_BEGIN = PROTO_FIELDS_END
148};
149
150enum UniquePositionField {
151  SERVER_UNIQUE_POSITION = UNIQUE_POSITION_FIELDS_BEGIN,
152  UNIQUE_POSITION,
153  UNIQUE_POSITION_FIELDS_END
154};
155
156enum {
157  UNIQUE_POSITION_FIELDS_COUNT =
158      UNIQUE_POSITION_FIELDS_END - UNIQUE_POSITION_FIELDS_BEGIN,
159  FIELD_COUNT = UNIQUE_POSITION_FIELDS_END - BEGIN_FIELDS,
160  // Past this point we have temporaries, stored in memory only.
161  BEGIN_TEMPS = UNIQUE_POSITION_FIELDS_END,
162  BIT_TEMPS_BEGIN = BEGIN_TEMPS,
163};
164
165enum BitTemp {
166  // Not to be confused with IS_UNSYNCED, this bit is used to detect local
167  // changes to items that happen during the server Commit operation.
168  SYNCING = BIT_TEMPS_BEGIN,
169  BIT_TEMPS_END,
170};
171
172enum {
173  BIT_TEMPS_COUNT = BIT_TEMPS_END - BIT_TEMPS_BEGIN
174};
175
176
177
178struct SYNC_EXPORT_PRIVATE EntryKernel {
179 private:
180  std::string string_fields[STRING_FIELDS_COUNT];
181  sync_pb::EntitySpecifics specifics_fields[PROTO_FIELDS_COUNT];
182  int64 int64_fields[INT64_FIELDS_COUNT];
183  base::Time time_fields[TIME_FIELDS_COUNT];
184  Id id_fields[ID_FIELDS_COUNT];
185  UniquePosition unique_position_fields[UNIQUE_POSITION_FIELDS_COUNT];
186  std::bitset<BIT_FIELDS_COUNT> bit_fields;
187  std::bitset<BIT_TEMPS_COUNT> bit_temps;
188
189 public:
190  EntryKernel();
191  ~EntryKernel();
192
193  // Set the dirty bit, and optionally add this entry's metahandle to
194  // a provided index on dirty bits in |dirty_index|. Parameter may be null,
195  // and will result only in setting the dirty bit of this entry.
196  inline void mark_dirty(syncable::MetahandleSet* dirty_index) {
197    if (!dirty_ && dirty_index) {
198      DCHECK_NE(0, ref(META_HANDLE));
199      dirty_index->insert(ref(META_HANDLE));
200    }
201    dirty_ = true;
202  }
203
204  // Clear the dirty bit, and optionally remove this entry's metahandle from
205  // a provided index on dirty bits in |dirty_index|. Parameter may be null,
206  // and will result only in clearing dirty bit of this entry.
207  inline void clear_dirty(syncable::MetahandleSet* dirty_index) {
208    if (dirty_ && dirty_index) {
209      DCHECK_NE(0, ref(META_HANDLE));
210      dirty_index->erase(ref(META_HANDLE));
211    }
212    dirty_ = false;
213  }
214
215  inline bool is_dirty() const {
216    return dirty_;
217  }
218
219  // Setters.
220  inline void put(MetahandleField field, int64 value) {
221    int64_fields[field - INT64_FIELDS_BEGIN] = value;
222  }
223  inline void put(Int64Field field, int64 value) {
224    int64_fields[field - INT64_FIELDS_BEGIN] = value;
225  }
226  inline void put(TimeField field, const base::Time& value) {
227    // Round-trip to proto time format and back so that we have
228    // consistent time resolutions (ms).
229    time_fields[field - TIME_FIELDS_BEGIN] =
230        ProtoTimeToTime(TimeToProtoTime(value));
231  }
232  inline void put(IdField field, const Id& value) {
233    id_fields[field - ID_FIELDS_BEGIN] = value;
234  }
235  inline void put(BaseVersion field, int64 value) {
236    int64_fields[field - INT64_FIELDS_BEGIN] = value;
237  }
238  inline void put(IndexedBitField field, bool value) {
239    bit_fields[field - BIT_FIELDS_BEGIN] = value;
240  }
241  inline void put(IsDelField field, bool value) {
242    bit_fields[field - BIT_FIELDS_BEGIN] = value;
243  }
244  inline void put(BitField field, bool value) {
245    bit_fields[field - BIT_FIELDS_BEGIN] = value;
246  }
247  inline void put(StringField field, const std::string& value) {
248    string_fields[field - STRING_FIELDS_BEGIN] = value;
249  }
250  inline void put(ProtoField field, const sync_pb::EntitySpecifics& value) {
251    specifics_fields[field - PROTO_FIELDS_BEGIN].CopyFrom(value);
252  }
253  inline void put(UniquePositionField field, const UniquePosition& value) {
254    unique_position_fields[field - UNIQUE_POSITION_FIELDS_BEGIN] = value;
255  }
256  inline void put(BitTemp field, bool value) {
257    bit_temps[field - BIT_TEMPS_BEGIN] = value;
258  }
259
260  // Const ref getters.
261  inline int64 ref(MetahandleField field) const {
262    return int64_fields[field - INT64_FIELDS_BEGIN];
263  }
264  inline int64 ref(Int64Field field) const {
265    return int64_fields[field - INT64_FIELDS_BEGIN];
266  }
267  inline const base::Time& ref(TimeField field) const {
268    return time_fields[field - TIME_FIELDS_BEGIN];
269  }
270  inline const Id& ref(IdField field) const {
271    return id_fields[field - ID_FIELDS_BEGIN];
272  }
273  inline int64 ref(BaseVersion field) const {
274    return int64_fields[field - INT64_FIELDS_BEGIN];
275  }
276  inline bool ref(IndexedBitField field) const {
277    return bit_fields[field - BIT_FIELDS_BEGIN];
278  }
279  inline bool ref(IsDelField field) const {
280    return bit_fields[field - BIT_FIELDS_BEGIN];
281  }
282  inline bool ref(BitField field) const {
283    return bit_fields[field - BIT_FIELDS_BEGIN];
284  }
285  inline const std::string& ref(StringField field) const {
286    return string_fields[field - STRING_FIELDS_BEGIN];
287  }
288  inline const sync_pb::EntitySpecifics& ref(ProtoField field) const {
289    return specifics_fields[field - PROTO_FIELDS_BEGIN];
290  }
291  inline const UniquePosition& ref(UniquePositionField field) const {
292    return unique_position_fields[field - UNIQUE_POSITION_FIELDS_BEGIN];
293  }
294  inline bool ref(BitTemp field) const {
295    return bit_temps[field - BIT_TEMPS_BEGIN];
296  }
297
298  // Non-const, mutable ref getters for object types only.
299  inline std::string& mutable_ref(StringField field) {
300    return string_fields[field - STRING_FIELDS_BEGIN];
301  }
302  inline sync_pb::EntitySpecifics& mutable_ref(ProtoField field) {
303    return specifics_fields[field - PROTO_FIELDS_BEGIN];
304  }
305  inline Id& mutable_ref(IdField field) {
306    return id_fields[field - ID_FIELDS_BEGIN];
307  }
308  inline UniquePosition& mutable_ref(UniquePositionField field) {
309    return unique_position_fields[field - UNIQUE_POSITION_FIELDS_BEGIN];
310  }
311
312  ModelType GetModelType() const;
313  ModelType GetServerModelType() const;
314  bool ShouldMaintainPosition() const;
315
316  // Dumps all kernel info into a DictionaryValue and returns it.
317  // Transfers ownership of the DictionaryValue to the caller.
318  // Note: |cryptographer| is an optional parameter for use in decrypting
319  // encrypted specifics. If it is NULL or the specifics are not decryptsble,
320  // they will be serialized as empty proto's.
321  base::DictionaryValue* ToValue(Cryptographer* cryptographer) const;
322
323 private:
324  // Tracks whether this entry needs to be saved to the database.
325  bool dirty_;
326};
327
328class EntryKernelLessByMetaHandle {
329 public:
330  inline bool operator()(const EntryKernel* a,
331                         const EntryKernel* b) const {
332    return a->ref(META_HANDLE) < b->ref(META_HANDLE);
333  }
334};
335
336typedef std::set<const EntryKernel*, EntryKernelLessByMetaHandle>
337    EntryKernelSet;
338
339struct EntryKernelMutation {
340  EntryKernel original, mutated;
341};
342
343typedef std::map<int64, EntryKernelMutation> EntryKernelMutationMap;
344
345typedef Immutable<EntryKernelMutationMap> ImmutableEntryKernelMutationMap;
346
347// Caller owns the return value.
348base::DictionaryValue* EntryKernelMutationToValue(
349    const EntryKernelMutation& mutation);
350
351// Caller owns the return value.
352base::ListValue* EntryKernelMutationMapToValue(
353    const EntryKernelMutationMap& mutations);
354
355}  // namespace syncable
356}  // namespace syncer
357
358#endif // SYNC_SYNCABLE_ENTRY_KERNEL_H_
359