Home | History | Annotate | Download | only in value_store
      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 
     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_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 
     97 ValueStoreFrontend::ValueStoreFrontend()
     98     : backend_(new Backend()) {
     99 }
    100 
    101 ValueStoreFrontend::ValueStoreFrontend(const base::FilePath& db_path)
    102     : backend_(new Backend()) {
    103   Init(db_path);
    104 }
    105 
    106 ValueStoreFrontend::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 
    113 ValueStoreFrontend::~ValueStoreFrontend() {
    114   DCHECK(CalledOnValidThread());
    115 }
    116 
    117 void 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 
    123 void 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 
    132 void 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 
    141 void 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