Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(556)

Unified Diff: chrome/browser/chromeos/contacts/contact_database.cc

Issue 10832064: contacts: Add contacts::ContactDatabase. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: one parameter per line Created 8 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/chromeos/contacts/contact_database.cc
diff --git a/chrome/browser/chromeos/contacts/contact_database.cc b/chrome/browser/chromeos/contacts/contact_database.cc
new file mode 100644
index 0000000000000000000000000000000000000000..c5b4c62d80068d1c27e78c998d0a5acfa364ff34
--- /dev/null
+++ b/chrome/browser/chromeos/contacts/contact_database.cc
@@ -0,0 +1,242 @@
+// Copyright (c) 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.
+
+#include "chrome/browser/chromeos/contacts/contact_database.h"
+
+#include <set>
+
+#include "base/file_util.h"
+#include "base/sequenced_task_runner.h"
+#include "base/threading/sequenced_worker_pool.h"
+#include "chrome/browser/chromeos/contacts/contact.pb.h"
+#include "content/public/browser/browser_thread.h"
+#include "leveldb/db.h"
+#include "leveldb/iterator.h"
+#include "leveldb/options.h"
+#include "leveldb/slice.h"
+#include "leveldb/status.h"
+#include "leveldb/write_batch.h"
+
+using content::BrowserThread;
+
+namespace contacts {
+
+ContactDatabase::ContactDatabase() : weak_ptr_factory_(this) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ base::SequencedWorkerPool* pool = BrowserThread::GetBlockingPool();
+ task_runner_ = pool->GetSequencedTaskRunner(pool->GetSequenceToken());
+}
+
+void ContactDatabase::DestroyOnUIThread() {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ weak_ptr_factory_.InvalidateWeakPtrs();
+ task_runner_->PostNonNestableTask(
+ FROM_HERE,
+ base::Bind(&ContactDatabase::DestroyFromTaskRunner,
+ base::Unretained(this)));
+}
+
+void ContactDatabase::Init(const FilePath& database_dir,
+ InitCallback callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ bool* success = new bool(false);
+ task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&ContactDatabase::InitFromTaskRunner,
+ base::Unretained(this),
+ database_dir,
+ success),
+ base::Bind(&ContactDatabase::RunInitCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ base::Owned(success)));
+}
+
+void ContactDatabase::SaveContacts(scoped_ptr<ContactPointers> contacts,
+ bool is_full_update,
+ SaveCallback callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ bool* success = new bool(false);
+ task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&ContactDatabase::SaveContactsFromTaskRunner,
+ base::Unretained(this),
+ base::Passed(contacts.Pass()),
+ is_full_update,
+ success),
+ base::Bind(&ContactDatabase::RunSaveCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ base::Owned(success)));
+}
+
+void ContactDatabase::LoadContacts(LoadCallback callback) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ bool* success = new bool(false);
+ scoped_ptr<ScopedVector<Contact> > contacts(new ScopedVector<Contact>);
+ ScopedVector<Contact>* contacts_ptr = contacts.get();
+ task_runner_->PostTaskAndReply(
+ FROM_HERE,
+ base::Bind(&ContactDatabase::LoadContactsFromTaskRunner,
+ base::Unretained(this),
+ success,
+ contacts_ptr),
+ base::Bind(&ContactDatabase::RunLoadCallback,
+ weak_ptr_factory_.GetWeakPtr(),
+ callback,
+ base::Owned(success),
+ base::Passed(contacts.Pass())));
+}
+
+ContactDatabase::~ContactDatabase() {
+ DCHECK(IsRunByTaskRunner());
+}
+
+bool ContactDatabase::IsRunByTaskRunner() const {
+ return BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread();
+}
+
+void ContactDatabase::DestroyFromTaskRunner() {
+ DCHECK(IsRunByTaskRunner());
+ delete this;
+}
+
+void ContactDatabase::RunInitCallback(InitCallback callback,
+ const bool* success) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ callback.Run(*success);
+}
+
+void ContactDatabase::RunSaveCallback(SaveCallback callback,
+ const bool* success) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ callback.Run(*success);
+}
+
+void ContactDatabase::RunLoadCallback(
+ LoadCallback callback,
+ const bool* success,
+ scoped_ptr<ScopedVector<Contact> > contacts) {
+ DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
+ callback.Run(*success, contacts.Pass());
+}
+
+void ContactDatabase::InitFromTaskRunner(const FilePath& database_dir,
+ bool* success) {
+ DCHECK(IsRunByTaskRunner());
+ DCHECK(success);
+ VLOG(1) << "Opening " << database_dir.value();
+
+ *success = false;
+
+ leveldb::Options options;
+ options.create_if_missing = true;
+ bool delete_and_retry_on_corruption = true;
+
+ while (true) {
+ leveldb::DB* db = NULL;
+ leveldb::Status status =
+ leveldb::DB::Open(options, database_dir.value(), &db);
+ if (status.ok()) {
+ CHECK(db);
+ db_.reset(db);
+ *success = true;
+ return;
+ }
+
+ LOG(WARNING) << "Unable to open " << database_dir.value() << ": "
+ << status.ToString();
+
+ // Delete the existing database and try again (just once, though).
+ if (status.IsCorruption() && delete_and_retry_on_corruption) {
+ LOG(WARNING) << "Deleting possibly-corrupt database";
+ file_util::Delete(database_dir, true);
+ delete_and_retry_on_corruption = false;
+ } else {
+ break;
+ }
+ }
+}
+
+void ContactDatabase::SaveContactsFromTaskRunner(
+ scoped_ptr<ContactPointers> contacts,
+ bool is_full_update,
+ bool* success) {
+ DCHECK(IsRunByTaskRunner());
+ DCHECK(success);
+ VLOG(1) << "Saving " << contacts->size() << " contact(s) to database as "
+ << (is_full_update ? "full" : "partial") << " update";
+
+ *success = false;
+
+ // If we're doing a full update, find all of the existing keys first so we can
+ // delete ones that aren't present in the new set of contacts.
+ std::set<std::string> keys_to_delete;
+ if (is_full_update) {
+ leveldb::ReadOptions options;
+ scoped_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
+ db_iterator->SeekToFirst();
+ while (db_iterator->Valid()) {
+ keys_to_delete.insert(db_iterator->key().ToString());
+ db_iterator->Next();
+ }
+ }
+
+ // TODO(derat): Serializing all of the contacts and so we can write them in a
+ // single batch may be expensive, memory-wise. Consider writing them in
+ // several batches instead. (To avoid using partial writes in the event of a
+ // crash, maybe add a dummy "write completed" contact that's removed in the
+ // first batch and added in the last.)
+ leveldb::WriteBatch updates;
+ for (ContactPointers::const_iterator it = contacts->begin();
+ it != contacts->end(); ++it) {
+ const contacts::Contact& contact = **it;
+ updates.Put(leveldb::Slice(contact.provider_id()),
+ leveldb::Slice(contact.SerializeAsString()));
+ keys_to_delete.erase(contact.provider_id());
+ }
+
+ for (std::set<std::string>::const_iterator it = keys_to_delete.begin();
+ it != keys_to_delete.end(); ++it) {
+ updates.Delete(leveldb::Slice(*it));
+ }
+
+ leveldb::WriteOptions options;
+ options.sync = true;
+ leveldb::Status status = db_->Write(options, &updates);
+ if (status.ok())
+ *success = true;
+ else
+ LOG(WARNING) << "Failed writing contacts: " << status.ToString();
+}
+
+void ContactDatabase::LoadContactsFromTaskRunner(
+ bool* success,
+ ScopedVector<Contact>* contacts_out) {
+ DCHECK(IsRunByTaskRunner());
+ DCHECK(success);
+ DCHECK(contacts_out);
+
+ *success = false;
+ contacts_out->clear();
+
+ leveldb::ReadOptions options;
+ scoped_ptr<leveldb::Iterator> db_iterator(db_->NewIterator(options));
+ db_iterator->SeekToFirst();
+ while (db_iterator->Valid()) {
+ scoped_ptr<Contact> contact(new Contact);
+ leveldb::Slice value_slice = db_iterator->value();
+ if (!contact->ParseFromArray(value_slice.data(), value_slice.size())) {
+ LOG(WARNING) << "Unable to parse contact "
+ << db_iterator->key().ToString();
+ return;
+ }
+ contacts_out->push_back(contact.release());
+ db_iterator->Next();
+ }
+
+ *success = true;
+}
+
+} // namespace contacts
« no previous file with comments | « chrome/browser/chromeos/contacts/contact_database.h ('k') | chrome/browser/chromeos/contacts/contact_database_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698