Skip to content

Commit 7bff18b

Browse files
Merge pull request #4816 from brave/sync_recover_after_dup_id
Recreating bookmarks with duplicated sync object id
2 parents 64062cc + 6280bda commit 7bff18b

7 files changed

+147
-1
lines changed

browser/profiles/brave_bookmark_model_loaded_observer.cc

+2
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ void BraveBookmarkModelLoadedObserver::BookmarkModelLoaded(
4444

4545
#if BUILDFLAG(ENABLE_BRAVE_SYNC)
4646
BraveProfileSyncServiceImpl::AddNonClonedBookmarkKeys(model);
47+
BraveProfileSyncServiceImpl::MigrateDuplicatedBookmarksObjectIds(profile_,
48+
model);
4749
#endif
4850

4951
BookmarkModelLoadedObserver::BookmarkModelLoaded(model, ids_reassigned);

chromium_src/components/sync/engine_impl/commit.cc

+12
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ brave_sync::RecordsListPtr ConvertCommitsToBraveRecords(
9292
if (entity.specifics().has_bookmark()) {
9393
const sync_pb::BookmarkSpecifics& bm_specifics =
9494
entity.specifics().bookmark();
95+
9596
auto record = std::make_unique<SyncRecord>();
9697
record->objectData = brave_sync::jslib_const::SyncObjectData_BOOKMARK;
9798

@@ -138,6 +139,17 @@ brave_sync::RecordsListPtr ConvertCommitsToBraveRecords(
138139
record->action = brave_sync::jslib::SyncRecord::Action::A_UPDATE;
139140
}
140141

142+
if (entity.deleted() && entity.version() == 0 &&
143+
record->objectId.empty()) {
144+
// This is for recover profile after crash with duplicated object ids
145+
// When doing delete of duplicated bookmark, pretend it has a new
146+
// object id to got through nudge/pull cycle
147+
// We are ok, if other devices would get this record, because they have
148+
// nothing to delete in fact
149+
record->objectId = brave_sync::tools::GenerateObjectId();
150+
record->action = brave_sync::jslib::SyncRecord::Action::A_DELETE;
151+
}
152+
141153
DCHECK(!record->objectId.empty());
142154

143155
MetaInfo metaInfo;

components/brave_sync/brave_profile_sync_service_impl.cc

+76
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include "brave/components/brave_sync/brave_profile_sync_service_impl.h"
77

88
#include <algorithm>
9+
#include <map>
910
#include <utility>
1011
#include <vector>
1112

@@ -165,6 +166,57 @@ SyncRecordPtr PrepareResolvedDevice(SyncDevice* device,
165166
record->SetDevice(std::move(device_record));
166167
return record;
167168
}
169+
170+
struct BookmarkByDateAddedComparator {
171+
bool operator()(const bookmarks::BookmarkNode* lhs,
172+
const bookmarks::BookmarkNode* rhs) const {
173+
DCHECK(lhs);
174+
DCHECK(rhs);
175+
DCHECK(!tools::IsTimeEmpty(lhs->date_added()));
176+
DCHECK(!tools::IsTimeEmpty(rhs->date_added()));
177+
return lhs->date_added() < rhs->date_added();
178+
}
179+
};
180+
using SortedNodes =
181+
std::set<const bookmarks::BookmarkNode*, BookmarkByDateAddedComparator>;
182+
using ObjectIdToNodes = std::map<std::string, SortedNodes>;
183+
184+
void FillObjectsMap(const bookmarks::BookmarkNode* parent,
185+
ObjectIdToNodes* object_id_nodes) {
186+
for (size_t i = 0; i < parent->children().size(); ++i) {
187+
const bookmarks::BookmarkNode* current_child = parent->children()[i].get();
188+
std::string object_id;
189+
if (current_child->GetMetaInfo("object_id", &object_id) &&
190+
!object_id.empty()) {
191+
(*object_id_nodes)[object_id].insert(current_child);
192+
}
193+
if (current_child->is_folder()) {
194+
FillObjectsMap(current_child, object_id_nodes);
195+
}
196+
}
197+
}
198+
199+
void ClearDuplicatedNodes(ObjectIdToNodes* object_id_nodes,
200+
bookmarks::BookmarkModel* model) {
201+
for (ObjectIdToNodes::iterator it_object_id = object_id_nodes->begin();
202+
it_object_id != object_id_nodes->end(); ++it_object_id) {
203+
const SortedNodes& nodes = it_object_id->second;
204+
if (nodes.size() > 1) {
205+
// Nodes are sorted from oldest to newest, go to the second by age
206+
SortedNodes::iterator it_nodes = nodes.begin();
207+
++it_nodes;
208+
for (; it_nodes != nodes.end(); ++it_nodes) {
209+
const bookmarks::BookmarkNode* node = *it_nodes;
210+
// Copy and delete node
211+
const auto* parent = node->parent();
212+
size_t original_index = parent->GetIndexOf(node);
213+
model->Copy(node, parent, original_index);
214+
model->Remove(node);
215+
brave_sync::AddBraveMetaInfo(parent->children()[original_index].get());
216+
}
217+
}
218+
}
219+
}
168220
} // namespace
169221

170222
BraveProfileSyncServiceImpl::BraveProfileSyncServiceImpl(Profile* profile,
@@ -755,6 +807,30 @@ void BraveProfileSyncServiceImpl::SetPermanentNodesOrder(
755807
brave_sync_prefs_->SetMigratedBookmarksVersion(2);
756808
}
757809

810+
// static
811+
void BraveProfileSyncServiceImpl::MigrateDuplicatedBookmarksObjectIds(
812+
Profile* profile,
813+
BookmarkModel* model) {
814+
DCHECK(model);
815+
DCHECK(model->loaded());
816+
817+
bool duplicated_bookmarks_recovered =
818+
profile->GetPrefs()->GetBoolean(prefs::kDuplicatedBookmarksRecovered);
819+
if (duplicated_bookmarks_recovered) {
820+
return;
821+
}
822+
823+
// Copying bookmarks through brave://bookmarks page could duplicate brave sync
824+
// metadata, which caused crash during chromium sync run
825+
// Go through nodes and re-create the oldest ones who have duplicated
826+
// object_id
827+
ObjectIdToNodes object_id_nodes;
828+
FillObjectsMap(model->root_node(), &object_id_nodes);
829+
ClearDuplicatedNodes(&object_id_nodes, model);
830+
831+
profile->GetPrefs()->SetBoolean(prefs::kDuplicatedBookmarksRecovered, true);
832+
}
833+
758834
std::unique_ptr<SyncRecord>
759835
BraveProfileSyncServiceImpl::BookmarkNodeToSyncBookmark(
760836
const bookmarks::BookmarkNode* node) {

components/brave_sync/brave_profile_sync_service_impl.h

+3
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,9 @@ class BraveProfileSyncServiceImpl
187187

188188
BraveSyncService* GetSyncService() const override;
189189

190+
static void MigrateDuplicatedBookmarksObjectIds(Profile* profile,
191+
BookmarkModel* model);
192+
190193
private:
191194
FRIEND_TEST_ALL_PREFIXES(::BraveSyncServiceTest, BookmarkAdded);
192195
FRIEND_TEST_ALL_PREFIXES(::BraveSyncServiceTest, BookmarkDeleted);

components/brave_sync/brave_sync_prefs.cc

+3
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ const char kSyncMigrateBookmarksVersion[]
4343
= "brave_sync.migrate_bookmarks_version";
4444
const char kSyncRecordsToResend[] = "brave_sync_records_to_resend";
4545
const char kSyncRecordsToResendMeta[] = "brave_sync_records_to_resend_meta";
46+
const char kDuplicatedBookmarksRecovered[] =
47+
"brave_sync_duplicated_bookmarks_recovered";
4648

4749
Prefs::Prefs(PrefService* pref_service) : pref_service_(pref_service) {}
4850

@@ -72,6 +74,7 @@ void Prefs::RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry) {
7274

7375
registry->RegisterListPref(prefs::kSyncRecordsToResend);
7476
registry->RegisterDictionaryPref(prefs::kSyncRecordsToResendMeta);
77+
registry->RegisterBooleanPref(kDuplicatedBookmarksRecovered, false);
7578
}
7679

7780
std::string Prefs::GetSeed() const {

components/brave_sync/brave_sync_prefs.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -66,12 +66,14 @@ extern const char kSyncDeviceList[];
6666
// the sync api version from the server
6767
extern const char kSyncApiVersion[];
6868
// The version of bookmarks state: 0,1,... .
69-
// Current to migrate to is 1.
69+
// Current to migrate to is 2.
7070
extern const char kSyncMigrateBookmarksVersion[];
7171
// Cached object_id list for unconfirmed records
7272
extern const char kSyncRecordsToResend[];
7373
// Meta info of kSyncRecordsToResend
7474
extern const char kSyncRecordsToResendMeta[];
75+
// Flag indicates we had recovered duplicated bookmarks object ids
76+
extern const char kDuplicatedBookmarksRecovered[];
7577

7678
class Prefs {
7779
public:

components/brave_sync/brave_sync_service_unittest.cc

+48
Original file line numberDiff line numberDiff line change
@@ -1631,3 +1631,51 @@ TEST_F(BraveSyncServiceTest, AddNonClonedBookmarkKeys) {
16311631
EXPECT_FALSE(bookmark_copy->GetMetaInfo("version", &meta_version));
16321632
EXPECT_TRUE(meta_version.empty());
16331633
}
1634+
1635+
TEST_F(BraveSyncServiceTest, MigrateDuplicatedBookmarksObjectIds) {
1636+
AsMutable(model()->other_node())->SetMetaInfo("order", kOtherNodeOrder);
1637+
1638+
const bookmarks::BookmarkNode* bookmark_a1 =
1639+
model()->AddURL(model()->other_node(), 0, base::ASCIIToUTF16("A1"),
1640+
GURL("https://a1.com"));
1641+
1642+
AsMutable(bookmark_a1)->SetMetaInfo("object_id", "object_id_value");
1643+
AsMutable(bookmark_a1)->SetMetaInfo("order", "255.255.255.3");
1644+
AsMutable(bookmark_a1)->SetMetaInfo("sync_timestamp", "sync_timestamp_value");
1645+
AsMutable(bookmark_a1)->SetMetaInfo("version", "version_value");
1646+
1647+
model()->Copy(bookmark_a1, model()->other_node(), 1);
1648+
1649+
const bookmarks::BookmarkNode* bookmark_copy =
1650+
model()->other_node()->children().at(1).get();
1651+
1652+
std::string meta_object_id;
1653+
EXPECT_TRUE(bookmark_copy->GetMetaInfo("object_id", &meta_object_id));
1654+
EXPECT_EQ(meta_object_id, "object_id_value");
1655+
std::string meta_order;
1656+
EXPECT_TRUE(bookmark_copy->GetMetaInfo("order", &meta_order));
1657+
EXPECT_EQ(meta_order, "255.255.255.3");
1658+
std::string meta_sync_timestamp;
1659+
EXPECT_TRUE(
1660+
bookmark_copy->GetMetaInfo("sync_timestamp", &meta_sync_timestamp));
1661+
EXPECT_EQ(meta_sync_timestamp, "sync_timestamp_value");
1662+
std::string meta_version;
1663+
EXPECT_TRUE(bookmark_copy->GetMetaInfo("version", &meta_version));
1664+
EXPECT_EQ(meta_version, "version_value");
1665+
1666+
sync_service()->AddNonClonedBookmarkKeys(model());
1667+
1668+
// Do the migration
1669+
BraveProfileSyncServiceImpl::MigrateDuplicatedBookmarksObjectIds(profile(),
1670+
model());
1671+
bookmark_copy = model()->other_node()->children().at(1).get();
1672+
1673+
std::string meta_migrated_object_id;
1674+
EXPECT_TRUE(
1675+
bookmark_copy->GetMetaInfo("object_id", &meta_migrated_object_id));
1676+
EXPECT_NE(meta_migrated_object_id, "object_id_value");
1677+
1678+
std::string meta_migrated_order;
1679+
EXPECT_TRUE(bookmark_copy->GetMetaInfo("order", &meta_migrated_order));
1680+
EXPECT_NE(meta_migrated_order, "255.255.255.3");
1681+
}

0 commit comments

Comments
 (0)