diff options
author | jyasskin@chromium.org <jyasskin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-22 05:54:08 +0000 |
---|---|---|
committer | jyasskin@chromium.org <jyasskin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-22 05:54:08 +0000 |
commit | e6f27a38b986daf96d9ba601f52b8a3380c69691 (patch) | |
tree | 97dd5457ea374e057fd00e3526def873565e2c62 /components/dom_distiller | |
parent | 5a65fde3eed81247f89429e963d7393fb8dc7341 (diff) | |
download | chromium_src-e6f27a38b986daf96d9ba601f52b8a3380c69691.zip chromium_src-e6f27a38b986daf96d9ba601f52b8a3380c69691.tar.gz chromium_src-e6f27a38b986daf96d9ba601f52b8a3380c69691.tar.bz2 |
Revert 230025 "Extract the in-memory model from DomDistillerStore"
It caused "Use of uninitialised values" in the Linux valgrind bot:
http://build.chromium.org/p/chromium.memory.fyi/builders/Linux%20Tests%20%28valgrind%29%282%29/builds/31483
> Extract the in-memory model from DomDistillerStore
>
> This moves interaction with the in-memory model from the store to its
> own class: DomDistillerModel. This also adds two ways to lookup entries
> to both the store and the model, GetEntryById and GetEntryByUrl.
>
> BUG=288015
> TBR=joi@chromium.org
>
> Review URL: https://codereview.chromium.org/26574002
TBR=cjhopman@chromium.org
Review URL: https://codereview.chromium.org/34363003
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@230057 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'components/dom_distiller')
-rw-r--r-- | components/dom_distiller/core/article_entry.cc | 21 | ||||
-rw-r--r-- | components/dom_distiller/core/article_entry.h | 10 | ||||
-rw-r--r-- | components/dom_distiller/core/dom_distiller_model.cc | 206 | ||||
-rw-r--r-- | components/dom_distiller/core/dom_distiller_model.h | 94 | ||||
-rw-r--r-- | components/dom_distiller/core/dom_distiller_model_unittest.cc | 131 | ||||
-rw-r--r-- | components/dom_distiller/core/dom_distiller_store.cc | 177 | ||||
-rw-r--r-- | components/dom_distiller/core/dom_distiller_store.h | 36 | ||||
-rw-r--r-- | components/dom_distiller/core/dom_distiller_store_unittest.cc | 17 |
8 files changed, 142 insertions, 550 deletions
diff --git a/components/dom_distiller/core/article_entry.cc b/components/dom_distiller/core/article_entry.cc index 1550caf..2e370a4 100644 --- a/components/dom_distiller/core/article_entry.cc +++ b/components/dom_distiller/core/article_entry.cc @@ -5,7 +5,6 @@ #include "components/dom_distiller/core/article_entry.h" #include "base/logging.h" -#include "sync/api/sync_change.h" using sync_pb::EntitySpecifics; using sync_pb::ArticlePage; @@ -46,24 +45,4 @@ EntitySpecifics SpecificsFromEntry(const ArticleEntry& entry) { return specifics; } -ArticleEntry GetEntryFromChange(const syncer::SyncChange& change) { - DCHECK(change.IsValid()); - DCHECK(change.sync_data().IsValid()); - return EntryFromSpecifics(change.sync_data().GetSpecifics()); -} - -std::string GetEntryIdFromSyncData(const syncer::SyncData& data) { - const EntitySpecifics& entity = data.GetSpecifics(); - DCHECK(entity.has_article()); - const ArticleSpecifics& specifics = entity.article(); - DCHECK(specifics.has_entry_id()); - return specifics.entry_id(); -} - -syncer::SyncData CreateLocalData(const ArticleEntry& entry) { - EntitySpecifics specifics = SpecificsFromEntry(entry); - const std::string& entry_id = entry.entry_id(); - return syncer::SyncData::CreateLocalData(entry_id, entry_id, specifics); -} - } // namespace dom_distiller diff --git a/components/dom_distiller/core/article_entry.h b/components/dom_distiller/core/article_entry.h index 388dc51..3811612 100644 --- a/components/dom_distiller/core/article_entry.h +++ b/components/dom_distiller/core/article_entry.h @@ -5,14 +5,9 @@ #ifndef COMPONENTS_DOM_DISTILLER_CORE_ARTICLE_ENTRY_H_ #define COMPONENTS_DOM_DISTILLER_CORE_ARTICLE_ENTRY_H_ -#include "sync/api/sync_data.h" #include "sync/protocol/article_specifics.pb.h" #include "sync/protocol/sync.pb.h" -namespace syncer { -class SyncChange; -} - namespace dom_distiller { typedef sync_pb::ArticleSpecifics ArticleEntry; @@ -25,11 +20,6 @@ bool AreEntriesEqual(const ArticleEntry& left, const ArticleEntry& right); sync_pb::EntitySpecifics SpecificsFromEntry(const ArticleEntry& entry); ArticleEntry EntryFromSpecifics(const sync_pb::EntitySpecifics& specifics); -ArticleEntry GetEntryFromChange(const syncer::SyncChange& change); -std::string GetEntryIdFromSyncData(const syncer::SyncData& data); -syncer::SyncData CreateLocalData(const ArticleEntry& entry); - - } // namespace dom_distiller #endif diff --git a/components/dom_distiller/core/dom_distiller_model.cc b/components/dom_distiller/core/dom_distiller_model.cc deleted file mode 100644 index 9468487..0000000 --- a/components/dom_distiller/core/dom_distiller_model.cc +++ /dev/null @@ -1,206 +0,0 @@ -// Copyright 2013 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. - -#include "components/dom_distiller/core/dom_distiller_model.h" - -using syncer::SyncChange; -using syncer::SyncChangeList; -using syncer::SyncData; -using syncer::SyncDataList; - -namespace dom_distiller { - -DomDistillerModel::DomDistillerModel() {} - -DomDistillerModel::DomDistillerModel( - const std::vector<ArticleEntry>& initial_data) { - for (size_t i = 0; i < initial_data.size(); ++i) { - AddEntry(initial_data[i]); - } -} - -DomDistillerModel::~DomDistillerModel() {} - -bool DomDistillerModel::GetEntryById(const std::string& entry_id, - ArticleEntry* entry) const { - KeyType key; - if (!GetKeyById(entry_id, &key)) { - return false; - } - GetEntryByKey(key, entry); - return true; -} - -bool DomDistillerModel::GetEntryByUrl(const GURL& url, - ArticleEntry* entry) const { - KeyType key; - if (!GetKeyByUrl(url, &key)) { - return false; - } - GetEntryByKey(key, entry); - return true; -} - -bool DomDistillerModel::GetKeyById(const std::string& entry_id, - KeyType* key) const { - StringToKeyMap::const_iterator it = entry_id_to_key_map_.find(entry_id); - if (it == entry_id_to_key_map_.end()) { - return false; - } - if (key != NULL) { - *key = it->second; - } - return true; -} - -bool DomDistillerModel::GetKeyByUrl(const GURL& url, KeyType* key) const { - StringToKeyMap::const_iterator it = url_to_key_map_.find(url.spec()); - if (it == url_to_key_map_.end()) { - return false; - } - if (key != NULL) { - *key = it->second; - } - return true; -} - -void DomDistillerModel::GetEntryByKey(KeyType key, ArticleEntry* entry) const { - if (entry != NULL) { - EntryMap::const_iterator it = entries_.find(key); - DCHECK(it != entries_.end()); - *entry = it->second; - } -} - -size_t DomDistillerModel::GetNumEntries() const { - return entries_.size(); -} - -std::vector<ArticleEntry> DomDistillerModel::GetEntries() const { - std::vector<ArticleEntry> entries_list; - for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end(); - ++it) { - entries_list.push_back(it->second); - } - return entries_list; -} - -SyncDataList DomDistillerModel::GetAllSyncData() const { - SyncDataList data; - for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end(); - ++it) { - data.push_back(CreateLocalData(it->second)); - } - return data; -} - -void DomDistillerModel::CalculateChangesForMerge( - const SyncDataList& data, - SyncChangeList* changes_to_apply, - SyncChangeList* changes_missing) { - typedef base::hash_set<std::string> StringSet; - StringSet entries_to_change; - for (SyncDataList::const_iterator it = data.begin(); it != data.end(); ++it) { - std::string entry_id = GetEntryIdFromSyncData(*it); - std::pair<StringSet::iterator, bool> insert_result = - entries_to_change.insert(entry_id); - - DCHECK(insert_result.second); - - SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD; - if (GetEntryById(entry_id, NULL)) { - change_type = SyncChange::ACTION_UPDATE; - } - changes_to_apply->push_back(SyncChange(FROM_HERE, change_type, *it)); - } - - for (EntryMap::const_iterator it = entries_.begin(); it != entries_.end(); - ++it) { - if (entries_to_change.find(it->second.entry_id()) == - entries_to_change.end()) { - changes_missing->push_back(SyncChange( - FROM_HERE, SyncChange::ACTION_ADD, CreateLocalData(it->second))); - } - } -} - -DomDistillerModel::ChangeResult DomDistillerModel::ApplyChangesToModel( - const SyncChangeList& changes, - SyncChangeList* changes_applied, - SyncChangeList* changes_missing) { - DCHECK(changes_applied); - DCHECK(changes_missing); - - ChangeResult result = SUCCESS; - - for (SyncChangeList::const_iterator it = changes.begin(); it != changes.end(); - ++it) { - result = ApplyChangeToModel(*it, changes_applied, changes_missing); - if (result != SUCCESS) { - break; - } - } - return result; -} - -void DomDistillerModel::AddEntry(const ArticleEntry& entry) { - const std::string& entry_id = entry.entry_id(); - KeyType key = next_key_++; - DCHECK(!GetKeyById(entry_id, NULL)); - entries_.insert(std::make_pair(key, entry)); - entry_id_to_key_map_.insert(std::make_pair(entry_id, key)); - for (int i = 0; i < entry.pages_size(); ++i) { - url_to_key_map_.insert(std::make_pair(entry.pages(i).url(), key)); - } -} - -void DomDistillerModel::RemoveEntry(const ArticleEntry& entry) { - const std::string& entry_id = entry.entry_id(); - KeyType key; - bool success = GetKeyById(entry_id, &key); - DCHECK(success); - - entries_.erase(key); - entry_id_to_key_map_.erase(entry_id); - for (int i = 0; i < entry.pages_size(); ++i) { - url_to_key_map_.erase(entry.pages(i).url()); - } -} - -DomDistillerModel::ChangeResult DomDistillerModel::ApplyChangeToModel( - const SyncChange& change, - SyncChangeList* changes_applied, - SyncChangeList* changes_missing) { - DCHECK(change.IsValid()); - DCHECK(changes_applied); - DCHECK(changes_missing); - - const std::string& entry_id = GetEntryIdFromSyncData(change.sync_data()); - - if (change.change_type() == SyncChange::ACTION_DELETE) { - // TODO(cjhopman): Support delete. - NOTIMPLEMENTED(); - return DELETE_NOT_SUPPORTED; - } - - ArticleEntry entry = GetEntryFromChange(change); - ArticleEntry current_entry; - if (!GetEntryById(entry_id, ¤t_entry)) { - AddEntry(entry); - changes_applied->push_back(SyncChange( - change.location(), SyncChange::ACTION_ADD, change.sync_data())); - } else { - if (!AreEntriesEqual(current_entry, entry)) { - // Currently, conflicts are simply resolved by accepting the last one to - // arrive. - RemoveEntry(current_entry); - AddEntry(entry); - changes_applied->push_back(SyncChange( - change.location(), SyncChange::ACTION_UPDATE, change.sync_data())); - } - } - return SUCCESS; -} - -} // namespace dom_distiller diff --git a/components/dom_distiller/core/dom_distiller_model.h b/components/dom_distiller/core/dom_distiller_model.h deleted file mode 100644 index 1bc2ec2..0000000 --- a/components/dom_distiller/core/dom_distiller_model.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2013 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_DOM_DISTILLER_CORE_DOM_DISTILLER_MODEL_H_ -#define COMPONENTS_DOM_DISTILLER_CORE_DOM_DISTILLER_MODEL_H_ - -#include <vector> - -#include "base/containers/hash_tables.h" -#include "base/id_map.h" -#include "components/dom_distiller/core/article_entry.h" -#include "sync/api/sync_change.h" -#include "sync/api/sync_change_processor.h" // syncer::SyncChangeList -#include "sync/api/sync_data.h" -#include "url/gurl.h" - -namespace dom_distiller { - -// This stores the in-memory model of the DOM distiller list. Entries can be -// looked up by URL or by entry_id. -// The model assumes that an URL corresponds to at most a single entry. If this -// assumption is broken, lookup by URL may return unexpected results. -class DomDistillerModel { - public: - enum ChangeResult { - SUCCESS = 0, - DELETE_NOT_SUPPORTED, - }; - - DomDistillerModel(); - explicit DomDistillerModel(const std::vector<ArticleEntry>& initial_data); - - ~DomDistillerModel(); - - // Lookup an ArticleEntry by ID or URL. Returns whether a corresponding entry - // was found. On success, if |entry| is not null, it will contain the entry. - bool GetEntryById(const std::string& entry_id, ArticleEntry* entry) const; - bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) const; - - std::vector<ArticleEntry> GetEntries() const; - size_t GetNumEntries() const; - - syncer::SyncDataList GetAllSyncData() const; - - // Convert a SyncDataList to a SyncChangeList of add or update changes based - // on the state of the model. Also calculate the entries missing from the - // SyncDataList. - void CalculateChangesForMerge(const syncer::SyncDataList& data, - syncer::SyncChangeList* changes_to_apply, - syncer::SyncChangeList* changes_missing); - - // Applies the change list to the model, appending the actual changes made to - // the model to |changes_applied|. If conflict resolution does not apply the - // requested change, then adds the "diff" between what was requested and what - // was actually applied to |changes_missing|. - // Note: Currently conflicts are resolved by just applying the requested - // change. This means nothing will be added to |changes_missing|. - ChangeResult ApplyChangesToModel(const syncer::SyncChangeList& change_list, - syncer::SyncChangeList* changes_applied, - syncer::SyncChangeList* changes_missing); - - private: - typedef int32 KeyType; - typedef base::hash_map<KeyType, ArticleEntry> EntryMap; - typedef base::hash_map<std::string, KeyType> StringToKeyMap; - - void AddEntry(const ArticleEntry& entry); - void RemoveEntry(const ArticleEntry& entry); - - // Lookup an entry's key by ID or URL. Returns whether a corresponding key was - // found. On success, if |key| is not null, it will contain the entry. - bool GetKeyById(const std::string& entry_id, KeyType* key) const; - bool GetKeyByUrl(const GURL& url, KeyType* key) const; - - // If |entry| is not null, assigns the entry for |key| to it. |key| must map - // to an entry in |entries_|. - void GetEntryByKey(KeyType key, ArticleEntry* entry) const; - - ChangeResult ApplyChangeToModel(const syncer::SyncChange& change, - syncer::SyncChangeList* changes_applied, - syncer::SyncChangeList* changes_missing); - - KeyType next_key_; - EntryMap entries_; - StringToKeyMap url_to_key_map_; - StringToKeyMap entry_id_to_key_map_; - - DISALLOW_COPY_AND_ASSIGN(DomDistillerModel); -}; - -} // namespace dom_distiller - -#endif diff --git a/components/dom_distiller/core/dom_distiller_model_unittest.cc b/components/dom_distiller/core/dom_distiller_model_unittest.cc deleted file mode 100644 index 0220439..0000000 --- a/components/dom_distiller/core/dom_distiller_model_unittest.cc +++ /dev/null @@ -1,131 +0,0 @@ -// Copyright 2013 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. - -#include "components/dom_distiller/core/dom_distiller_model.h" - -#include "testing/gtest/include/gtest/gtest.h" - -namespace dom_distiller { - -TEST(DomDistillerModelTest, TestGetByEntryId) { - ArticleEntry entry1; - entry1.set_entry_id("id1"); - entry1.set_title("title1"); - ArticleEntry entry2; - entry2.set_entry_id("id2"); - entry2.set_title("title1"); - - std::vector<ArticleEntry> initial_model; - initial_model.push_back(entry1); - initial_model.push_back(entry2); - - DomDistillerModel model(initial_model); - - ArticleEntry found_entry; - EXPECT_TRUE(model.GetEntryById(entry1.entry_id(), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry1, found_entry)); - - EXPECT_TRUE(model.GetEntryById(entry2.entry_id(), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry2, found_entry)); - - EXPECT_FALSE(model.GetEntryById("some_other_id", NULL)); -} - -TEST(DomDistillerModelTest, TestGetByUrl) { - ArticleEntry entry1; - entry1.set_entry_id("id1"); - entry1.set_title("title1"); - ArticleEntryPage* page1 = entry1.add_pages(); - page1->set_url("http://example.com/1"); - ArticleEntryPage* page2 = entry1.add_pages(); - page2->set_url("http://example.com/2"); - - ArticleEntry entry2; - entry2.set_entry_id("id2"); - entry2.set_title("title1"); - ArticleEntryPage* page3 = entry2.add_pages(); - page3->set_url("http://example.com/a1"); - - std::vector<ArticleEntry> initial_model; - initial_model.push_back(entry1); - initial_model.push_back(entry2); - - DomDistillerModel model(initial_model); - - ArticleEntry found_entry; - EXPECT_TRUE(model.GetEntryByUrl(GURL(page1->url()), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry1, found_entry)); - - EXPECT_TRUE(model.GetEntryByUrl(GURL(page2->url()), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry1, found_entry)); - - EXPECT_TRUE(model.GetEntryByUrl(GURL(page3->url()), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry2, found_entry)); - - EXPECT_FALSE(model.GetEntryByUrl(GURL("http://example.com/foo"), NULL)); -} - -// This test ensures that the model handles the case where an URL maps to -// multiple entries. In that case, the model is allowed to have an inconsistent -// url-to-entry mapping, but it should not fail in other ways (i.e. id-to-entry -// should be correct, shouldn't crash). -TEST(DomDistillerModelTest, TestUrlToMultipleEntries) { - ArticleEntry entry1; - entry1.set_entry_id("id1"); - entry1.set_title("title1"); - ArticleEntryPage* page1 = entry1.add_pages(); - page1->set_url("http://example.com/1"); - ArticleEntryPage* page2 = entry1.add_pages(); - page2->set_url("http://example.com/2"); - - ArticleEntry entry2; - entry2.set_entry_id("id2"); - entry2.set_title("title1"); - ArticleEntryPage* page3 = entry2.add_pages(); - page3->set_url("http://example.com/1"); - - std::vector<ArticleEntry> initial_model; - initial_model.push_back(entry1); - initial_model.push_back(entry2); - - DomDistillerModel model(initial_model); - - EXPECT_TRUE(model.GetEntryByUrl(GURL(page1->url()), NULL)); - EXPECT_TRUE(model.GetEntryByUrl(GURL(page2->url()), NULL)); - EXPECT_TRUE(model.GetEntryByUrl(GURL(page3->url()), NULL)); - - ArticleEntry found_entry; - EXPECT_TRUE(model.GetEntryById(entry1.entry_id(), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry1, found_entry)); - - EXPECT_TRUE(model.GetEntryById(entry2.entry_id(), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry2, found_entry)); - - syncer::SyncChangeList changes_to_apply; - syncer::SyncChangeList changes_applied; - syncer::SyncChangeList changes_missing; - - entry2.mutable_pages(0)->set_url("http://example.com/foo1"); - changes_to_apply.push_back(syncer::SyncChange( - FROM_HERE, syncer::SyncChange::ACTION_UPDATE, CreateLocalData(entry2))); - model.ApplyChangesToModel( - changes_to_apply, &changes_applied, &changes_missing); - - EXPECT_TRUE(model.GetEntryById(entry1.entry_id(), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry1, found_entry)); - - EXPECT_TRUE(model.GetEntryById(entry2.entry_id(), &found_entry)); - ASSERT_TRUE(IsEntryValid(found_entry)); - EXPECT_TRUE(AreEntriesEqual(entry2, found_entry)); -} - -} // namespace dom_distiller diff --git a/components/dom_distiller/core/dom_distiller_store.cc b/components/dom_distiller/core/dom_distiller_store.cc index 8be2cb6..f5a7a70 100644 --- a/components/dom_distiller/core/dom_distiller_store.cc +++ b/components/dom_distiller/core/dom_distiller_store.cc @@ -23,6 +23,24 @@ using syncer::SyncMergeResult; namespace dom_distiller { +namespace { + +std::string GetEntryIdFromSyncData(const SyncData& data) { + const EntitySpecifics& entity = data.GetSpecifics(); + DCHECK(entity.has_article()); + const ArticleSpecifics& specifics = entity.article(); + DCHECK(specifics.has_entry_id()); + return specifics.entry_id(); +} + +SyncData CreateLocalData(const ArticleEntry& entry) { + EntitySpecifics specifics = SpecificsFromEntry(entry); + const std::string& entry_id = entry.entry_id(); + return SyncData::CreateLocalData(entry_id, entry_id, specifics); +} + +} // namespace + DomDistillerStore::DomDistillerStore( scoped_ptr<DomDistillerDatabaseInterface> database, const base::FilePath& database_dir) @@ -36,11 +54,11 @@ DomDistillerStore::DomDistillerStore( DomDistillerStore::DomDistillerStore( scoped_ptr<DomDistillerDatabaseInterface> database, - const std::vector<ArticleEntry>& initial_data, + const EntryMap& initial_model, const base::FilePath& database_dir) : database_(database.Pass()), database_loaded_(false), - model_(initial_data), + model_(initial_model), weak_ptr_factory_(this) { database_->Init(database_dir, base::Bind(&DomDistillerStore::OnDatabaseInit, @@ -54,23 +72,11 @@ syncer::SyncableService* DomDistillerStore::GetSyncableService() { return this; } -bool DomDistillerStore::GetEntryById(const std::string& entry_id, - ArticleEntry* entry) { - return model_.GetEntryById(entry_id, entry); -} - -bool DomDistillerStore::GetEntryByUrl(const GURL& url, - ArticleEntry* entry) { - return model_.GetEntryByUrl(url, entry); -} - - bool DomDistillerStore::AddEntry(const ArticleEntry& entry) { if (!database_loaded_) { return false; } - - if (model_.GetEntryById(entry.entry_id(), NULL)) { + if (model_.find(entry.entry_id()) != model_.end()) { return false; } @@ -80,11 +86,7 @@ bool DomDistillerStore::AddEntry(const ArticleEntry& entry) { SyncChangeList changes_applied; SyncChangeList changes_missing; - - if (!ApplyChangesToModel( - changes_to_apply, &changes_applied, &changes_missing)) { - return false; - } + ApplyChangesToModel(changes_to_apply, &changes_applied, &changes_missing); DCHECK_EQ(size_t(0), changes_missing.size()); DCHECK_EQ(size_t(1), changes_applied.size()); @@ -96,7 +98,11 @@ bool DomDistillerStore::AddEntry(const ArticleEntry& entry) { } std::vector<ArticleEntry> DomDistillerStore::GetEntries() const { - return model_.GetEntries(); + std::vector<ArticleEntry> entries; + for (EntryMap::const_iterator it = model_.begin(); it != model_.end(); ++it) { + entries.push_back(it->second); + } + return entries; } // syncer::SyncableService implementation. @@ -127,7 +133,11 @@ void DomDistillerStore::StopSyncing(ModelType type) { } SyncDataList DomDistillerStore::GetAllSyncData(ModelType type) const { - return model_.GetAllSyncData(); + SyncDataList data; + for (EntryMap::const_iterator it = model_.begin(); it != model_.end(); ++it) { + data.push_back(CreateLocalData(it->second)); + } + return data; } SyncError DomDistillerStore::ProcessSyncChanges( @@ -136,34 +146,17 @@ SyncError DomDistillerStore::ProcessSyncChanges( DCHECK(database_loaded_); SyncChangeList database_changes; SyncChangeList sync_changes; - if (!ApplyChangesToModel(change_list, &database_changes, &sync_changes)) { - return SyncError(FROM_HERE, - SyncError::DATATYPE_ERROR, - "Applying changes to the DOM distiller model failed", - syncer::ARTICLES); - } + SyncError error = + ApplyChangesToModel(change_list, &database_changes, &sync_changes); ApplyChangesToDatabase(database_changes); DCHECK_EQ(size_t(0), sync_changes.size()); - return SyncError(); + return error; } -bool DomDistillerStore::ApplyChangesToModel( - const SyncChangeList& changes, - SyncChangeList* changes_applied, - SyncChangeList* changes_missing) { - DomDistillerModel::ChangeResult change_result = - model_.ApplyChangesToModel(changes, changes_applied, changes_missing); - if (change_result == DomDistillerModel::SUCCESS) { - return true; - } - - LOG(WARNING) << "Applying changes to DOM distiller model failed with error " - << change_result; - - database_.reset(); - database_loaded_ = false; - StopSyncing(syncer::ARTICLES); - return false; +ArticleEntry DomDistillerStore::GetEntryFromChange(const SyncChange& change) { + DCHECK(change.IsValid()); + DCHECK(change.sync_data().IsValid()); + return EntryFromSpecifics(change.sync_data().GetSpecifics()); } void DomDistillerStore::OnDatabaseInit(bool success) { @@ -245,6 +238,35 @@ bool DomDistillerStore::ApplyChangesToDatabase( return true; } +void DomDistillerStore::CalculateChangesForMerge( + const SyncDataList& data, + SyncChangeList* changes_to_apply, + SyncChangeList* changes_missing) { + typedef base::hash_set<std::string> StringSet; + StringSet entries_to_change; + for (SyncDataList::const_iterator it = data.begin(); it != data.end(); ++it) { + std::string entry_id = GetEntryIdFromSyncData(*it); + std::pair<StringSet::iterator, bool> insert_result = + entries_to_change.insert(entry_id); + + DCHECK(insert_result.second); + + SyncChange::SyncChangeType change_type = SyncChange::ACTION_ADD; + EntryMap::const_iterator current = model_.find(entry_id); + if (current != model_.end()) { + change_type = SyncChange::ACTION_UPDATE; + } + changes_to_apply->push_back(SyncChange(FROM_HERE, change_type, *it)); + } + + for (EntryMap::const_iterator it = model_.begin(); it != model_.end(); ++it) { + if (entries_to_change.find(it->first) == entries_to_change.end()) { + changes_missing->push_back(SyncChange( + FROM_HERE, SyncChange::ACTION_ADD, CreateLocalData(it->second))); + } + } +} + SyncMergeResult DomDistillerStore::MergeDataWithModel( const SyncDataList& data, SyncChangeList* changes_applied, @@ -253,18 +275,12 @@ SyncMergeResult DomDistillerStore::MergeDataWithModel( DCHECK(changes_missing); SyncMergeResult result(syncer::ARTICLES); - result.set_num_items_before_association(model_.GetNumEntries()); + result.set_num_items_before_association(model_.size()); SyncChangeList changes_to_apply; - model_.CalculateChangesForMerge(data, &changes_to_apply, changes_missing); - SyncError error; - if (!ApplyChangesToModel( - changes_to_apply, changes_applied, changes_missing)) { - error = SyncError(FROM_HERE, - SyncError::DATATYPE_ERROR, - "Applying changes to the DOM distiller model failed", - syncer::ARTICLES); - } + CalculateChangesForMerge(data, &changes_to_apply, changes_missing); + SyncError error = + ApplyChangesToModel(changes_to_apply, changes_applied, changes_missing); int num_added = 0; int num_modified = 0; @@ -288,10 +304,57 @@ SyncMergeResult DomDistillerStore::MergeDataWithModel( result.set_num_items_deleted(0); result.set_pre_association_version(0); - result.set_num_items_after_association(model_.GetNumEntries()); + result.set_num_items_after_association(model_.size()); result.set_error(error); return result; } +SyncError DomDistillerStore::ApplyChangesToModel( + const SyncChangeList& changes, + SyncChangeList* changes_applied, + SyncChangeList* changes_missing) { + DCHECK(changes_applied); + DCHECK(changes_missing); + + for (SyncChangeList::const_iterator it = changes.begin(); it != changes.end(); + ++it) { + ApplyChangeToModel(*it, changes_applied, changes_missing); + } + return SyncError(); +} + +void DomDistillerStore::ApplyChangeToModel(const SyncChange& change, + SyncChangeList* changes_applied, + SyncChangeList* changes_missing) { + DCHECK(changes_applied); + DCHECK(changes_missing); + DCHECK(change.IsValid()); + + const std::string& entry_id = GetEntryIdFromSyncData(change.sync_data()); + EntryMap::iterator entry_it = model_.find(entry_id); + + if (change.change_type() == SyncChange::ACTION_DELETE) { + // TODO(cjhopman): Support delete. + NOTIMPLEMENTED(); + StopSyncing(syncer::ARTICLES); + return; + } + + ArticleEntry entry = GetEntryFromChange(change); + if (entry_it == model_.end()) { + model_.insert(std::make_pair(entry.entry_id(), entry)); + changes_applied->push_back(SyncChange( + change.location(), SyncChange::ACTION_ADD, change.sync_data())); + } else { + if (!AreEntriesEqual(entry_it->second, entry)) { + // Currently, conflicts are simply resolved by accepting the last one to + // arrive. + entry_it->second = entry; + changes_applied->push_back(SyncChange( + change.location(), SyncChange::ACTION_UPDATE, change.sync_data())); + } + } +} + } // namespace dom_distiller diff --git a/components/dom_distiller/core/dom_distiller_store.h b/components/dom_distiller/core/dom_distiller_store.h index 18641b7..fdc1851 100644 --- a/components/dom_distiller/core/dom_distiller_store.h +++ b/components/dom_distiller/core/dom_distiller_store.h @@ -11,14 +11,12 @@ #include "base/memory/weak_ptr.h" #include "components/dom_distiller/core/article_entry.h" #include "components/dom_distiller/core/dom_distiller_database.h" -#include "components/dom_distiller/core/dom_distiller_model.h" #include "sync/api/sync_change.h" #include "sync/api/sync_data.h" #include "sync/api/sync_error.h" #include "sync/api/sync_error_factory.h" #include "sync/api/sync_merge_result.h" #include "sync/api/syncable_service.h" -#include "url/gurl.h" namespace base { class FilePath; @@ -36,12 +34,6 @@ class DomDistillerStoreInterface { virtual bool AddEntry(const ArticleEntry& entry) = 0; - // Lookup an ArticleEntry by ID or URL. Returns whether a corresponding entry - // was found. On success, if |entry| is not null, it will contain the entry. - virtual bool GetEntryById(const std::string& entry_id, - ArticleEntry* entry) = 0; - virtual bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) = 0; - // Gets a copy of all the current entries. virtual std::vector<ArticleEntry> GetEntries() const = 0; @@ -67,6 +59,8 @@ class DomDistillerStoreInterface { class DomDistillerStore : public syncer::SyncableService, DomDistillerStoreInterface { public: + typedef base::hash_map<std::string, ArticleEntry> EntryMap; + // Creates storage using the given database for local storage. Initializes the // database with |database_dir|. DomDistillerStore(scoped_ptr<DomDistillerDatabaseInterface> database, @@ -76,7 +70,7 @@ class DomDistillerStore : public syncer::SyncableService, // database with |database_dir|. Also initializes the internal model to // |initial_model|. DomDistillerStore(scoped_ptr<DomDistillerDatabaseInterface> database, - const std::vector<ArticleEntry>& initial_data, + const EntryMap& initial_model, const base::FilePath& database_dir); virtual ~DomDistillerStore(); @@ -84,9 +78,6 @@ class DomDistillerStore : public syncer::SyncableService, // DomDistillerStoreInterface implementation. virtual syncer::SyncableService* GetSyncableService() OVERRIDE; virtual bool AddEntry(const ArticleEntry& entry) OVERRIDE; - virtual bool GetEntryById(const std::string& entry_id, - ArticleEntry* entry) OVERRIDE; - virtual bool GetEntryByUrl(const GURL& url, ArticleEntry* entry) OVERRIDE; virtual std::vector<ArticleEntry> GetEntries() const OVERRIDE; // syncer::SyncableService implementation. @@ -101,6 +92,9 @@ class DomDistillerStore : public syncer::SyncableService, virtual syncer::SyncError ProcessSyncChanges( const tracked_objects::Location& from_here, const syncer::SyncChangeList& change_list) OVERRIDE; + + static ArticleEntry GetEntryFromChange(const syncer::SyncChange& change); + private: void OnDatabaseInit(bool success); void OnDatabaseLoad(bool success, scoped_ptr<EntryVector> entries); @@ -122,18 +116,24 @@ class DomDistillerStore : public syncer::SyncableService, const syncer::SyncChangeList& change_list); bool ApplyChangesToDatabase(const syncer::SyncChangeList& change_list); - // Applies the changes to |model_|. If the model returns an error, disables - // syncing and database changes and returns false. - bool ApplyChangesToModel(const syncer::SyncChangeList& change_list, - syncer::SyncChangeList* changes_applied, - syncer::SyncChangeList* changes_missing); + // Applies the change list to the in-memory model, appending the actual + // changes made to the model to changes_applied. If conflict resolution does + // not apply the requested change, then adds the "diff" to changes_missing. + syncer::SyncError ApplyChangesToModel( + const syncer::SyncChangeList& change_list, + syncer::SyncChangeList* changes_applied, + syncer::SyncChangeList* changes_missing); + + void ApplyChangeToModel(const syncer::SyncChange& change, + syncer::SyncChangeList* changes_applied, + syncer::SyncChangeList* changes_missing); scoped_ptr<syncer::SyncChangeProcessor> sync_processor_; scoped_ptr<syncer::SyncErrorFactory> error_factory_; scoped_ptr<DomDistillerDatabaseInterface> database_; bool database_loaded_; - DomDistillerModel model_; + EntryMap model_; base::WeakPtrFactory<DomDistillerStore> weak_ptr_factory_; diff --git a/components/dom_distiller/core/dom_distiller_store_unittest.cc b/components/dom_distiller/core/dom_distiller_store_unittest.cc index 9e4cf35..333d72d 100644 --- a/components/dom_distiller/core/dom_distiller_store_unittest.cc +++ b/components/dom_distiller/core/dom_distiller_store_unittest.cc @@ -34,21 +34,12 @@ namespace { const ModelType kDomDistillerModelType = syncer::ARTICLES; -typedef base::hash_map<std::string, ArticleEntry> EntryMap; +typedef DomDistillerStore::EntryMap EntryMap; void AddEntry(const ArticleEntry& e, EntryMap* map) { (*map)[e.entry_id()] = e; } -std::vector<ArticleEntry> EntryMapToList(const EntryMap& entries) { - std::vector<ArticleEntry> entry_list; - for (EntryMap::const_iterator it = entries.begin(); it != entries.end(); - ++it) { - entry_list.push_back(it->second); - } - return entry_list; -} - class FakeDB : public DomDistillerDatabaseInterface { typedef base::Callback<void(bool)> Callback; @@ -143,7 +134,7 @@ class FakeSyncChangeProcessor : public syncer::SyncChangeProcessor { for (SyncChangeList::const_iterator it = changes.begin(); it != changes.end(); ++it) { - AddEntry(GetEntryFromChange(*it), model_); + AddEntry(DomDistillerStore::GetEntryFromChange(*it), model_); } return SyncError(); } @@ -212,7 +203,7 @@ class DomDistillerStoreTest : public testing::Test { fake_db_ = new FakeDB(&db_model_); store_.reset(new DomDistillerStore( scoped_ptr<DomDistillerDatabaseInterface>(fake_db_), - EntryMapToList(store_model_), + store_model_, db_dir_)); } @@ -457,7 +448,7 @@ TEST_F(DomDistillerStoreTest, TestSyncMergeWithSecondDomDistillerStore) { FakeDB* other_fake_db = new FakeDB(&other_db_model); scoped_ptr<DomDistillerStore> owned_other_store(new DomDistillerStore( scoped_ptr<DomDistillerDatabaseInterface>(other_fake_db), - std::vector<ArticleEntry>(), + EntryMap(), base::FilePath(FILE_PATH_LITERAL("/fake/other/path")))); DomDistillerStore* other_store = owned_other_store.get(); other_fake_db->InitCallback(true); |