File: synced_bookmark_tracker.h

package info (click to toggle)
chromium 138.0.7204.92-1
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 6,071,576 kB
  • sloc: cpp: 34,933,512; ansic: 7,176,967; javascript: 4,110,704; python: 1,419,953; asm: 946,768; xml: 739,956; pascal: 187,324; sh: 89,623; perl: 88,663; objc: 79,944; sql: 50,304; cs: 41,786; fortran: 24,137; makefile: 21,806; php: 13,980; tcl: 13,166; yacc: 8,925; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (318 lines) | stat: -rw-r--r-- 13,378 bytes parent folder | download | duplicates (3)
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
// Copyright 2018 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_SYNC_BOOKMARKS_SYNCED_BOOKMARK_TRACKER_H_
#define COMPONENTS_SYNC_BOOKMARKS_SYNCED_BOOKMARK_TRACKER_H_

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

#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/time/time.h"
#include "base/uuid.h"
#include "components/sync/base/client_tag_hash.h"
#include "components/sync/protocol/data_type_state.pb.h"

namespace sync_pb {
class BookmarkModelMetadata;
class EntitySpecifics;
}  // namespace sync_pb

namespace bookmarks {
class BookmarkNode;
}  // namespace bookmarks

namespace sync_bookmarks {

class BookmarkModelView;
class SyncedBookmarkTrackerEntity;

// This class is responsible for keeping the mapping between bookmark nodes in
// the local model and the server-side corresponding sync entities. It manages
// the metadata for its entities and caches entity data upon a local change
// until commit confirmation is received.
class SyncedBookmarkTracker {
 public:
  // Returns a client tag hash given a bookmark UUID.
  static syncer::ClientTagHash GetClientTagHashFromUuid(const base::Uuid& uuid);

  // Creates an empty instance with no entities. Never returns null.
  static std::unique_ptr<SyncedBookmarkTracker> CreateEmpty(
      sync_pb::DataTypeState data_type_state);

  // Loads a tracker from a proto (usually from disk) after enforcing the
  // consistency of the metadata against the BookmarkModel. Returns null if the
  // data is inconsistent with sync metadata (i.e. corrupt). `model` must not be
  // null.
  static std::unique_ptr<SyncedBookmarkTracker>
  CreateFromBookmarkModelAndMetadata(
      const BookmarkModelView* model,
      sync_pb::BookmarkModelMetadata model_metadata);

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

  ~SyncedBookmarkTracker();

  // This method is used to denote that all bookmarks are reuploaded and there
  // is no need to reupload them again after next browser startup.
  void SetBookmarksReuploaded();

  // Returns null if no entity is found.
  const SyncedBookmarkTrackerEntity* GetEntityForSyncId(
      const std::string& sync_id) const;

  // Returns null if no entity is found.
  const SyncedBookmarkTrackerEntity* GetEntityForClientTagHash(
      const syncer::ClientTagHash& client_tag_hash) const;

  // Convenience function, similar to GetEntityForClientTagHash().
  const SyncedBookmarkTrackerEntity* GetEntityForUuid(
      const base::Uuid& uuid) const;

  // Returns null if no entity is found.
  const SyncedBookmarkTrackerEntity* GetEntityForBookmarkNode(
      const bookmarks::BookmarkNode* node) const;

  // Starts tracking local bookmark `bookmark_node`, which must not be tracked
  // beforehand. The rest of the arguments represent the initial metadata.
  // Returns the tracked entity.
  const SyncedBookmarkTrackerEntity* Add(
      const bookmarks::BookmarkNode* bookmark_node,
      const std::string& sync_id,
      int64_t server_version,
      base::Time creation_time,
      const sync_pb::EntitySpecifics& specifics);

  // Updates the sync metadata for a tracked entity. `entity` must be owned by
  // this tracker.
  void Update(const SyncedBookmarkTrackerEntity* entity,
              int64_t server_version,
              base::Time modification_time,
              const sync_pb::EntitySpecifics& specifics);

  // Updates the server version of an existing entity. `entity` must be owned by
  // this tracker.
  void UpdateServerVersion(const SyncedBookmarkTrackerEntity* entity,
                           int64_t server_version);

  // Marks an existing entry that a commit request might have been sent to the
  // server. `entity` must be owned by this tracker.
  void MarkCommitMayHaveStarted(const SyncedBookmarkTrackerEntity* entity);

  // This class maintains the order of calls to this method and the same order
  // is guaranteed when returning local changes in
  // GetEntitiesWithLocalChanges() as well as in BuildBookmarkModelMetadata().
  // `entity` must be owned by this tracker. `location` is used to propagate
  // debug information about which piece of code triggered the deletion.
  void MarkDeleted(const SyncedBookmarkTrackerEntity* entity,
                   const base::Location& location);

