Chromium Code Reviews| Index: content/browser/service_worker/service_worker_database.cc |
| diff --git a/content/browser/service_worker/service_worker_database.cc b/content/browser/service_worker/service_worker_database.cc |
| index 77e33473f439b968c3b8be3c9d0900cab5e45e01..469223ba3e980c6f6c42b4324d261894bd1bb7c4 100644 |
| --- a/content/browser/service_worker/service_worker_database.cc |
| +++ b/content/browser/service_worker/service_worker_database.cc |
| @@ -7,6 +7,7 @@ |
| #include <string> |
| #include "base/file_util.h" |
| +#include "base/location.h" |
| #include "base/logging.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "third_party/leveldatabase/src/helpers/memenv/memenv.h" |
| @@ -17,18 +18,21 @@ |
| // LevelDB database schema |
| // ======================= |
| // |
| +// NOTE |
| +// - int64 value is serialized as a string by base::Int64ToString(). |
| +// |
| // Version 1 (in sorted order) |
| // key: "DB_VERSION" |
| -// value: <int64 serialized as a string> |
| +// value: "1" |
| // |
| // key: "NEXT_REGISTRATION_ID" |
| -// value: <int64 serialized as a string> |
| +// value: <int64 'next_available_registration_id'> |
| // |
| // key: "NEXT_RESOURCE_ID" |
| -// value: <int64 serialized as a string> |
| +// value: <int64 'next_available_resource_id'> |
| // |
| // key: "NEXT_VERSION_ID" |
| -// value: <int64 serialized as a string> |
| +// value: <int64 'next_available_version_id'> |
| namespace content { |
| @@ -80,9 +84,9 @@ bool ServiceWorkerDatabase::GetNextAvailableIds( |
| int64 ver_id = -1; |
| int64 res_id = -1; |
| - if (!ReadInt64(kNextRegIdKey, ®_id) || |
| - !ReadInt64(kNextVerIdKey, &ver_id) || |
| - !ReadInt64(kNextResIdKey, &res_id)) |
| + if (!ReadNextAvailableId(kNextRegIdKey, ®_id) || |
| + !ReadNextAvailableId(kNextVerIdKey, &ver_id) || |
| + !ReadNextAvailableId(kNextResIdKey, &res_id)) |
| return false; |
| *next_avail_registration_id = reg_id; |
| @@ -125,15 +129,13 @@ bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) { |
| if (!status.ok()) { |
| DCHECK(!db); |
| // TODO(nhiroki): Should we retry to open the database? |
| - DLOG(ERROR) << "Failed to open LevelDB database: " << status.ToString(); |
| - is_disabled_ = true; |
| + HandleError(FROM_HERE, status); |
| return false; |
| } |
| db_.reset(db); |
| if (IsEmpty() && !PopulateInitialData()) { |
| DLOG(ERROR) << "Failed to populate the database."; |
| - is_disabled_ = true; |
| db_.reset(); |
| return false; |
| } |
| @@ -141,56 +143,45 @@ bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) { |
| } |
| bool ServiceWorkerDatabase::PopulateInitialData() { |
| - scoped_ptr<leveldb::WriteBatch> batch(new leveldb::WriteBatch); |
| - batch->Put(kDatabaseVersionKey, base::Int64ToString(kCurrentSchemaVersion)); |
| - batch->Put(kNextRegIdKey, "0"); |
| - batch->Put(kNextResIdKey, "0"); |
| - batch->Put(kNextVerIdKey, "0"); |
| - return WriteBatch(batch.Pass()); |
| + leveldb::WriteBatch batch; |
| + batch.Put(kDatabaseVersionKey, base::Int64ToString(kCurrentSchemaVersion)); |
| + batch.Put(kNextRegIdKey, base::Int64ToString(0)); |
| + batch.Put(kNextResIdKey, base::Int64ToString(0)); |
| + batch.Put(kNextVerIdKey, base::Int64ToString(0)); |
| + return WriteBatch(&batch); |
| } |
| -bool ServiceWorkerDatabase::ReadInt64( |
| - const leveldb::Slice& key, |
| - int64* value_out) { |
| - DCHECK(value_out); |
| +bool ServiceWorkerDatabase::ReadNextAvailableId( |
| + const char* id_key, int64* next_avail_id) { |
| + DCHECK(id_key); |
| + DCHECK(next_avail_id); |
| std::string value; |
| - leveldb::Status status = db_->Get(leveldb::ReadOptions(), key, &value); |
| + leveldb::Status status = db_->Get(leveldb::ReadOptions(), id_key, &value); |
| if (!status.ok()) { |
| - DLOG(ERROR) << "Failed to read data keyed by " |
| - << key.ToString() << ": " << status.ToString(); |
| - is_disabled_ = true; |
| - if (status.IsCorruption()) |
| - was_corruption_detected_ = true; |
| + HandleError(FROM_HERE, status); |
| return false; |
| } |
| - int64 parsed = -1; |
| + int64 parsed; |
| if (!base::StringToInt64(value, &parsed)) { |
| - DLOG(ERROR) << "Database might be corrupted: " |
| - << key.ToString() << ", " << value; |
| - is_disabled_ = true; |
| - was_corruption_detected_ = true; |
| + HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse")); |
| return false; |
| } |
| - *value_out = parsed; |
| + *next_avail_id = parsed; |
| return true; |
| } |
| -bool ServiceWorkerDatabase::WriteBatch(scoped_ptr<leveldb::WriteBatch> batch) { |
| - if (!batch) |
| - return true; |
| - |
| - leveldb::Status status = db_->Write(leveldb::WriteOptions(), batch.get()); |
| - if (status.ok()) |
| - return true; |
| - |
| - DLOG(ERROR) << "Failed to write the batch: " << status.ToString(); |
| - is_disabled_ = true; |
| - if (status.IsCorruption()) |
| - was_corruption_detected_ = true; |
| - return false; |
| +bool ServiceWorkerDatabase::WriteBatch(leveldb::WriteBatch* batch) { |
| + DCHECK(batch); |
| + DCHECK(!is_disabled_); |
| + leveldb::Status status = db_->Write(leveldb::WriteOptions(), batch); |
| + if (!status.ok()) { |
| + HandleError(FROM_HERE, status); |
| + return false; |
| + } |
| + return true; |
| } |
| bool ServiceWorkerDatabase::IsOpen() { |
| @@ -200,7 +191,21 @@ bool ServiceWorkerDatabase::IsOpen() { |
| bool ServiceWorkerDatabase::IsEmpty() { |
| scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions())); |
| itr->SeekToFirst(); |
| + // TODO(nhiroki): Handle an error. |
| + DCHECK(itr->status().ok()); |
| return !itr->Valid(); |
| } |
| +void ServiceWorkerDatabase::HandleError( |
| + const tracked_objects::Location& from_here, |
| + const leveldb::Status& status) { |
| + // TODO(nhiroki): Add an UMA histogram. |
| + DLOG(ERROR) << "Failed at: " << from_here.ToString() |
| + << " with error: " << status.ToString(); |
| + is_disabled_ = true; |
| + if (status.IsCorruption()) |
| + was_corruption_detected_ = true; |
| + db_.reset(); |
|
michaeln
2014/04/25 00:01:36
ok, db is closed when anything goes wrong
|
| +} |
| + |
| } // namespace content |