1a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
5a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/value_store/value_store_frontend.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h"
82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/debug/trace_event.h"
92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/files/file_path.h"
102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h"
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_thread.h"
12a1401311d1ab56c4ed0a474bd38c108f75cb0cd9Torne (Richard Coles)#include "extensions/browser/value_store/leveldb_value_store.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserThread;
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)class ValueStoreFrontend::Backend : public base::RefCountedThreadSafe<Backend> {
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  Backend() : storage_(NULL) {}
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  void Init(const base::FilePath& db_path) {
21effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_CURRENTLY_ON(BrowserThread::FILE);
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!storage_);
232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    TRACE_EVENT0("ValueStoreFrontend::Backend", "Init");
242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    db_path_ = db_path;
252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    storage_ = new LeveldbValueStore(db_path);
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // This variant is useful for testing (using a mock ValueStore).
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void InitWithStore(scoped_ptr<ValueStore> storage) {
30effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_CURRENTLY_ON(BrowserThread::FILE);
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    DCHECK(!storage_);
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    storage_ = storage.release();
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Get(const std::string& key,
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)           const ValueStoreFrontend::ReadCallback& callback) {
37effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_CURRENTLY_ON(BrowserThread::FILE);
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    ValueStore::ReadResult result = storage_->Get(key);
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // Extract the value from the ReadResult and pass ownership of it to the
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // callback.
423240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    scoped_ptr<base::Value> value;
433240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    if (!result->HasError()) {
4458537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      result->settings().RemoveWithoutPathExpansion(key, &value);
453240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    } else {
4658537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)      LOG(WARNING) << "Reading " << key << " from " << db_path_.value()
4758537e28ecd584eab876aee8be7156509866d23aTorne (Richard Coles)                   << " failed: " << result->error().message;
483240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch    }
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(&ValueStoreFrontend::Backend::RunCallback,
523240926e260ce088908e02ac07a6cf7b0c0cbf44Ben Murdoch                   this, callback, base::Passed(&value)));
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Set(const std::string& key, scoped_ptr<base::Value> value) {
56effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_CURRENTLY_ON(BrowserThread::FILE);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't need the old value, so skip generating changes.
58f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    ValueStore::WriteResult result = storage_->Set(
59f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        ValueStore::IGNORE_QUOTA | ValueStore::NO_GENERATE_CHANGES,
60f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        key,
61f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)        *value.get());
62f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)    LOG_IF(ERROR, result->HasError()) << "Error while writing " << key << " to "
63f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)                                      << db_path_.value();
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void Remove(const std::string& key) {
67effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_CURRENTLY_ON(BrowserThread::FILE);
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    storage_->Remove(key);
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) private:
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  friend class base::RefCountedThreadSafe<Backend>;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  virtual ~Backend() {
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (BrowserThread::CurrentlyOn(BrowserThread::FILE)) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      delete storage_;
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    } else {
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      BrowserThread::DeleteSoon(BrowserThread::FILE, FROM_HERE, storage_);
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void RunCallback(const ValueStoreFrontend::ReadCallback& callback,
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   scoped_ptr<base::Value> value) {
84effb81e5f8246d0db0270817048dc992db66e9fbBen Murdoch    DCHECK_CURRENTLY_ON(BrowserThread::UI);
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    callback.Run(value.Pass());
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // The actual ValueStore that handles persisting the data to disk. Used
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // exclusively on the FILE thread.
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ValueStore* storage_;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  base::FilePath db_path_;
932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DISALLOW_COPY_AND_ASSIGN(Backend);
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
972a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ValueStoreFrontend::ValueStoreFrontend()
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : backend_(new Backend()) {
992a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1002a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1012a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)ValueStoreFrontend::ValueStoreFrontend(const base::FilePath& db_path)
1022a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)    : backend_(new Backend()) {
1032a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  Init(db_path);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1064e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)ValueStoreFrontend::ValueStoreFrontend(scoped_ptr<ValueStore> value_store)
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    : backend_(new Backend()) {
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ValueStoreFrontend::Backend::InitWithStore,
1104e180b6a0b4720a9b8e9e959a882386f690f08ffTorne (Richard Coles)                 backend_, base::Passed(&value_store)));
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)ValueStoreFrontend::~ValueStoreFrontend() {
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void ValueStoreFrontend::Init(const base::FilePath& db_path) {
1182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)      base::Bind(&ValueStoreFrontend::Backend::Init,
1202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 backend_, db_path));
1212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)}
1222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ValueStoreFrontend::Get(const std::string& key,
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             const ReadCallback& callback) {
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ValueStoreFrontend::Backend::Get,
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 backend_, key, callback));
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ValueStoreFrontend::Set(const std::string& key,
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                             scoped_ptr<base::Value> value) {
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ValueStoreFrontend::Backend::Set,
1382a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)                 backend_, key, base::Passed(&value)));
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void ValueStoreFrontend::Remove(const std::string& key) {
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(CalledOnValidThread());
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(BrowserThread::FILE, FROM_HERE,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(&ValueStoreFrontend::Backend::Remove,
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 backend_, key));
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
148