  // Untracks an entity, which also invalidates the pointer. `entity` must be
  // owned by this tracker.
  void Remove(const SyncedBookmarkTrackerEntity* entity);

  // Increment sequence number in the metadata for `entity`. `entity` must be
  // owned by this tracker.
  void IncrementSequenceNumber(const SyncedBookmarkTrackerEntity* entity);

  sync_pb::BookmarkModelMetadata BuildBookmarkModelMetadata() const;

  // Returns true if there are any local entities to be committed.
  bool HasLocalChanges() const;

  // Gets the number of unsynced bookmarks.
  size_t GetUnsyncedDataCount() const;

  const sync_pb::DataTypeState& data_type_state() const {
    return data_type_state_;
  }

  void set_data_type_state(sync_pb::DataTypeState data_type_state) {
    data_type_state_ = std::move(data_type_state);
  }

  std::vector<const SyncedBookmarkTrackerEntity*> GetAllEntities() const;

  std::vector<const SyncedBookmarkTrackerEntity*> GetEntitiesWithLocalChanges()
      const;

  // Updates the tracker after receiving the commit response. `sync_id` should
  // match the already tracked sync ID for `entity`, with the exception of the
  // initial commit, where the temporary client-generated ID will be overridden
  // by the server-provided final ID. `entity` must be owned by this tracker.
  void UpdateUponCommitResponse(const SyncedBookmarkTrackerEntity* entity,
                                const std::string& sync_id,
                                int64_t server_version,
                                int64_t acked_sequence_number);

  // Informs the tracker that the sync ID for `entity` has changed. It updates
  // the internal state of the tracker accordingly. `entity` must be owned by
  // this tracker.
  void UpdateSyncIdIfNeeded(const SyncedBookmarkTrackerEntity* entity,
                            const std::string& sync_id);

  // Used to start tracking an entity that overwrites a previous local tombstone
  // (e.g. user-initiated bookmark deletion undo). `entity` must be owned by
  // this tracker.
  void UndeleteTombstoneForBookmarkNode(
      const SyncedBookmarkTrackerEntity* entity,
      const bookmarks::BookmarkNode* node);

  // Set the value of `EntityMetadata.acked_sequence_number` for `entity` to be
  // equal to `EntityMetadata.sequence_number` such that it is not returned in
  // GetEntitiesWithLocalChanges(). `entity` must be owned by this tracker.
  void AckSequenceNumber(const SyncedBookmarkTrackerEntity* entity);

  // Whether the tracker is empty or not.
  bool IsEmpty() const;

  // Returns the estimate of dynamically allocated memory in bytes.
  size_t EstimateMemoryUsage() const;

  // Returns number of tracked bookmarks that aren't deleted.
  size_t TrackedBookmarksCount() const;

  // Returns number of bookmarks that have been deleted but the server hasn't
  // confirmed the deletion yet.
  size_t TrackedUncommittedTombstonesCount() const;

  // Returns number of tracked entities. Used only in test.
  size_t TrackedEntitiesCountForTest() const;

  // Clears the specifics hash for `entity`, useful for testing.
  void ClearSpecificsHashForTest(const SyncedBookmarkTrackerEntity* entity);

  // Checks whether all nodes in `bookmark_model` that *should* be tracked as
  // per IsNodeSyncable() are tracked.
  void CheckAllNodesTracked(const BookmarkModelView* bookmark_model) const;

  // This method is used to mark all entities except permanent nodes as
  // unsynced. This will cause reuploading of all bookmarks. The reupload
  // will be initiated only when the `bookmarks_hierarchy_fields_reuploaded`
  // field in BookmarksMetadata is false. This field is used to prevent
  // reuploading after each browser restart. Returns true if the reupload was
  // initiated.
  // TODO(crbug.com/40780588): remove this code when most of bookmarks are
  // reuploaded.
  bool ReuploadBookmarksOnLoadIfNeeded();

  // Causes the tracker to remember that a remote sync update (initial or
  // incremental) was ignored because its parent was unknown (either because
  // the data was corrupt or because the update is a descendant of an
  // unsupported permanent folder).
  void RecordIgnoredServerUpdateDueToMissingParent(int64_t server_version);

  std::optional<int64_t> GetNumIgnoredUpdatesDueToMissingParentForTest() const;
  std::optional<int64_t>
  GetMaxVersionAmongIgnoredUpdatesDueToMissingParentForTest() const;

