Commit 13bcb652 authored by nhiroki@chromium.org's avatar nhiroki@chromium.org

ServiceWorker: Manipulate uncommitted/purgeable resource ids

This CL provides a way to manipulate uncommitted/purgeable resource ids
in ServiceWorkerDatabase.

- An uncommitted resource list contains resources which have been cached but a
registration associated with them hasn't been saved yet. When the registration
is saved, these are removed from the list.
- A purgeable resource list contains resources that no registration refers to.

BUG=364099
TEST=content_unittests --gtest_filter=ServiceWorkerDatabaseTest.*
R=michaeln@chromium.org

Review URL: https://codereview.chromium.org/254733002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@267118 0039d316-1c4b-4281-b951-d872f2087c98
parent e6e59f5d
...@@ -42,9 +42,15 @@ ...@@ -42,9 +42,15 @@
// key: "INITDATA_UNIQUE_ORIGIN:" + <GURL 'origin'> // key: "INITDATA_UNIQUE_ORIGIN:" + <GURL 'origin'>
// value: <empty> // value: <empty>
// //
// key: "PRES:" + <int64 'purgeable_resource_id'>
// value: <empty>
//
// key: "REG:" + <GURL 'origin'> + '\x00' + <int64 'registration_id'> // key: "REG:" + <GURL 'origin'> + '\x00' + <int64 'registration_id'>
// (ex. "REG:http://example.com\x00123456") // (ex. "REG:http://example.com\x00123456")
// value: <ServiceWorkerRegistrationData serialized as a string> // value: <ServiceWorkerRegistrationData serialized as a string>
//
// key: "URES:" + <int64 'uncommitted_resource_id'>
// value: <empty>
namespace content { namespace content {
...@@ -59,6 +65,9 @@ const char kUniqueOriginKey[] = "INITDATA_UNIQUE_ORIGIN:"; ...@@ -59,6 +65,9 @@ const char kUniqueOriginKey[] = "INITDATA_UNIQUE_ORIGIN:";
const char kRegKeyPrefix[] = "REG:"; const char kRegKeyPrefix[] = "REG:";
const char kKeySeparator = '\x00'; const char kKeySeparator = '\x00';
const char kUncommittedResIdKeyPrefix[] = "URES:";
const char kPurgeableResIdKeyPrefix[] = "PRES:";
const int64 kCurrentSchemaVersion = 1; const int64 kCurrentSchemaVersion = 1;
bool RemovePrefix(const std::string& str, bool RemovePrefix(const std::string& str,
...@@ -84,6 +93,11 @@ std::string CreateUniqueOriginKey(const GURL& origin) { ...@@ -84,6 +93,11 @@ std::string CreateUniqueOriginKey(const GURL& origin) {
return base::StringPrintf("%s%s", kUniqueOriginKey, origin.spec().c_str()); return base::StringPrintf("%s%s", kUniqueOriginKey, origin.spec().c_str());
} }
std::string CreateResourceIdKey(const char* key_prefix, int64 resource_id) {
return base::StringPrintf(
"%s%s", key_prefix, base::Int64ToString(resource_id).c_str());
}
void PutRegistrationDataToBatch( void PutRegistrationDataToBatch(
const ServiceWorkerDatabase::RegistrationData& input, const ServiceWorkerDatabase::RegistrationData& input,
leveldb::WriteBatch* batch) { leveldb::WriteBatch* batch) {
...@@ -350,6 +364,34 @@ bool ServiceWorkerDatabase::DeleteRegistration(int64 registration_id, ...@@ -350,6 +364,34 @@ bool ServiceWorkerDatabase::DeleteRegistration(int64 registration_id,
return WriteBatch(&batch); return WriteBatch(&batch);
} }
bool ServiceWorkerDatabase::GetUncommittedResourceIds(std::set<int64>* ids) {
return ReadResourceIds(kUncommittedResIdKeyPrefix, ids);
}
bool ServiceWorkerDatabase::WriteUncommittedResourceIds(
const std::set<int64>& ids) {
return WriteResourceIds(kUncommittedResIdKeyPrefix, ids);
}
bool ServiceWorkerDatabase::ClearUncommittedResourceIds(
const std::set<int64>& ids) {
return DeleteResourceIds(kUncommittedResIdKeyPrefix, ids);
}
bool ServiceWorkerDatabase::GetPurgeableResourceIds(std::set<int64>* ids) {
return ReadResourceIds(kPurgeableResIdKeyPrefix, ids);
}
bool ServiceWorkerDatabase::WritePurgeableResourceIds(
const std::set<int64>& ids) {
return WriteResourceIds(kPurgeableResIdKeyPrefix, ids);
}
bool ServiceWorkerDatabase::ClearPurgeableResourceIds(
const std::set<int64>& ids) {
return DeleteResourceIds(kPurgeableResIdKeyPrefix, ids);
}
bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) { bool ServiceWorkerDatabase::LazyOpen(bool create_if_needed) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread()); DCHECK(sequence_checker_.CalledOnValidSequencedThread());
if (IsOpen()) if (IsOpen())
...@@ -451,6 +493,75 @@ bool ServiceWorkerDatabase::ReadRegistrationData( ...@@ -451,6 +493,75 @@ bool ServiceWorkerDatabase::ReadRegistrationData(
return true; return true;
} }
bool ServiceWorkerDatabase::ReadResourceIds(const char* id_key_prefix,
std::set<int64>* ids) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(id_key_prefix);
DCHECK(ids);
if (!LazyOpen(false) || is_disabled_)
return false;
scoped_ptr<leveldb::Iterator> itr(db_->NewIterator(leveldb::ReadOptions()));
for (itr->Seek(id_key_prefix); itr->Valid(); itr->Next()) {
if (!itr->status().ok()) {
HandleError(FROM_HERE, itr->status());
ids->clear();
return false;
}
std::string unprefixed;
if (!RemovePrefix(itr->key().ToString(), id_key_prefix, &unprefixed))
break;
int64 resource_id;
if (!base::StringToInt64(unprefixed, &resource_id)) {
HandleError(FROM_HERE, leveldb::Status::Corruption("failed to parse"));
ids->clear();
return false;
}
ids->insert(resource_id);
}
return true;
}
bool ServiceWorkerDatabase::WriteResourceIds(const char* id_key_prefix,
const std::set<int64>& ids) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(id_key_prefix);
if (!LazyOpen(true) || is_disabled_)
return false;
if (ids.empty())
return true;
leveldb::WriteBatch batch;
for (std::set<int64>::const_iterator itr = ids.begin();
itr != ids.end(); ++itr) {
// Value should be empty.
batch.Put(CreateResourceIdKey(id_key_prefix, *itr), "");
}
return WriteBatch(&batch);
}
bool ServiceWorkerDatabase::DeleteResourceIds(const char* id_key_prefix,
const std::set<int64>& ids) {
DCHECK(sequence_checker_.CalledOnValidSequencedThread());
DCHECK(id_key_prefix);
if (!LazyOpen(true) || is_disabled_)
return false;
if (ids.empty())
return true;
leveldb::WriteBatch batch;
for (std::set<int64>::const_iterator itr = ids.begin();
itr != ids.end(); ++itr) {
batch.Delete(CreateResourceIdKey(id_key_prefix, *itr));
}
return WriteBatch(&batch);
}
bool ServiceWorkerDatabase::ReadDatabaseVersion(int64* db_version) { bool ServiceWorkerDatabase::ReadDatabaseVersion(int64* db_version) {
std::string value; std::string value;
leveldb::Status status = leveldb::Status status =
......
...@@ -96,6 +96,37 @@ class CONTENT_EXPORT ServiceWorkerDatabase { ...@@ -96,6 +96,37 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
bool DeleteRegistration(int64 registration_id, bool DeleteRegistration(int64 registration_id,
const GURL& origin); const GURL& origin);
// As new resources are put into the diskcache, they go into an uncommitted
// list. When a registration is saved that refers to those ids, they're
// removed from that list. When a resource no longer has any registrations or
// caches referring to it, it's added to the purgeable list. Periodically,
// the purgeable list can be purged from the diskcache. At system startup, all
// uncommitted ids are moved to the purgeable list.
// Reads uncommitted resource ids from the database. Returns true on success.
// Otherwise clears |ids| and returns false.
bool GetUncommittedResourceIds(std::set<int64>* ids);
// Writes |ids| into the database as uncommitted resources. Returns true on
// success. Otherwise writes nothing and returns false.
bool WriteUncommittedResourceIds(const std::set<int64>& ids);
// Deletes uncommitted resource ids specified by |ids| from the database.
// Returns true on success. Otherwise deletes nothing and returns false.
bool ClearUncommittedResourceIds(const std::set<int64>& ids);
// Reads purgeable resource ids from the database. Returns true on success.
// Otherwise clears |ids| and returns false.
bool GetPurgeableResourceIds(std::set<int64>* ids);
// Writes |ids| into the database as purgeable resources. Returns true on
// success. Otherwise writes nothing and returns false.
bool WritePurgeableResourceIds(const std::set<int64>& ids);
// Deletes purgeable resource ids specified by |ids| from the database.
// Returns true on success. Otherwise deletes nothing and returns false.
bool ClearPurgeableResourceIds(const std::set<int64>& ids);
bool is_disabled() const { return is_disabled_; } bool is_disabled() const { return is_disabled_; }
bool was_corruption_detected() const { return was_corruption_detected_; } bool was_corruption_detected() const { return was_corruption_detected_; }
...@@ -111,6 +142,12 @@ class CONTENT_EXPORT ServiceWorkerDatabase { ...@@ -111,6 +142,12 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
bool ReadRegistrationData(int64 registration_id, bool ReadRegistrationData(int64 registration_id,
const GURL& origin, const GURL& origin,
RegistrationData* registration); RegistrationData* registration);
bool ReadResourceIds(const char* id_key_prefix,
std::set<int64>* ids);
bool WriteResourceIds(const char* id_key_prefix,
const std::set<int64>& ids);
bool DeleteResourceIds(const char* id_key_prefix,
const std::set<int64>& ids);
bool ReadDatabaseVersion(int64* db_version); bool ReadDatabaseVersion(int64* db_version);
// Write a batch into the database. // Write a batch into the database.
......
...@@ -266,4 +266,88 @@ TEST(ServiceWorkerDatabaseTest, Registration) { ...@@ -266,4 +266,88 @@ TEST(ServiceWorkerDatabaseTest, Registration) {
data.registration_id, origin, &data_out, &resources_out)); data.registration_id, origin, &data_out, &resources_out));
} }
TEST(ServiceWorkerDatabaseTest, UncommittedResourceIds) {
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
// Write {1, 2, 3}.
std::set<int64> ids1;
ids1.insert(1);
ids1.insert(2);
ids1.insert(3);
EXPECT_TRUE(database->WriteUncommittedResourceIds(ids1));
std::set<int64> ids_out;
EXPECT_TRUE(database->GetUncommittedResourceIds(&ids_out));
EXPECT_EQ(ids1.size(), ids_out.size());
EXPECT_TRUE(base::STLIncludes(ids1, ids_out));
// Write {2, 4}.
std::set<int64> ids2;
ids2.insert(2);
ids2.insert(4);
EXPECT_TRUE(database->WriteUncommittedResourceIds(ids2));
ids_out.clear();
EXPECT_TRUE(database->GetUncommittedResourceIds(&ids_out));
EXPECT_EQ(4U, ids_out.size());
EXPECT_TRUE(ContainsKey(ids_out, 1));
EXPECT_TRUE(ContainsKey(ids_out, 2));
EXPECT_TRUE(ContainsKey(ids_out, 3));
EXPECT_TRUE(ContainsKey(ids_out, 4));
// Delete {2, 3}.
std::set<int64> ids3;
ids3.insert(2);
ids3.insert(3);
EXPECT_TRUE(database->ClearUncommittedResourceIds(ids3));
ids_out.clear();
EXPECT_TRUE(database->GetUncommittedResourceIds(&ids_out));
EXPECT_EQ(2U, ids_out.size());
EXPECT_TRUE(ContainsKey(ids_out, 1));
EXPECT_TRUE(ContainsKey(ids_out, 4));
}
TEST(ServiceWorkerDatabaseTest, PurgeableResourceIds) {
scoped_ptr<ServiceWorkerDatabase> database(CreateDatabaseInMemory());
// Write {1, 2, 3}.
std::set<int64> ids1;
ids1.insert(1);
ids1.insert(2);
ids1.insert(3);
EXPECT_TRUE(database->WritePurgeableResourceIds(ids1));
std::set<int64> ids_out;
EXPECT_TRUE(database->GetPurgeableResourceIds(&ids_out));
EXPECT_EQ(ids1.size(), ids_out.size());
EXPECT_TRUE(base::STLIncludes(ids1, ids_out));
// Write {2, 4}.
std::set<int64> ids2;
ids2.insert(2);
ids2.insert(4);
EXPECT_TRUE(database->WritePurgeableResourceIds(ids2));
ids_out.clear();
EXPECT_TRUE(database->GetPurgeableResourceIds(&ids_out));
EXPECT_EQ(4U, ids_out.size());
EXPECT_TRUE(ContainsKey(ids_out, 1));
EXPECT_TRUE(ContainsKey(ids_out, 2));
EXPECT_TRUE(ContainsKey(ids_out, 3));
EXPECT_TRUE(ContainsKey(ids_out, 4));
// Delete {2, 3}.
std::set<int64> ids3;
ids3.insert(2);
ids3.insert(3);
EXPECT_TRUE(database->ClearPurgeableResourceIds(ids3));
ids_out.clear();
EXPECT_TRUE(database->GetPurgeableResourceIds(&ids_out));
EXPECT_EQ(2U, ids_out.size());
EXPECT_TRUE(ContainsKey(ids_out, 1));
EXPECT_TRUE(ContainsKey(ids_out, 4));
}
} // namespace content } // namespace content
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment