From 633098129a191b5573d7d23e7bdab8eb746bf5cc Mon Sep 17 00:00:00 2001 From: "asvitkine@chromium.org" Date: Tue, 20 May 2014 08:18:59 +0000 Subject: [PATCH] Revert 271602 "Implementation of leveldb-backed PrefStore." Caused failure: LevelDBPrefStoreTest.GetMutableValue (run #1): [ RUN ] LevelDBPrefStoreTest.GetMutableValue Received signal 11 SEGV_MAPERR 000000000008 #0 0x00000345595e base::debug::StackTrace::StackTrace() #1 0x000003455b78 base::debug::(anonymous namespace)::StackDumpSignalHandler() #2 0x7f22d6faccb0 \u003Cunknown> #3 0x000003473e6b base::JSONWriter::BuildJSONString() #4 0x000003474aca base::JSONWriter::WriteWithOptions() #5 0x0000028861d1 Serialize() #6 0x000002888b6e LevelDBPrefStore::ReportValueChanged() #7 0x0000016af06d LevelDBPrefStoreTest_GetMutableValue_Test::TestBody() http://build.chromium.org/p/chromium.chromiumos/builders/Linux%20ChromiumOS%20Tests%20%281%29/builds/43483/steps/unit_tests/logs/GetMutableValue > Implementation of leveldb-backed PrefStore. > > This is not hooked up yet, migration code from Json-backed stores is needed, among other things. > > BUG=362814 > > Review URL: https://codereview.chromium.org/169323003 TBR=dgrogan@chromium.org Review URL: https://codereview.chromium.org/290633013 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@271611 0039d316-1c4b-4281-b951-d872f2087c98 --- base/prefs/json_pref_store.cc | 5 - base/prefs/persistent_pref_store.h | 3 - .../browser/prefs/chrome_pref_service_factory.cc | 3 +- chrome/browser/prefs/leveldb_pref_store.cc | 418 --------------------- chrome/browser/prefs/leveldb_pref_store.h | 116 ------ .../browser/prefs/leveldb_pref_store_unittest.cc | 300 --------------- chrome/chrome_browser.gypi | 2 - chrome/chrome_tests_unit.gypi | 1 - .../test/data/prefs/corrupted_leveldb/000005.ldb | Bin 121 -> 0 bytes chrome/test/data/prefs/corrupted_leveldb/CURRENT | 1 - .../data/prefs/corrupted_leveldb/MANIFEST-000007 | Bin 88 -> 0 bytes tools/metrics/histograms/histograms.xml | 38 -- 12 files changed, 1 insertion(+), 886 deletions(-) delete mode 100644 chrome/browser/prefs/leveldb_pref_store.cc delete mode 100644 chrome/browser/prefs/leveldb_pref_store.h delete mode 100644 chrome/browser/prefs/leveldb_pref_store_unittest.cc delete mode 100644 chrome/test/data/prefs/corrupted_leveldb/000005.ldb delete mode 100644 chrome/test/data/prefs/corrupted_leveldb/CURRENT delete mode 100644 chrome/test/data/prefs/corrupted_leveldb/MANIFEST-000007 diff --git a/base/prefs/json_pref_store.cc b/base/prefs/json_pref_store.cc index a6c236261ba5..e99d64fc40c6 100644 --- a/base/prefs/json_pref_store.cc +++ b/base/prefs/json_pref_store.cc @@ -330,11 +330,6 @@ void JsonPrefStore::OnFileRead(scoped_ptr value, // operation itself. NOTREACHED(); break; - case PREF_READ_ERROR_LEVELDB_IO: - case PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY: - case PREF_READ_ERROR_LEVELDB_CORRUPTION: - // These are specific to LevelDBPrefStore. - NOTREACHED(); case PREF_READ_ERROR_MAX_ENUM: NOTREACHED(); break; diff --git a/base/prefs/persistent_pref_store.h b/base/prefs/persistent_pref_store.h index 11d2a54dcc0f..177d86097450 100644 --- a/base/prefs/persistent_pref_store.h +++ b/base/prefs/persistent_pref_store.h @@ -33,9 +33,6 @@ class BASE_PREFS_EXPORT PersistentPrefStore : public WriteablePrefStore { // Indicates that ReadPrefs() couldn't complete synchronously and is waiting // for an asynchronous task to complete first. PREF_READ_ERROR_ASYNCHRONOUS_TASK_INCOMPLETE = 10, - PREF_READ_ERROR_LEVELDB_IO = 11, - PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY = 12, - PREF_READ_ERROR_LEVELDB_CORRUPTION = 13, PREF_READ_ERROR_MAX_ENUM }; diff --git a/chrome/browser/prefs/chrome_pref_service_factory.cc b/chrome/browser/prefs/chrome_pref_service_factory.cc index 4aa72d2927d0..390bfc7f67de 100644 --- a/chrome/browser/prefs/chrome_pref_service_factory.cc +++ b/chrome/browser/prefs/chrome_pref_service_factory.cc @@ -313,8 +313,7 @@ void HandleReadError(PersistentPrefStore::PrefReadError error) { // an example problem that this can cause. // Do some diagnosis and try to avoid losing data. int message_id = 0; - if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE || - error == PersistentPrefStore::PREF_READ_ERROR_LEVELDB_CORRUPTION) { + if (error <= PersistentPrefStore::PREF_READ_ERROR_JSON_TYPE) { message_id = IDS_PREFERENCES_CORRUPT_ERROR; } else if (error != PersistentPrefStore::PREF_READ_ERROR_NO_FILE) { message_id = IDS_PREFERENCES_UNREADABLE_ERROR; diff --git a/chrome/browser/prefs/leveldb_pref_store.cc b/chrome/browser/prefs/leveldb_pref_store.cc deleted file mode 100644 index e43ec45e80e8..000000000000 --- a/chrome/browser/prefs/leveldb_pref_store.cc +++ /dev/null @@ -1,418 +0,0 @@ -// Copyright 2014 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/prefs/leveldb_pref_store.h" - -#include "base/bind.h" -#include "base/callback.h" -#include "base/file_util.h" -#include "base/json/json_string_value_serializer.h" -#include "base/location.h" -#include "base/metrics/sparse_histogram.h" -#include "base/sequenced_task_runner.h" -#include "base/task_runner_util.h" -#include "base/threading/thread_restrictions.h" -#include "base/time/time.h" -#include "base/values.h" -#include "third_party/leveldatabase/env_chromium.h" -#include "third_party/leveldatabase/src/include/leveldb/db.h" -#include "third_party/leveldatabase/src/include/leveldb/write_batch.h" - -namespace { - -enum ErrorMasks { - OPENED = 1 << 0, - DESTROYED = 1 << 1, - REPAIRED = 1 << 2, - DESTROY_FAILED = 1 << 3, - REPAIR_FAILED = 1 << 4, - IO_ERROR = 1 << 5, - DATA_LOST = 1 << 6, - ITER_NOT_OK = 1 << 7, - FILE_NOT_SPECIFIED = 1 << 8, -}; - -PersistentPrefStore::PrefReadError IntToPrefReadError(int error) { - DCHECK(error); - if (error == FILE_NOT_SPECIFIED) - return PersistentPrefStore::PREF_READ_ERROR_FILE_NOT_SPECIFIED; - if (error == OPENED) - return PersistentPrefStore::PREF_READ_ERROR_NONE; - if (error & IO_ERROR) - return PersistentPrefStore::PREF_READ_ERROR_LEVELDB_IO; - if (error & OPENED) - return PersistentPrefStore::PREF_READ_ERROR_LEVELDB_CORRUPTION; - return PersistentPrefStore::PREF_READ_ERROR_LEVELDB_CORRUPTION_READ_ONLY; -} - -} // namespace - -struct LevelDBPrefStore::ReadingResults { - ReadingResults() : error(0) {} - bool no_dir; - scoped_ptr db; - scoped_ptr value_map; - int error; -}; - -// An instance of this class is created on the UI thread but is used -// exclusively on the FILE thread. -class LevelDBPrefStore::FileThreadSerializer { - public: - explicit FileThreadSerializer(scoped_ptr db) : db_(db.Pass()) {} - void WriteToDatabase( - std::map* keys_to_set, - std::set* keys_to_delete) { - DCHECK(keys_to_set->size() > 0 || keys_to_delete->size() > 0); - leveldb::WriteBatch batch; - for (std::map::iterator iter = - keys_to_set->begin(); - iter != keys_to_set->end(); - iter++) { - batch.Put(iter->first, iter->second); - } - - for (std::set::iterator iter = keys_to_delete->begin(); - iter != keys_to_delete->end(); - iter++) { - batch.Delete(*iter); - } - - leveldb::Status status = db_->Write(leveldb::WriteOptions(), &batch); - - // DCHECK is fine; the corresponding error is ignored in JsonPrefStore. - // There's also no API available to surface the error back up to the caller. - // TODO(dgrogan): UMA? - DCHECK(status.ok()) << status.ToString(); - } - - private: - scoped_ptr db_; - DISALLOW_COPY_AND_ASSIGN(FileThreadSerializer); -}; - -bool MoveDirectoryAside(const base::FilePath& path) { - base::FilePath bad_path = path.AppendASCII(".bad"); - if (!base::Move(path, bad_path)) { - base::DeleteFile(bad_path, true); - return false; - } - return true; -} - -/* static */ -void LevelDBPrefStore::OpenDB(const base::FilePath& path, - ReadingResults* reading_results) { - DCHECK_EQ(0, reading_results->error); - leveldb::Options options; - options.create_if_missing = true; - leveldb::DB* db; - while (1) { - leveldb::Status status = - leveldb::DB::Open(options, path.AsUTF8Unsafe(), &db); - if (status.ok()) { - reading_results->db.reset(db); - reading_results->error |= OPENED; - break; - } - if (leveldb_env::IsIOError(status)) { - reading_results->error |= IO_ERROR; - break; - } - if (reading_results->error & DESTROYED) - break; - - DCHECK(!(reading_results->error & REPAIR_FAILED)); - if (!(reading_results->error & REPAIRED)) { - status = leveldb::RepairDB(path.AsUTF8Unsafe(), options); - if (status.ok()) { - reading_results->error |= REPAIRED; - continue; - } - reading_results->error |= REPAIR_FAILED; - } - if (!MoveDirectoryAside(path)) { - status = leveldb::DestroyDB(path.AsUTF8Unsafe(), options); - if (!status.ok()) { - reading_results->error |= DESTROY_FAILED; - break; - } - } - reading_results->error |= DESTROYED; - } - DCHECK(reading_results->error); - DCHECK(!((reading_results->error & OPENED) && - (reading_results->error & DESTROY_FAILED))); - DCHECK(reading_results->error != (REPAIR_FAILED | OPENED)); -} - -/* static */ -scoped_ptr LevelDBPrefStore::DoReading( - const base::FilePath& path) { - base::ThreadRestrictions::AssertIOAllowed(); - - scoped_ptr reading_results(new ReadingResults); - - reading_results->no_dir = !base::PathExists(path.DirName()); - OpenDB(path, reading_results.get()); - if (!reading_results->db) { - DCHECK(!(reading_results->error & OPENED)); - return reading_results.Pass(); - } - - DCHECK(reading_results->error & OPENED); - reading_results->value_map.reset(new PrefValueMap); - scoped_ptr it( - reading_results->db->NewIterator(leveldb::ReadOptions())); - // TODO(dgrogan): Is it really necessary to check it->status() each iteration? - for (it->SeekToFirst(); it->Valid() && it->status().ok(); it->Next()) { - const std::string value_string = it->value().ToString(); - JSONStringValueSerializer deserializer(value_string); - std::string error_message; - int error_code; - base::Value* json_value = - deserializer.Deserialize(&error_code, &error_message); - if (json_value) { - reading_results->value_map->SetValue(it->key().ToString(), json_value); - } else { - DLOG(ERROR) << "Invalid json for key " << it->key().ToString() - << ": " << error_message; - reading_results->error |= DATA_LOST; - } - } - - if (!it->status().ok()) - reading_results->error |= ITER_NOT_OK; - - return reading_results.Pass(); -} - -LevelDBPrefStore::LevelDBPrefStore( - const base::FilePath& filename, - base::SequencedTaskRunner* sequenced_task_runner) - : path_(filename), - sequenced_task_runner_(sequenced_task_runner), - original_task_runner_(base::MessageLoopProxy::current()), - read_only_(false), - initialized_(false), - read_error_(PREF_READ_ERROR_NONE), - weak_ptr_factory_(this) {} - -LevelDBPrefStore::~LevelDBPrefStore() { - CommitPendingWrite(); - sequenced_task_runner_->DeleteSoon(FROM_HERE, serializer_.release()); -} - -bool LevelDBPrefStore::GetValue(const std::string& key, - const base::Value** result) const { - DCHECK(initialized_); - const base::Value* tmp = NULL; - if (!prefs_.GetValue(key, &tmp)) { - return false; - } - - if (result) - *result = tmp; - return true; -} - -// Callers of GetMutableValue have to also call ReportValueChanged. -bool LevelDBPrefStore::GetMutableValue(const std::string& key, - base::Value** result) { - DCHECK(initialized_); - return prefs_.GetValue(key, result); -} - -void LevelDBPrefStore::AddObserver(PrefStore::Observer* observer) { - observers_.AddObserver(observer); -} - -void LevelDBPrefStore::RemoveObserver(PrefStore::Observer* observer) { - observers_.RemoveObserver(observer); -} - -bool LevelDBPrefStore::HasObservers() const { - return observers_.might_have_observers(); -} - -bool LevelDBPrefStore::IsInitializationComplete() const { return initialized_; } - -void LevelDBPrefStore::PersistFromUIThread() { - if (read_only_) - return; - DCHECK(serializer_); - - scoped_ptr > keys_to_delete(new std::set); - keys_to_delete->swap(keys_to_delete_); - - scoped_ptr > keys_to_set( - new std::map); - keys_to_set->swap(keys_to_set_); - - sequenced_task_runner_->PostTask( - FROM_HERE, - base::Bind(&LevelDBPrefStore::FileThreadSerializer::WriteToDatabase, - base::Unretained(serializer_.get()), - base::Owned(keys_to_set.release()), - base::Owned(keys_to_delete.release()))); -} - -void LevelDBPrefStore::ScheduleWrite() { - if (!timer_.IsRunning()) { - timer_.Start(FROM_HERE, - base::TimeDelta::FromSeconds(10), - this, - &LevelDBPrefStore::PersistFromUIThread); - } -} - -void LevelDBPrefStore::SetValue(const std::string& key, base::Value* value) { - SetValueInternal(key, value, true /*notify*/); -} - -void LevelDBPrefStore::SetValueSilently(const std::string& key, - base::Value* value) { - SetValueInternal(key, value, false /*notify*/); -} - -static std::string Serialize(base::Value* value) { - std::string value_string; - JSONStringValueSerializer serializer(&value_string); - bool serialized_ok = serializer.Serialize(*value); - DCHECK(serialized_ok); - return value_string; -} - -void LevelDBPrefStore::SetValueInternal(const std::string& key, - base::Value* value, - bool notify) { - DCHECK(initialized_); - DCHECK(value); - scoped_ptr new_value(value); - base::Value* old_value = NULL; - prefs_.GetValue(key, &old_value); - if (!old_value || !value->Equals(old_value)) { - std::string value_string = Serialize(value); - prefs_.SetValue(key, new_value.release()); - MarkForInsertion(key, value_string); - if (notify) - NotifyObservers(key); - } -} - -void LevelDBPrefStore::RemoveValue(const std::string& key) { - DCHECK(initialized_); - if (prefs_.RemoveValue(key)) { - MarkForDeletion(key); - NotifyObservers(key); - } -} - -bool LevelDBPrefStore::ReadOnly() const { return read_only_; } - -PersistentPrefStore::PrefReadError LevelDBPrefStore::GetReadError() const { - return read_error_; -} - -PersistentPrefStore::PrefReadError LevelDBPrefStore::ReadPrefs() { - DCHECK(!initialized_); - scoped_ptr reading_results; - if (path_.empty()) { - reading_results.reset(new ReadingResults); - reading_results->error = FILE_NOT_SPECIFIED; - } else { - reading_results = DoReading(path_); - } - - PrefReadError error = IntToPrefReadError(reading_results->error); - OnStorageRead(reading_results.Pass()); - return error; -} - -void LevelDBPrefStore::ReadPrefsAsync(ReadErrorDelegate* error_delegate) { - DCHECK_EQ(false, initialized_); - error_delegate_.reset(error_delegate); - if (path_.empty()) { - scoped_ptr reading_results(new ReadingResults); - reading_results->error = FILE_NOT_SPECIFIED; - OnStorageRead(reading_results.Pass()); - return; - } - PostTaskAndReplyWithResult(sequenced_task_runner_, - FROM_HERE, - base::Bind(&LevelDBPrefStore::DoReading, path_), - base::Bind(&LevelDBPrefStore::OnStorageRead, - weak_ptr_factory_.GetWeakPtr())); -} - -void LevelDBPrefStore::CommitPendingWrite() { - if (timer_.IsRunning()) { - timer_.Stop(); - PersistFromUIThread(); - } -} - -void LevelDBPrefStore::MarkForDeletion(const std::string& key) { - if (read_only_) - return; - keys_to_delete_.insert(key); - // Need to erase in case there's a set operation in the same batch that would - // clobber this delete. - keys_to_set_.erase(key); - ScheduleWrite(); -} - -void LevelDBPrefStore::MarkForInsertion(const std::string& key, - const std::string& value) { - if (read_only_) - return; - keys_to_set_[key] = value; - // Need to erase in case there's a delete operation in the same batch that - // would clobber this set. - keys_to_delete_.erase(key); - ScheduleWrite(); -} - -void LevelDBPrefStore::ReportValueChanged(const std::string& key) { - base::Value* new_value = NULL; - DCHECK(prefs_.GetValue(key, &new_value)); - std::string value_string = Serialize(new_value); - MarkForInsertion(key, value_string); - NotifyObservers(key); -} - -void LevelDBPrefStore::NotifyObservers(const std::string& key) { - FOR_EACH_OBSERVER(PrefStore::Observer, observers_, OnPrefValueChanged(key)); -} - -void LevelDBPrefStore::OnStorageRead( - scoped_ptr reading_results) { - UMA_HISTOGRAM_SPARSE_SLOWLY("LevelDBPrefStore.ReadErrors", - reading_results->error); - read_error_ = IntToPrefReadError(reading_results->error); - - if (reading_results->no_dir) { - FOR_EACH_OBSERVER( - PrefStore::Observer, observers_, OnInitializationCompleted(false)); - return; - } - - initialized_ = true; - - if (reading_results->db) { - DCHECK(reading_results->value_map); - serializer_.reset(new FileThreadSerializer(reading_results->db.Pass())); - prefs_.Swap(reading_results->value_map.get()); - } else { - read_only_ = true; - } - - // TODO(dgrogan): Call pref_filter_->FilterOnLoad - - if (error_delegate_.get() && read_error_ != PREF_READ_ERROR_NONE) - error_delegate_->OnError(read_error_); - - FOR_EACH_OBSERVER( - PrefStore::Observer, observers_, OnInitializationCompleted(true)); -} diff --git a/chrome/browser/prefs/leveldb_pref_store.h b/chrome/browser/prefs/leveldb_pref_store.h deleted file mode 100644 index 1eb37f342798..000000000000 --- a/chrome/browser/prefs/leveldb_pref_store.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2014 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. - -#ifndef CHROME_BROWSER_PREFS_LEVELDB_PREF_STORE_H_ -#define CHROME_BROWSER_PREFS_LEVELDB_PREF_STORE_H_ - -#include -#include - -#include "base/basictypes.h" -#include "base/compiler_specific.h" -#include "base/files/file_path.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop_proxy.h" -#include "base/observer_list.h" -#include "base/prefs/persistent_pref_store.h" -#include "base/prefs/pref_value_map.h" -#include "base/timer/timer.h" - -namespace base { -class DictionaryValue; -class SequencedTaskRunner; -class Value; -} - -namespace leveldb { -class DB; -} - -// A writable PrefStore implementation that is used for user preferences. -class LevelDBPrefStore : public PersistentPrefStore { - public: - // |sequenced_task_runner| is must be a shutdown-blocking task runner, ideally - // created by GetTaskRunnerForFile() method above. - LevelDBPrefStore(const base::FilePath& pref_filename, - base::SequencedTaskRunner* sequenced_task_runner); - - // PrefStore overrides: - virtual bool GetValue(const std::string& key, - const base::Value** result) const OVERRIDE; - virtual void AddObserver(PrefStore::Observer* observer) OVERRIDE; - virtual void RemoveObserver(PrefStore::Observer* observer) OVERRIDE; - virtual bool HasObservers() const OVERRIDE; - virtual bool IsInitializationComplete() const OVERRIDE; - - // PersistentPrefStore overrides: - virtual bool GetMutableValue(const std::string& key, - base::Value** result) OVERRIDE; - // Takes ownership of value. - virtual void SetValue(const std::string& key, base::Value* value) OVERRIDE; - virtual void SetValueSilently(const std::string& key, - base::Value* value) OVERRIDE; - virtual void RemoveValue(const std::string& key) OVERRIDE; - virtual bool ReadOnly() const OVERRIDE; - virtual PrefReadError GetReadError() const OVERRIDE; - virtual PrefReadError ReadPrefs() OVERRIDE; - virtual void ReadPrefsAsync(ReadErrorDelegate* error_delegate) OVERRIDE; - virtual void CommitPendingWrite() OVERRIDE; - virtual void ReportValueChanged(const std::string& key) OVERRIDE; - - private: - struct ReadingResults; - class FileThreadSerializer; - - virtual ~LevelDBPrefStore(); - - static scoped_ptr DoReading(const base::FilePath& path); - static void OpenDB(const base::FilePath& path, - ReadingResults* reading_results); - void OnStorageRead(scoped_ptr reading_results); - - void PersistFromUIThread(); - void RemoveFromUIThread(const std::string& key); - void ScheduleWrite(); - - void SetValueInternal(const std::string& key, - base::Value* value, - bool notify); - void NotifyObservers(const std::string& key); - void MarkForInsertion(const std::string& key, const std::string& value); - void MarkForDeletion(const std::string& key); - - base::FilePath path_; - - const scoped_refptr sequenced_task_runner_; - const scoped_refptr original_task_runner_; - - PrefValueMap prefs_; - - bool read_only_; - - ObserverList observers_; - - scoped_ptr error_delegate_; - - bool initialized_; - PrefReadError read_error_; - - // This object is created on the UI thread right after preferences are loaded - // from disk. A message to delete it is sent to the FILE thread by - // ~LevelDBPrefStore. - scoped_ptr serializer_; - - // Changes are accumulated in |keys_to_delete_| and |keys_to_set_| and are - // stored in the database according to |timer_|. - std::set keys_to_delete_; - std::map keys_to_set_; - base::OneShotTimer timer_; - - base::WeakPtrFactory weak_ptr_factory_; - - DISALLOW_COPY_AND_ASSIGN(LevelDBPrefStore); -}; - -#endif // CHROME_BROWSER_PREFS_LEVELDB_PREF_STORE_H_ diff --git a/chrome/browser/prefs/leveldb_pref_store_unittest.cc b/chrome/browser/prefs/leveldb_pref_store_unittest.cc deleted file mode 100644 index db523418c36e..000000000000 --- a/chrome/browser/prefs/leveldb_pref_store_unittest.cc +++ /dev/null @@ -1,300 +0,0 @@ -// Copyright 2014 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/prefs/leveldb_pref_store.h" - -#include "base/file_util.h" -#include "base/files/scoped_temp_dir.h" -#include "base/memory/scoped_ptr.h" -#include "base/message_loop/message_loop.h" -#include "base/path_service.h" -#include "base/run_loop.h" -#include "base/values.h" -#include "chrome/common/chrome_paths.h" -#include "testing/gmock/include/gmock/gmock.h" -#include "testing/gtest/include/gtest/gtest.h" - -namespace { - -class MockPrefStoreObserver : public PrefStore::Observer { - public: - MOCK_METHOD1(OnPrefValueChanged, void(const std::string&)); - MOCK_METHOD1(OnInitializationCompleted, void(bool)); -}; - -class MockReadErrorDelegate : public PersistentPrefStore::ReadErrorDelegate { - public: - MOCK_METHOD1(OnError, void(PersistentPrefStore::PrefReadError)); -}; - -} // namespace - -class LevelDBPrefStoreTest : public testing::Test { - protected: - virtual void SetUp() OVERRIDE { - ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); - - ASSERT_TRUE(PathService::Get(chrome::DIR_TEST_DATA, &data_dir_)); - data_dir_ = data_dir_.AppendASCII("prefs"); - ASSERT_TRUE(PathExists(data_dir_)); - } - - void Open() { - pref_store_ = new LevelDBPrefStore( - temp_dir_.path(), message_loop_.message_loop_proxy().get()); - EXPECT_EQ(LevelDBPrefStore::PREF_READ_ERROR_NONE, pref_store_->ReadPrefs()); - } - - void Close() { - pref_store_ = NULL; - base::RunLoop().RunUntilIdle(); - } - - void CloseAndReopen() { - Close(); - Open(); - } - - // The path to temporary directory used to contain the test operations. - base::ScopedTempDir temp_dir_; - // The path to the directory where the test data is stored in the source tree. - base::FilePath data_dir_; - // A message loop that we can use as the file thread message loop. - base::MessageLoop message_loop_; - - scoped_refptr pref_store_; -}; - -TEST_F(LevelDBPrefStoreTest, PutAndGet) { - Open(); - const std::string key = "some.key"; - pref_store_->SetValue(key, new base::FundamentalValue(5)); - base::FundamentalValue orig_value(5); - const base::Value* actual_value; - EXPECT_TRUE(pref_store_->GetValue(key, &actual_value)); - EXPECT_TRUE(orig_value.Equals(actual_value)); -} - -TEST_F(LevelDBPrefStoreTest, PutAndGetPersistent) { - Open(); - const std::string key = "some.key"; - pref_store_->SetValue(key, new base::FundamentalValue(5)); - - CloseAndReopen(); - const base::Value* actual_value = NULL; - base::FundamentalValue orig_value(5); - EXPECT_TRUE(pref_store_->GetValue(key, &actual_value)); - EXPECT_TRUE(orig_value.Equals(actual_value)); -} - -TEST_F(LevelDBPrefStoreTest, BasicObserver) { - scoped_refptr pref_store = new LevelDBPrefStore( - temp_dir_.path(), message_loop_.message_loop_proxy().get()); - MockPrefStoreObserver mock_observer; - pref_store->AddObserver(&mock_observer); - EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); - EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_NONE, pref_store->ReadPrefs()); - testing::Mock::VerifyAndClearExpectations(&mock_observer); - - const std::string key = "some.key"; - EXPECT_CALL(mock_observer, OnPrefValueChanged(key)).Times(1); - pref_store->SetValue(key, new base::FundamentalValue(5)); - - pref_store->RemoveObserver(&mock_observer); -} - -TEST_F(LevelDBPrefStoreTest, SetValueSilently) { - Open(); - - MockPrefStoreObserver mock_observer; - pref_store_->AddObserver(&mock_observer); - const std::string key = "some.key"; - EXPECT_CALL(mock_observer, OnPrefValueChanged(key)).Times(0); - pref_store_->SetValueSilently(key, new base::FundamentalValue(30)); - pref_store_->RemoveObserver(&mock_observer); - - CloseAndReopen(); - base::FundamentalValue value(30); - const base::Value* actual_value = NULL; - EXPECT_TRUE(pref_store_->GetValue(key, &actual_value)); - EXPECT_TRUE(base::Value::Equals(&value, actual_value)); -} - -TEST_F(LevelDBPrefStoreTest, GetMutableValue) { - Open(); - - const std::string key = "some.key"; - base::DictionaryValue* orig_value = new base::DictionaryValue; - orig_value->SetInteger("key2", 25); - pref_store_->SetValue(key, orig_value); - - base::Value* actual_value; - EXPECT_TRUE(pref_store_->GetMutableValue(key, &actual_value)); - EXPECT_TRUE(orig_value->Equals(actual_value)); - base::DictionaryValue* dict_value; - ASSERT_TRUE(actual_value->GetAsDictionary(&dict_value)); - dict_value->SetInteger("key2", 30); - pref_store_->ReportValueChanged(key); - - // Ensure the new value is stored in memory. - const base::Value* retrieved_value; - EXPECT_TRUE(pref_store_->GetValue(key, &retrieved_value)); - scoped_ptr golden_value(new base::DictionaryValue); - golden_value->SetInteger("key2", 30); - EXPECT_TRUE(base::Value::Equals(golden_value.get(), retrieved_value)); - - // Ensure the new value is persisted to disk. - CloseAndReopen(); - EXPECT_TRUE(pref_store_->GetValue(key, &retrieved_value)); - EXPECT_TRUE(base::Value::Equals(golden_value.get(), retrieved_value)); -} - -TEST_F(LevelDBPrefStoreTest, RemoveFromMemory) { - Open(); - const std::string key = "some.key"; - pref_store_->SetValue(key, new base::FundamentalValue(5)); - - MockPrefStoreObserver mock_observer; - pref_store_->AddObserver(&mock_observer); - EXPECT_CALL(mock_observer, OnPrefValueChanged(key)).Times(1); - pref_store_->RemoveValue(key); - pref_store_->RemoveObserver(&mock_observer); - - const base::Value* retrieved_value; - EXPECT_FALSE(pref_store_->GetValue(key, &retrieved_value)); -} - -TEST_F(LevelDBPrefStoreTest, RemoveFromDisk) { - Open(); - const std::string key = "some.key"; - pref_store_->SetValue(key, new base::FundamentalValue(5)); - - CloseAndReopen(); - - pref_store_->RemoveValue(key); - - CloseAndReopen(); - - const base::Value* retrieved_value; - EXPECT_FALSE(pref_store_->GetValue(key, &retrieved_value)); -} - -TEST_F(LevelDBPrefStoreTest, OpenAsync) { - // First set a key/value with a synchronous connection. - Open(); - const std::string key = "some.key"; - pref_store_->SetValue(key, new base::FundamentalValue(5)); - Close(); - - scoped_refptr pref_store(new LevelDBPrefStore( - temp_dir_.path(), message_loop_.message_loop_proxy().get())); - MockReadErrorDelegate* delegate = new MockReadErrorDelegate; - pref_store->ReadPrefsAsync(delegate); - - MockPrefStoreObserver mock_observer; - pref_store->AddObserver(&mock_observer); - EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); - base::RunLoop().RunUntilIdle(); - pref_store->RemoveObserver(&mock_observer); - - const base::Value* result; - EXPECT_TRUE(pref_store->GetValue("some.key", &result)); - int int_value; - EXPECT_TRUE(result->GetAsInteger(&int_value)); - EXPECT_EQ(5, int_value); - - pref_store = NULL; -} - -TEST_F(LevelDBPrefStoreTest, OpenAsyncError) { - // Open a connection that will lock the database. - Open(); - - // Try to open an async connection to the same database. - scoped_refptr pref_store(new LevelDBPrefStore( - temp_dir_.path(), message_loop_.message_loop_proxy().get())); - MockReadErrorDelegate* delegate = new MockReadErrorDelegate; - pref_store->ReadPrefsAsync(delegate); - - MockPrefStoreObserver mock_observer; - pref_store->AddObserver(&mock_observer); - EXPECT_CALL(*delegate, - OnError(PersistentPrefStore::PREF_READ_ERROR_LEVELDB_IO)) - .Times(1); - EXPECT_CALL(mock_observer, OnInitializationCompleted(true)).Times(1); - base::RunLoop().RunUntilIdle(); - pref_store->RemoveObserver(&mock_observer); - - EXPECT_TRUE(pref_store->ReadOnly()); - EXPECT_EQ(PersistentPrefStore::PREF_READ_ERROR_LEVELDB_IO, - pref_store->GetReadError()); - - // Sync connection to the database will be closed by the destructor. -} - -TEST_F(LevelDBPrefStoreTest, RepairCorrupt) { - // Open a database where CURRENT has no newline. Ensure that repair is called - // and there is no error reading the database. - base::FilePath corrupted_dir = data_dir_.AppendASCII("corrupted_leveldb"); - base::FilePath dest = temp_dir_.path().AppendASCII("corrupted_leveldb"); - const bool kRecursive = true; - ASSERT_TRUE(CopyDirectory(corrupted_dir, dest, kRecursive)); - pref_store_ = - new LevelDBPrefStore(dest, message_loop_.message_loop_proxy().get()); - EXPECT_EQ(LevelDBPrefStore::PREF_READ_ERROR_LEVELDB_CORRUPTION, - pref_store_->ReadPrefs()); -} - -TEST_F(LevelDBPrefStoreTest, Values) { - Open(); - pref_store_->SetValue("boolean", new base::FundamentalValue(false)); - pref_store_->SetValue("integer", new base::FundamentalValue(10)); - pref_store_->SetValue("double", new base::FundamentalValue(10.3)); - pref_store_->SetValue("string", new base::StringValue("some string")); - - base::DictionaryValue* dict_value = new base::DictionaryValue; - dict_value->Set("boolean", new base::FundamentalValue(true)); - scoped_ptr golden_dict_value(dict_value->DeepCopy()); - pref_store_->SetValue("dictionary", dict_value); - - base::ListValue* list_value = new base::ListValue; - list_value->Set(2, new base::StringValue("string in list")); - scoped_ptr golden_list_value(list_value->DeepCopy()); - pref_store_->SetValue("list", list_value); - - // Do something nontrivial as well. - base::DictionaryValue* compound_value = new base::DictionaryValue; - base::ListValue* outer_list = new base::ListValue; - base::ListValue* inner_list = new base::ListValue; - inner_list->Set(0, new base::FundamentalValue(5)); - outer_list->Set(1, inner_list); - compound_value->Set("compound_lists", outer_list); - scoped_ptr golden_compound_value( - compound_value->DeepCopy()); - pref_store_->SetValue("compound_value", compound_value); - - CloseAndReopen(); - - const base::Value* value; - EXPECT_TRUE(pref_store_->GetValue("boolean", &value)); - EXPECT_TRUE(base::FundamentalValue(false).Equals(value)); - - EXPECT_TRUE(pref_store_->GetValue("integer", &value)); - EXPECT_TRUE(base::FundamentalValue(10).Equals(value)); - - EXPECT_TRUE(pref_store_->GetValue("double", &value)); - EXPECT_TRUE(base::FundamentalValue(10.3).Equals(value)); - - EXPECT_TRUE(pref_store_->GetValue("string", &value)); - EXPECT_TRUE(base::StringValue("some string").Equals(value)); - - EXPECT_TRUE(pref_store_->GetValue("dictionary", &value)); - EXPECT_TRUE(base::Value::Equals(golden_dict_value.get(), value)); - - EXPECT_TRUE(pref_store_->GetValue("list", &value)); - EXPECT_TRUE(base::Value::Equals(golden_list_value.get(), value)); - - EXPECT_TRUE(pref_store_->GetValue("compound_value", &value)); - EXPECT_TRUE(base::Value::Equals(golden_compound_value.get(), value)); -} diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi index 9939ef4270b8..4749931e838e 100644 --- a/chrome/chrome_browser.gypi +++ b/chrome/chrome_browser.gypi @@ -1549,8 +1549,6 @@ 'browser/prefs/incognito_mode_prefs.h', 'browser/prefs/interceptable_pref_filter.cc', 'browser/prefs/interceptable_pref_filter.h', - 'browser/prefs/leveldb_pref_store.cc', - 'browser/prefs/leveldb_pref_store.h', 'browser/prefs/pref_hash_calculator.cc', 'browser/prefs/pref_hash_calculator.h', 'browser/prefs/pref_hash_filter.cc', diff --git a/chrome/chrome_tests_unit.gypi b/chrome/chrome_tests_unit.gypi index b8b5b4bf9817..a0d9987db754 100644 --- a/chrome/chrome_tests_unit.gypi +++ b/chrome/chrome_tests_unit.gypi @@ -1154,7 +1154,6 @@ 'browser/prefs/chrome_pref_service_unittest.cc', 'browser/prefs/command_line_pref_store_unittest.cc', 'browser/prefs/incognito_mode_prefs_unittest.cc', - 'browser/prefs/leveldb_pref_store_unittest.cc', 'browser/prefs/pref_hash_calculator_unittest.cc', 'browser/prefs/pref_hash_filter_unittest.cc', 'browser/prefs/pref_hash_store_impl_unittest.cc', diff --git a/chrome/test/data/prefs/corrupted_leveldb/000005.ldb b/chrome/test/data/prefs/corrupted_leveldb/000005.ldb deleted file mode 100644 index c39be32380471df25fe402711d2fc9723cf61764..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 121 zcwS==U@XqhP1Vaztz=|m00UDH0cKBdd1ede9Qd?w0|O^h3FChVV32`JO^wj-R^-qV QV;};A|8D43DRsXM0FaRt>i_@% diff --git a/chrome/test/data/prefs/corrupted_leveldb/CURRENT b/chrome/test/data/prefs/corrupted_leveldb/CURRENT deleted file mode 100644 index e9a7922e786f..000000000000 --- a/chrome/test/data/prefs/corrupted_leveldb/CURRENT +++ /dev/null @@ -1 +0,0 @@ -MANIFEST-000007 \ No newline at end of file diff --git a/chrome/test/data/prefs/corrupted_leveldb/MANIFEST-000007 b/chrome/test/data/prefs/corrupted_leveldb/MANIFEST-000007 deleted file mode 100644 index 6c1a1aca77f9b9057bbf71e84da1945f4d3f1e56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcwPel00001 literal 88 zcwU>e#p{6+10$nUPHI_dPD+xVQ)NkNd1i5{bAE0?Vo_pAei1tZYo$POer~E>c4{Rf ZBLf&<2&`LqcP|G6BNGQF12ZQJBLLL37i0hc diff --git a/tools/metrics/histograms/histograms.xml b/tools/metrics/histograms/histograms.xml index eaecb2a998dc..60700d7134ad 100644 --- a/tools/metrics/histograms/histograms.xml +++ b/tools/metrics/histograms/histograms.xml @@ -8989,14 +8989,6 @@ Therefore, the affected-histogram name has to have at least one dot in it. - - dgrogan@chromium.org - - Bitfield that indicates errors and recovery that occurred when opening a - LevelDB preferences database. - - - feng@chromium.org @@ -37283,36 +37275,6 @@ Therefore, the affected-histogram name has to have at least one dot in it. - - - - - - - - - - - - - - - - - - - - - - - - - - - - -- 2.11.4.GIT