1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/value_store/value_store_frontend.h" 6 7 #include "base/bind.h" 8 #include "base/debug/trace_event.h" 9 #include "base/files/file_path.h" 10 #include "base/logging.h" 11 #include "chrome/browser/value_store/leveldb_value_store.h" 12 #include "content/public/browser/browser_thread.h" 13 14 using content::BrowserThread; 15 16 class ValueStoreFrontend::Backend : public base::RefCountedThreadSafe<Backend> { 17 public: 18 Backend() : storage_(NULL) {} 19 20 void Init(const base::FilePath& db_path) { 21 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 22 DCHECK(!storage_); 23 TRACE_EVENT0("ValueStoreFrontend::Backend", "Init"); 24 db_path_ = db_path; 25 storage_ = new LeveldbValueStore(db_path); 26 } 27 28 // This variant is useful for testing (using a mock ValueStore). 29 void InitWithStore(scoped_ptr<ValueStore> storage) { 30 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 31 DCHECK(!storage_); 32 storage_ = storage.release(); 33 } 34 35 void Get(const std::string& key, 36 const ValueStoreFrontend::ReadCallback& callback) { 37 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 38 ValueStore::ReadResult result = storage_->Get(key); 39 40 // Extract the value from the ReadResult and pass ownership of it to the 41 // callback. 42 scoped_ptr<base::Value> value; 43 if (!result->HasError()) { 44 result->settings()->RemoveWithoutPathExpansion(key, &value); 45 } else { 46 LOG(INFO) << "Reading " << key << " from " << db_path_.value() 47 << " failed: " << result->error(); 48 } 49 50 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, 51 base::Bind(&ValueStoreFrontend::Backend::RunCallback, 52 this, callback, base::Passed(&value))); 53 } 54 55 void Set(const std::string& key, scoped_ptr<base::Value> value) { 56 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 57 // We don't need the old value, so skip generating changes. 58 storage_->Set(ValueStore::IGNORE_QUOTA | ValueStore::NO_GENERATE_CHANGES, 59 key, *value.get()); 60 } 61 62 void Remove(const std::string& key) { 63 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); 64 storage_->Remove(key); 65 } 66 67 private: 68 friend class base::RefCountedThreadSafe<Backend>; 69 70 virtual ~Backend() { 71 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 72 delete storage_; 73 } else { 74 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, storage_); 75 } 76 } 77 78 void RunCallback(const ValueStoreFrontend::ReadCallback& callback, 79 scoped_ptr<base::Value> value) { 80 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 81 callback.Run(value.Pass()); 82 } 83 84 // The actual ValueStore that handles persisting the data to disk. Used 85 // exclusively on the FILE thread. 86 ValueStore* storage_; 87 88 base::FilePath db_path_; 89 90 DISALLOW_COPY_AND_ASSIGN(Backend); 91 }; 92 93 ValueStoreFrontend::ValueStoreFrontend() 94 : backend_(new Backend()) { 95 } 96 97 ValueStoreFrontend::ValueStoreFrontend(const base::FilePath& db_path) 98 : backend_(new Backend()) { 99 Init(db_path); 100 } 101 102 ValueStoreFrontend::ValueStoreFrontend(ValueStore* value_store) 103 : backend_(new Backend()) { 104 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 105 base::Bind(&ValueStoreFrontend::Backend::InitWithStore, 106 backend_, base::Passed(scoped_ptr<ValueStore>(value_store)))); 107 } 108 109 ValueStoreFrontend::~ValueStoreFrontend() { 110 DCHECK(CalledOnValidThread()); 111 } 112 113 void ValueStoreFrontend::Init(const base::FilePath& db_path) { 114 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 115 base::Bind(&ValueStoreFrontend::Backend::Init, 116 backend_, db_path)); 117 } 118 119 void ValueStoreFrontend::Get(const std::string& key, 120 const ReadCallback& callback) { 121 DCHECK(CalledOnValidThread()); 122 123 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 124 base::Bind(&ValueStoreFrontend::Backend::Get, 125 backend_, key, callback)); 126 } 127 128 void ValueStoreFrontend::Set(const std::string& key, 129 scoped_ptr<base::Value> value) { 130 DCHECK(CalledOnValidThread()); 131 132 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 133 base::Bind(&ValueStoreFrontend::Backend::Set, 134 backend_, key, base::Passed(&value))); 135 } 136 137 void ValueStoreFrontend::Remove(const std::string& key) { 138 DCHECK(CalledOnValidThread()); 139 140 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 141 base::Bind(&ValueStoreFrontend::Backend::Remove, 142 backend_, key)); 143 } 144