1// Copyright 2014 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 "extensions/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 "content/public/browser/browser_thread.h" 12#include "extensions/browser/value_store/leveldb_value_store.h" 13 14using content::BrowserThread; 15 16class ValueStoreFrontend::Backend : public base::RefCountedThreadSafe<Backend> { 17 public: 18 Backend() : storage_(NULL) {} 19 20 void Init(const base::FilePath& db_path) { 21 DCHECK_CURRENTLY_ON(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_CURRENTLY_ON(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_CURRENTLY_ON(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(WARNING) << "Reading " << key << " from " << db_path_.value() 47 << " failed: " << result->error().message; 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_CURRENTLY_ON(BrowserThread::FILE); 57 // We don't need the old value, so skip generating changes. 58 ValueStore::WriteResult result = storage_->Set( 59 ValueStore::IGNORE_QUOTA | ValueStore::NO_GENERATE_CHANGES, 60 key, 61 *value.get()); 62 LOG_IF(ERROR, result->HasError()) << "Error while writing " << key << " to " 63 << db_path_.value(); 64 } 65 66 void Remove(const std::string& key) { 67 DCHECK_CURRENTLY_ON(BrowserThread::FILE); 68 storage_->Remove(key); 69 } 70 71 private: 72 friend class base::RefCountedThreadSafe<Backend>; 73 74 virtual ~Backend() { 75 if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) { 76 delete storage_; 77 } else { 78 BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, storage_); 79 } 80 } 81 82 void RunCallback(const ValueStoreFrontend::ReadCallback& callback, 83 scoped_ptr<base::Value> value) { 84 DCHECK_CURRENTLY_ON(BrowserThread::UI); 85 callback.Run(value.Pass()); 86 } 87 88 // The actual ValueStore that handles persisting the data to disk. Used 89 // exclusively on the FILE thread. 90 ValueStore* storage_; 91 92 base::FilePath db_path_; 93 94 DISALLOW_COPY_AND_ASSIGN(Backend); 95}; 96 97ValueStoreFrontend::ValueStoreFrontend() 98 : backend_(new Backend()) { 99} 100 101ValueStoreFrontend::ValueStoreFrontend(const base::FilePath& db_path) 102 : backend_(new Backend()) { 103 Init(db_path); 104} 105 106ValueStoreFrontend::ValueStoreFrontend(scoped_ptr<ValueStore> value_store) 107 : backend_(new Backend()) { 108 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 109 base::Bind(&ValueStoreFrontend::Backend::InitWithStore, 110 backend_, base::Passed(&value_store))); 111} 112 113ValueStoreFrontend::~ValueStoreFrontend() { 114 DCHECK(CalledOnValidThread()); 115} 116 117void ValueStoreFrontend::Init(const base::FilePath& db_path) { 118 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 119 base::Bind(&ValueStoreFrontend::Backend::Init, 120 backend_, db_path)); 121} 122 123void ValueStoreFrontend::Get(const std::string& key, 124 const ReadCallback& callback) { 125 DCHECK(CalledOnValidThread()); 126 127 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 128 base::Bind(&ValueStoreFrontend::Backend::Get, 129 backend_, key, callback)); 130} 131 132void ValueStoreFrontend::Set(const std::string& key, 133 scoped_ptr<base::Value> value) { 134 DCHECK(CalledOnValidThread()); 135 136 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 137 base::Bind(&ValueStoreFrontend::Backend::Set, 138 backend_, key, base::Passed(&value))); 139} 140 141void ValueStoreFrontend::Remove(const std::string& key) { 142 DCHECK(CalledOnValidThread()); 143 144 BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE, 145 base::Bind(&ValueStoreFrontend::Backend::Remove, 146 backend_, key)); 147} 148