| Index: webkit/dom_storage/session_storage_database.cc
|
| diff --git a/webkit/dom_storage/session_storage_database.cc b/webkit/dom_storage/session_storage_database.cc
|
| index 0f01db70778f2f2ba0fc43785121b34d76397d9a..6c853c8834ef12763e0495fabf59dc6459e987b0 100644
|
| --- a/webkit/dom_storage/session_storage_database.cc
|
| +++ b/webkit/dom_storage/session_storage_database.cc
|
| @@ -52,12 +52,20 @@ void SessionStorageDatabase::ReadAreaValues(const std::string& namespace_id,
|
| // nothing to be added to the result.
|
| if (!LazyOpen(false))
|
| return;
|
| +
|
| + // While ReadAreaValues is in progress, another thread can call
|
| + // CommitAreaChanges. CommitAreaChanges might update map ref count key while
|
| + // this thread is iterating over the map ref count key. To protect the reading
|
| + // operation, create a snapshot and read from it.
|
| + leveldb::ReadOptions options;
|
| + options.snapshot = db_->GetSnapshot();
|
| +
|
| std::string map_id;
|
| bool exists;
|
| - if (!GetMapForArea(namespace_id, origin.spec(), &exists, &map_id))
|
| - return;
|
| - if (exists)
|
| - ReadMap(map_id, result, false);
|
| + if (GetMapForArea(namespace_id, origin.spec(), options, &exists, &map_id) &&
|
| + exists)
|
| + ReadMap(map_id, options, result, false);
|
| + db_->ReleaseSnapshot(options.snapshot);
|
| }
|
|
|
| bool SessionStorageDatabase::CommitAreaChanges(const std::string& namespace_id,
|
| @@ -78,7 +86,8 @@ bool SessionStorageDatabase::CommitAreaChanges(const std::string& namespace_id,
|
|
|
| std::string map_id;
|
| bool exists;
|
| - if (!GetMapForArea(namespace_id, origin.spec(), &exists, &map_id))
|
| + if (!GetMapForArea(namespace_id, origin.spec(), leveldb::ReadOptions(),
|
| + &exists, &map_id))
|
| return false;
|
| if (exists) {
|
| int64 ref_count;
|
| @@ -223,6 +232,17 @@ bool SessionStorageDatabase::ReadNamespaceIds(
|
| return true;
|
| }
|
|
|
| +bool SessionStorageDatabase::ReadOriginsInNamespace(
|
| + const std::string& namespace_id, std::vector<GURL>* origins) {
|
| + std::map<std::string, std::string> areas;
|
| + if (!GetAreasInNamespace(namespace_id, &areas))
|
| + return false;
|
| + for (std::map<std::string, std::string>::const_iterator it = areas.begin();
|
| + it != areas.end(); ++it)
|
| + origins->push_back(GURL(it->first));
|
| + return true;
|
| +}
|
| +
|
| bool SessionStorageDatabase::LazyOpen(bool create_if_needed) {
|
| base::AutoLock auto_lock(db_lock_);
|
| if (db_error_ || is_inconsistent_) {
|
| @@ -373,7 +393,8 @@ bool SessionStorageDatabase::DeleteAreaHelper(
|
| leveldb::WriteBatch* batch) {
|
| std::string map_id;
|
| bool exists;
|
| - if (!GetMapForArea(namespace_id, origin, &exists, &map_id))
|
| + if (!GetMapForArea(namespace_id, origin, leveldb::ReadOptions(), &exists,
|
| + &map_id))
|
| return false;
|
| if (!exists)
|
| return true; // Nothing to delete.
|
| @@ -386,9 +407,10 @@ bool SessionStorageDatabase::DeleteAreaHelper(
|
|
|
| bool SessionStorageDatabase::GetMapForArea(const std::string& namespace_id,
|
| const std::string& origin,
|
| + const leveldb::ReadOptions& options,
|
| bool* exists, std::string* map_id) {
|
| std::string namespace_key = NamespaceKey(namespace_id, origin);
|
| - leveldb::Status s = db_->Get(leveldb::ReadOptions(), namespace_key, map_id);
|
| + leveldb::Status s = db_->Get(options, namespace_key, map_id);
|
| if (s.IsNotFound()) {
|
| *exists = false;
|
| return true;
|
| @@ -421,9 +443,10 @@ bool SessionStorageDatabase::CreateMapForArea(const std::string& namespace_id,
|
| }
|
|
|
| bool SessionStorageDatabase::ReadMap(const std::string& map_id,
|
| + const leveldb::ReadOptions& options,
|
| ValuesMap* result,
|
| bool only_keys) {
|
| - scoped_ptr<leveldb::Iterator> it(db_->NewIterator(leveldb::ReadOptions()));
|
| + scoped_ptr<leveldb::Iterator> it(db_->NewIterator(options));
|
| std::string map_start_key = MapRefCountKey(map_id);
|
| it->Seek(map_start_key);
|
| // The map needs to exist, otherwise we have a stale map_id in the database.
|
| @@ -518,7 +541,7 @@ bool SessionStorageDatabase::DecreaseMapRefCount(const std::string& map_id,
|
| bool SessionStorageDatabase::ClearMap(const std::string& map_id,
|
| leveldb::WriteBatch* batch) {
|
| ValuesMap values;
|
| - if (!ReadMap(map_id, &values, true))
|
| + if (!ReadMap(map_id, leveldb::ReadOptions(), &values, true))
|
| return false;
|
| for (ValuesMap::const_iterator it = values.begin(); it != values.end(); ++it)
|
| batch->Delete(MapKey(map_id, UTF16ToUTF8(it->first)));
|
| @@ -549,7 +572,7 @@ bool SessionStorageDatabase::DeepCopyArea(
|
| // Read the values from the old map here. If we don't need to copy the data,
|
| // this can stay empty.
|
| ValuesMap values;
|
| - if (copy_data && !ReadMap(*map_id, &values, false))
|
| + if (copy_data && !ReadMap(*map_id, leveldb::ReadOptions(), &values, false))
|
| return false;
|
| if (!DecreaseMapRefCount(*map_id, 1, batch))
|
| return false;
|
|
|