 private:
  // Enumeration of possible reasons why persisted metadata are considered
  // corrupted and don't match the bookmark model. Used in UMA metrics. Do not
  // re-order or delete these entries; they are used in a UMA histogram. Please
  // edit SyncBookmarkModelMetadataCorruptionReason in enums.xml if a value is
  // added.
  // LINT.IfChange(SyncBookmarkModelMetadataCorruptionReason)
  enum class CorruptionReason {
    NO_CORRUPTION = 0,
    MISSING_SERVER_ID = 1,
    BOOKMARK_ID_IN_TOMBSTONE = 2,
    MISSING_BOOKMARK_ID = 3,
    // COUNT_MISMATCH = 4,  // Deprecated.
    // IDS_MISMATCH = 5,  // Deprecated.
    DUPLICATED_SERVER_ID = 6,
    UNKNOWN_BOOKMARK_ID = 7,
    UNTRACKED_BOOKMARK = 8,
    BOOKMARK_UUID_MISMATCH = 9,
    DUPLICATED_CLIENT_TAG_HASH = 10,
    TRACKED_MANAGED_NODE = 11,
    MISSING_CLIENT_TAG_HASH = 12,
    MISSING_FAVICON_HASH = 13,

    kMaxValue = MISSING_FAVICON_HASH
  };
  // LINT.ThenChange(/tools/metrics/histograms/metadata/sync/enums.xml:SyncBookmarkModelMetadataCorruptionReason)

  SyncedBookmarkTracker(
      sync_pb::DataTypeState data_type_state,
      bool bookmarks_reuploaded,
      std::optional<int64_t> num_ignored_updates_due_to_missing_parent,
      std::optional<int64_t>
          max_version_among_ignored_updates_due_to_missing_parent);

  // Add entities to `this` tracker based on the content of `*model` and
  // `model_metadata`. Validates the integrity of `*model` and `model_metadata`
  // and returns an enum representing any inconsistency.
  CorruptionReason InitEntitiesFromModelAndMetadata(
      const BookmarkModelView* model,
      sync_pb::BookmarkModelMetadata model_metadata);

  // Conceptually, find a tracked entity that matches `entity` and returns a
  // non-const pointer of it. The actual implementation is a const_cast.
  // `entity` must be owned by this tracker.
  SyncedBookmarkTrackerEntity* AsMutableEntity(
      const SyncedBookmarkTrackerEntity* entity);

  // Reorders `entities` that represents local non-deletions such that parent
  // creation/update is before child creation/update. Returns the ordered list.
  std::vector<const SyncedBookmarkTrackerEntity*>
  ReorderUnsyncedEntitiesExceptDeletions(
      const std::vector<const SyncedBookmarkTrackerEntity*>& entities) const;

  // Recursive method that starting from `node` appends all corresponding
  // entities with updates in top-down order to `ordered_entities`.
  void TraverseAndAppend(
      const bookmarks::BookmarkNode* node,
      std::vector<const SyncedBookmarkTrackerEntity*>* ordered_entities) const;

  // A map of sync server ids to sync entities. This should contain entries and
  // metadata for almost everything.
  std::unordered_map<std::string, std::unique_ptr<SyncedBookmarkTrackerEntity>>
      sync_id_to_entities_map_;

  // Index for efficient lookups by client tag hash.
  std::unordered_map<
      syncer::ClientTagHash,
      raw_ptr<const SyncedBookmarkTrackerEntity, CtnExperimental>,
      syncer::ClientTagHash::Hash>
      client_tag_hash_to_entities_map_;

  // A map of bookmark nodes to sync entities. It's keyed by the bookmark node
  // pointers which get assigned when loading the bookmark model. This map is
  // first initialized in the constructor.
  std::unordered_map<const bookmarks::BookmarkNode*,
                     raw_ptr<SyncedBookmarkTrackerEntity, CtnExperimental>>
      bookmark_node_to_entities_map_;

  // A list of pending local bookmark deletions. They should be sent to the
  // server in the same order as stored in the list. The same order should also
  // be maintained across browser restarts (i.e. across calls to the ctor() and
  // BuildBookmarkModelMetadata().
  std::vector<raw_ptr<SyncedBookmarkTrackerEntity, VectorExperimental>>
      ordered_local_tombstones_;

  // The model metadata (progress marker, initial sync done, etc).
  sync_pb::DataTypeState data_type_state_;

  // This field contains the value of
  // BookmarksMetadata::bookmarks_hierarchy_fields_reuploaded.
  // TODO(crbug.com/40780588): remove this code when most of bookmarks are
  // reuploaded.
  bool bookmarks_reuploaded_ = false;

  // See corresponding proto fields in BookmarkModelMetadata.
  std::optional<int64_t> num_ignored_updates_due_to_missing_parent_;
  std::optional<int64_t>
      max_version_among_ignored_updates_due_to_missing_parent_;
};

}  // namespace sync_bookmarks

#endif  // COMPONENTS_SYNC_BOOKMARKS_SYNCED_BOOKMARK_TRACKER_H_