summaryrefslogtreecommitdiffstats
path: root/sync/syncable/entry_kernel.h
blob: 064cdd46b6d1e79b0b53538c6310a4a6c1ecba89 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
// 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 SYNC_SYNCABLE_ENTRY_KERNEL_H_
#define SYNC_SYNCABLE_ENTRY_KERNEL_H_

#include <stdint.h>

#include <algorithm>
#include <map>
#include <set>
#include <string>

#include "base/time/time.h"
#include "base/values.h"
#include "sync/base/sync_export.h"
#include "sync/internal_api/public/base/model_type.h"
#include "sync/internal_api/public/base/unique_position.h"
#include "sync/internal_api/public/util/immutable.h"
#include "sync/internal_api/public/util/proto_value_ptr.h"
#include "sync/protocol/attachments.pb.h"
#include "sync/protocol/sync.pb.h"
#include "sync/syncable/metahandle_set.h"
#include "sync/syncable/syncable_id.h"
#include "sync/util/time.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 SYNC_EXPORT EntryKernel {
 private:
  typedef syncer::ProtoValuePtr<sync_pb::EntitySpecifics> EntitySpecificsPtr;
  typedef syncer::ProtoValuePtr<sync_pb::AttachmentMetadata>
      AttachmentMetadataPtr;

  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;
  }

  // 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.
  // Transfers ownership of the DictionaryValue to the caller.
  // 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.
  base::DictionaryValue* ToValue(Cryptographer* cryptographer) const;

 private:
  // Tracks whether this entry needs to be saved to the database.
  bool dirty_;
};

class EntryKernelLessByMetaHandle {
 public:
  inline bool operator()(const EntryKernel* a,
                         const EntryKernel* b) const {
    return a->ref(META_HANDLE) < b->ref(META_HANDLE);
  }
};

typedef std::set<const EntryKernel*, EntryKernelLessByMetaHandle>
    EntryKernelSet;

struct EntryKernelMutation {
  EntryKernel original, mutated;
};

typedef std::map<int64_t, EntryKernelMutation> EntryKernelMutationMap;

typedef Immutable<EntryKernelMutationMap> ImmutableEntryKernelMutationMap;

// Caller owns the return value.
base::DictionaryValue* EntryKernelMutationToValue(
    const EntryKernelMutation& mutation);

// Caller owns the return value.
base::ListValue* EntryKernelMutationMapToValue(
    const EntryKernelMutationMap& mutations);

std::ostream& operator<<(std::ostream& os, const EntryKernel& entry_kernel);

}  // namespace syncable
}  // namespace syncer

#endif  // SYNC_SYNCABLE_ENTRY_KERNEL_H_