Commit c6307aa9 authored by dmurph's avatar dmurph Committed by Commit bot

Adding size and total size to the service worker database.

Tests currently do not pass because the 'resources_total_size_bytes' is not populated in the database tests, as I moved this population to the service_worker_storage class. Waiting for guidance on the best place to populate this before modifying too many tests.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#300415}
parent 1eac3a72
......@@ -112,8 +112,8 @@ bool ServiceWorkerContextRequestHandler::ShouldAddToScriptCache(
version_->status() != ServiceWorkerVersion::INSTALLING) {
return false;
}
return version_->script_cache_map()->Lookup(url) ==
kInvalidServiceWorkerResponseId;
return version_->script_cache_map()->LookupResourceId(url) ==
kInvalidServiceWorkerResponseId;
}
bool ServiceWorkerContextRequestHandler::ShouldReadFromScriptCache(
......@@ -122,7 +122,7 @@ bool ServiceWorkerContextRequestHandler::ShouldReadFromScriptCache(
if (version_->status() == ServiceWorkerVersion::NEW ||
version_->status() == ServiceWorkerVersion::INSTALLING)
return false;
*response_id_out = version_->script_cache_map()->Lookup(url);
*response_id_out = version_->script_cache_map()->LookupResourceId(url);
return *response_id_out != kInvalidServiceWorkerResponseId;
}
......
......@@ -134,6 +134,7 @@ void PutRegistrationDataToBatch(
data.set_is_active(input.is_active);
data.set_has_fetch_handler(input.has_fetch_handler);
data.set_last_update_check_time(input.last_update_check.ToInternalValue());
data.set_resources_total_size_bytes(input.resources_total_size_bytes);
std::string value;
bool success = data.SerializeToString(&value);
......@@ -147,11 +148,13 @@ void PutResourceRecordToBatch(
int64 version_id,
leveldb::WriteBatch* batch) {
DCHECK(batch);
DCHECK_GE(input.size_bytes, 0);
// Convert ResourceRecord to ServiceWorkerResourceRecord.
ServiceWorkerResourceRecord record;
record.set_resource_id(input.resource_id);
record.set_url(input.url.spec());
record.set_size_bytes(input.size_bytes);
std::string value;
bool success = record.SerializeToString(&value);
......@@ -230,6 +233,8 @@ ServiceWorkerDatabase::Status ParseRegistrationData(
out->has_fetch_handler = data.has_fetch_handler();
out->last_update_check =
base::Time::FromInternalValue(data.last_update_check_time());
out->resources_total_size_bytes = data.resources_total_size_bytes();
return ServiceWorkerDatabase::STATUS_OK;
}
......@@ -248,6 +253,7 @@ ServiceWorkerDatabase::Status ParseResourceRecord(
// Convert ServiceWorkerResourceRecord to ResourceRecord.
out->resource_id = record.resource_id();
out->url = url;
out->size_bytes = record.size_bytes();
return ServiceWorkerDatabase::STATUS_OK;
}
......@@ -292,7 +298,8 @@ ServiceWorkerDatabase::RegistrationData::RegistrationData()
: registration_id(kInvalidServiceWorkerRegistrationId),
version_id(kInvalidServiceWorkerVersionId),
is_active(false),
has_fetch_handler(false) {
has_fetch_handler(false),
resources_total_size_bytes(0) {
}
ServiceWorkerDatabase::RegistrationData::~RegistrationData() {
......@@ -498,6 +505,15 @@ ServiceWorkerDatabase::Status ServiceWorkerDatabase::WriteRegistration(
BumpNextVersionIdIfNeeded(registration.version_id, &batch);
PutUniqueOriginToBatch(registration.scope.GetOrigin(), &batch);
#if DCHECK_IS_ON
uint64 total_size_bytes = 0;
for (const auto& resource : resources) {
total_size_bytes += resource.size_bytes;
}
DCHECK_EQ(total_size_bytes, registration.resources_total_size_bytes)
<< "The total size in the registration must match the cumulative "
<< "sizes of the resources.";
#endif
PutRegistrationDataToBatch(registration, &batch);
// Used for avoiding multiple writes for the same resource id or url.
......
......@@ -64,6 +64,9 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
bool has_fetch_handler;
base::Time last_update_check;
// Not populated until ServiceWorkerStorage::StoreRegistration is called.
uint64 resources_total_size_bytes;
RegistrationData();
~RegistrationData();
};
......@@ -71,9 +74,13 @@ class CONTENT_EXPORT ServiceWorkerDatabase {
struct ResourceRecord {
int64 resource_id;
GURL url;
// Signed so we can store -1 to specify an unknown or error state. When
// stored to the database, this value should always be >= 0.
int64 size_bytes;
ResourceRecord() {}
ResourceRecord(int64 id, GURL url) : resource_id(id), url(url) {}
ResourceRecord() : resource_id(-1), size_bytes(0) {}
ResourceRecord(int64 id, GURL url, int64 size_bytes)
: resource_id(id), url(url), size_bytes(size_bytes) {}
};
// Reads next available ids from the database. Returns OK if they are
......
......@@ -23,9 +23,12 @@ message ServiceWorkerRegistrationData {
// Serialized by Time::ToInternalValue().
required int64 last_update_check_time = 7;
optional uint64 resources_total_size_bytes = 8;
}
message ServiceWorkerResourceRecord {
required int64 resource_id = 1;
required string url = 2;
optional uint64 size_bytes = 3;
}
......@@ -37,12 +37,9 @@ GURL URL(const GURL& origin, const std::string& path) {
return out;
}
Resource CreateResource(int64 resource_id, const GURL& url) {
Resource CreateResource(int64 resource_id, const GURL& url, uint64 size_bytes) {
EXPECT_TRUE(url.is_valid());
Resource resource;
resource.resource_id = resource_id;
resource.url = url;
return resource;
return Resource(resource_id, url, size_bytes);
}
ServiceWorkerDatabase* CreateDatabase(const base::FilePath& path) {
......@@ -62,6 +59,8 @@ void VerifyRegistrationData(const RegistrationData& expected,
EXPECT_EQ(expected.is_active, actual.is_active);
EXPECT_EQ(expected.has_fetch_handler, actual.has_fetch_handler);
EXPECT_EQ(expected.last_update_check, actual.last_update_check);
EXPECT_EQ(expected.resources_total_size_bytes,
actual.resources_total_size_bytes);
}
void VerifyResourceRecords(const std::vector<Resource>& expected,
......@@ -70,6 +69,7 @@ void VerifyResourceRecords(const std::vector<Resource>& expected,
for (size_t i = 0; i < expected.size(); ++i) {
EXPECT_EQ(expected[i].resource_id, actual[i].resource_id);
EXPECT_EQ(expected[i].url, actual[i].url);
EXPECT_EQ(expected[i].size_bytes, actual[i].size_bytes);
}
}
......@@ -465,10 +465,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Basic) {
data.scope = URL(origin, "/foo");
data.script = URL(origin, "/script.js");
data.version_id = 200;
data.resources_total_size_bytes = 10939 + 200;
std::vector<Resource> resources;
resources.push_back(CreateResource(1, URL(origin, "/resource1")));
resources.push_back(CreateResource(2, URL(origin, "/resource2")));
resources.push_back(CreateResource(1, URL(origin, "/resource1"), 10939));
resources.push_back(CreateResource(2, URL(origin, "/resource2"), 200));
// Write a resource to the uncommitted list to make sure that writing
// registration removes resource ids associated with the registration from
......@@ -542,10 +543,11 @@ TEST(ServiceWorkerDatabaseTest, DeleteNonExistentRegistration) {
data.scope = URL(origin, "/foo");
data.script = URL(origin, "/script.js");
data.version_id = 200;
data.resources_total_size_bytes = 19 + 29129;
std::vector<Resource> resources;
resources.push_back(CreateResource(1, URL(origin, "/resource1")));
resources.push_back(CreateResource(2, URL(origin, "/resource2")));
resources.push_back(CreateResource(1, URL(origin, "/resource1"), 19));
resources.push_back(CreateResource(2, URL(origin, "/resource2"), 29129));
const int64 kNonExistentRegistrationId = 999;
const int64 kArbitraryVersionId = 222; // Used as a dummy initial value
......@@ -591,10 +593,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) {
data.scope = URL(origin, "/foo");
data.script = URL(origin, "/script.js");
data.version_id = 200;
data.resources_total_size_bytes = 10 + 11;
std::vector<Resource> resources1;
resources1.push_back(CreateResource(1, URL(origin, "/resource1")));
resources1.push_back(CreateResource(2, URL(origin, "/resource2")));
resources1.push_back(CreateResource(1, URL(origin, "/resource1"), 10));
resources1.push_back(CreateResource(2, URL(origin, "/resource2"), 11));
int64 deleted_version_id = 222; // Dummy inital value
std::vector<int64> newly_purgeable_resources;
......@@ -617,9 +620,10 @@ TEST(ServiceWorkerDatabaseTest, Registration_Overwrite) {
// Update the registration.
RegistrationData updated_data = data;
updated_data.version_id = data.version_id + 1;
updated_data.resources_total_size_bytes = 12 + 13;
std::vector<Resource> resources2;
resources2.push_back(CreateResource(3, URL(origin, "/resource3")));
resources2.push_back(CreateResource(4, URL(origin, "/resource4")));
resources2.push_back(CreateResource(3, URL(origin, "/resource3"), 12));
resources2.push_back(CreateResource(4, URL(origin, "/resource4"), 13));
EXPECT_EQ(ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(updated_data,
......@@ -660,10 +664,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
data1.scope = URL(origin, "/foo");
data1.script = URL(origin, "/script1.js");
data1.version_id = 200;
data1.resources_total_size_bytes = 1451 + 15234;
std::vector<Resource> resources1;
resources1.push_back(CreateResource(1, URL(origin, "/resource1")));
resources1.push_back(CreateResource(2, URL(origin, "/resource2")));
resources1.push_back(CreateResource(1, URL(origin, "/resource1"), 1451));
resources1.push_back(CreateResource(2, URL(origin, "/resource2"), 15234));
EXPECT_EQ(
ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
......@@ -675,10 +680,11 @@ TEST(ServiceWorkerDatabaseTest, Registration_Multiple) {
data2.scope = URL(origin, "/bar");
data2.script = URL(origin, "/script2.js");
data2.version_id = 201;
data2.resources_total_size_bytes = 5 + 6;
std::vector<Resource> resources2;
resources2.push_back(CreateResource(3, URL(origin, "/resource3")));
resources2.push_back(CreateResource(4, URL(origin, "/resource4")));
resources2.push_back(CreateResource(3, URL(origin, "/resource3"), 5));
resources2.push_back(CreateResource(4, URL(origin, "/resource4"), 6));
EXPECT_EQ(
ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
......@@ -957,10 +963,11 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
data1.scope = URL(origin1, "/foo");
data1.script = URL(origin1, "/script1.js");
data1.version_id = 100;
data1.resources_total_size_bytes = 2013 + 512;
std::vector<Resource> resources1;
resources1.push_back(CreateResource(1, URL(origin1, "/resource1")));
resources1.push_back(CreateResource(2, URL(origin1, "/resource2")));
resources1.push_back(CreateResource(1, URL(origin1, "/resource1"), 2013));
resources1.push_back(CreateResource(2, URL(origin1, "/resource2"), 512));
ASSERT_EQ(
ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
......@@ -971,10 +978,11 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
data2.scope = URL(origin1, "/bar");
data2.script = URL(origin1, "/script2.js");
data2.version_id = 101;
data2.resources_total_size_bytes = 4 + 5;
std::vector<Resource> resources2;
resources2.push_back(CreateResource(3, URL(origin1, "/resource3")));
resources2.push_back(CreateResource(4, URL(origin1, "/resource4")));
resources2.push_back(CreateResource(3, URL(origin1, "/resource3"), 4));
resources2.push_back(CreateResource(4, URL(origin1, "/resource4"), 5));
ASSERT_EQ(
ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
......@@ -986,10 +994,11 @@ TEST(ServiceWorkerDatabaseTest, DeleteAllDataForOrigin) {
data3.scope = URL(origin2, "/hoge");
data3.script = URL(origin2, "/script3.js");
data3.version_id = 102;
data3.resources_total_size_bytes = 6 + 7;
std::vector<Resource> resources3;
resources3.push_back(CreateResource(5, URL(origin2, "/resource5")));
resources3.push_back(CreateResource(6, URL(origin2, "/resource6")));
resources3.push_back(CreateResource(5, URL(origin2, "/resource5"), 6));
resources3.push_back(CreateResource(6, URL(origin2, "/resource6"), 7));
ASSERT_EQ(
ServiceWorkerDatabase::STATUS_OK,
database->WriteRegistration(
......
......@@ -933,6 +933,7 @@ class UpdateJobTestHelper
const GURL& script,
bool pause_after_download) override {
const std::string kMockScriptBody = "mock_script";
const uint64 kMockScriptSize = 19284;
ServiceWorkerVersion* version = context()->GetLiveVersion(version_id);
ASSERT_TRUE(version);
version->AddListener(this);
......@@ -943,7 +944,7 @@ class UpdateJobTestHelper
version->script_cache_map()->NotifyStartedCaching(script, resource_id);
WriteStringResponse(storage(), resource_id, kMockScriptBody);
version->script_cache_map()->NotifyFinishedCaching(
script, net::URLRequestStatus());
script, kMockScriptSize, net::URLRequestStatus());
} else {
// Spoof caching the script for the new version.
int64 resource_id = storage()->NewResourceId();
......@@ -953,7 +954,7 @@ class UpdateJobTestHelper
else
WriteStringResponse(storage(), resource_id, "mock_different_script");
version->script_cache_map()->NotifyFinishedCaching(
script, net::URLRequestStatus());
script, kMockScriptSize, net::URLRequestStatus());
}
EmbeddedWorkerTestHelper::OnStartWorker(
embedded_worker_id, version_id, scope, script, pause_after_download);
......
......@@ -493,9 +493,9 @@ void ServiceWorkerRegisterJob::OnPausedAfterDownload() {
registration()->active_version();
DCHECK(most_recent_version.get());
int64 most_recent_script_id =
most_recent_version->script_cache_map()->Lookup(script_url_);
most_recent_version->script_cache_map()->LookupResourceId(script_url_);
int64 new_script_id =
new_version()->script_cache_map()->Lookup(script_url_);
new_version()->script_cache_map()->LookupResourceId(script_url_);
// TODO(michaeln): It would be better to compare as the new resource
// is being downloaded and to avoid writing it to disk until we know
......
......@@ -22,52 +22,64 @@ ServiceWorkerScriptCacheMap::ServiceWorkerScriptCacheMap(
ServiceWorkerScriptCacheMap::~ServiceWorkerScriptCacheMap() {
}
int64 ServiceWorkerScriptCacheMap::Lookup(const GURL& url) {
ResourceIDMap::const_iterator found = resource_ids_.find(url);
if (found == resource_ids_.end())
int64 ServiceWorkerScriptCacheMap::LookupResourceId(const GURL& url) {
ResourceMap::const_iterator found = resource_map_.find(url);
if (found == resource_map_.end())
return kInvalidServiceWorkerResponseId;
return found->second;
return found->second.resource_id;
}
int64 ServiceWorkerScriptCacheMap::LookupResourceSize(const GURL& url) {
ResourceMap::const_iterator found = resource_map_.find(url);
if (found == resource_map_.end())
return kInvalidServiceWorkerResponseId;
return found->second.size_bytes;
}
void ServiceWorkerScriptCacheMap::NotifyStartedCaching(
const GURL& url, int64 resource_id) {
DCHECK_EQ(kInvalidServiceWorkerResponseId, Lookup(url));
DCHECK_EQ(kInvalidServiceWorkerResponseId, LookupResourceId(url));
DCHECK(owner_->status() == ServiceWorkerVersion::NEW ||
owner_->status() == ServiceWorkerVersion::INSTALLING);
resource_ids_[url] = resource_id;
resource_map_[url] =
ServiceWorkerDatabase::ResourceRecord(resource_id, url, -1);
context_->storage()->StoreUncommittedResponseId(resource_id);
}
void ServiceWorkerScriptCacheMap::NotifyFinishedCaching(
const GURL& url, const net::URLRequestStatus& status) {
DCHECK_NE(kInvalidServiceWorkerResponseId, Lookup(url));
const GURL& url,
int64 size_bytes,
const net::URLRequestStatus& status) {
DCHECK_NE(kInvalidServiceWorkerResponseId, LookupResourceId(url));
DCHECK(owner_->status() == ServiceWorkerVersion::NEW ||
owner_->status() == ServiceWorkerVersion::INSTALLING);
if (!status.is_success()) {
context_->storage()->DoomUncommittedResponse(Lookup(url));
resource_ids_.erase(url);
context_->storage()->DoomUncommittedResponse(LookupResourceId(url));
resource_map_.erase(url);
if (owner_->script_url() == url)
main_script_status_ = status;
} else {
resource_map_[url].size_bytes = size_bytes;
}
}
void ServiceWorkerScriptCacheMap::GetResources(
std::vector<ServiceWorkerDatabase::ResourceRecord>* resources) {
DCHECK(resources->empty());
for (ResourceIDMap::const_iterator it = resource_ids_.begin();
it != resource_ids_.end(); ++it) {
resources->push_back(
ServiceWorkerDatabase::ResourceRecord(it->second, it->first));
for (ResourceMap::const_iterator it = resource_map_.begin();
it != resource_map_.end();
++it) {
resources->push_back(it->second);
}
}
void ServiceWorkerScriptCacheMap::SetResources(
const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources) {
DCHECK(resource_ids_.empty());
DCHECK(resource_map_.empty());
typedef std::vector<ServiceWorkerDatabase::ResourceRecord> RecordVector;
for (RecordVector::const_iterator it = resources.begin();
it != resources.end(); ++it) {
resource_ids_[it->url] = it->resource_id;
resource_map_[it->url] = *it;
}
}
......
......@@ -25,12 +25,16 @@ class ServiceWorkerVersion;
// for a particular version's implicit script resources.
class CONTENT_EXPORT ServiceWorkerScriptCacheMap {
public:
int64 Lookup(const GURL& url);
int64 LookupResourceId(const GURL& url);
// A size of -1 means that we don't know the size yet
// (it has not finished caching).
int64 LookupResourceSize(const GURL& url);
// Used during the initial run of a new version to build the map
// of resources ids.
void NotifyStartedCaching(const GURL& url, int64 resource_id);
void NotifyFinishedCaching(const GURL& url,
int64 size_bytes,
const net::URLRequestStatus& status);
// Used to retrieve the results of the initial run of a new version.
......@@ -41,14 +45,14 @@ class CONTENT_EXPORT ServiceWorkerScriptCacheMap {
void SetResources(
const std::vector<ServiceWorkerDatabase::ResourceRecord>& resources);
size_t size() const { return resource_ids_.size(); }
size_t size() const { return resource_map_.size(); }
const net::URLRequestStatus& main_script_status() const {
return main_script_status_;
}
private:
typedef std::map<GURL, int64> ResourceIDMap;
typedef std::map<GURL, ServiceWorkerDatabase::ResourceRecord> ResourceMap;
// The version objects owns its script cache and provides a rawptr to it.
friend class ServiceWorkerVersion;
......@@ -59,7 +63,7 @@ class CONTENT_EXPORT ServiceWorkerScriptCacheMap {
ServiceWorkerVersion* owner_;
base::WeakPtr<ServiceWorkerContextCore> context_;
ResourceIDMap resource_ids_;
ResourceMap resource_map_;
net::URLRequestStatus main_script_status_;
DISALLOW_COPY_AND_ASSIGN(ServiceWorkerScriptCacheMap);
......
......@@ -465,6 +465,12 @@ void ServiceWorkerStorage::StoreRegistration(
ResourceList resources;
version->script_cache_map()->GetResources(&resources);
uint64 resources_total_size_bytes = 0;
for (const auto& resource : resources) {
resources_total_size_bytes += resource.size_bytes;
}
data.resources_total_size_bytes = resources_total_size_bytes;
if (!has_checked_for_stale_resources_)
DeleteStaleResources();
......
......@@ -561,6 +561,8 @@ class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest {
version_id_ = storage()->NewVersionId();
resource_id1_ = storage()->NewResourceId();
resource_id2_ = storage()->NewResourceId();
resource_id1_size_ = 239193;
resource_id2_size_ = 59923;
// Cons up a new registration+version with two script resources.
RegistrationData data;
......@@ -570,8 +572,10 @@ class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest {
data.version_id = version_id_;
data.is_active = false;
std::vector<ResourceRecord> resources;
resources.push_back(ResourceRecord(resource_id1_, script_));
resources.push_back(ResourceRecord(resource_id2_, import_));
resources.push_back(
ResourceRecord(resource_id1_, script_, resource_id1_size_));
resources.push_back(
ResourceRecord(resource_id2_, import_, resource_id2_size_));
registration_ = storage()->GetOrCreateRegistration(data, resources);
registration_->waiting_version()->SetStatus(ServiceWorkerVersion::NEW);
......@@ -609,7 +613,9 @@ class ServiceWorkerResourceStorageTest : public ServiceWorkerStorageTest {
int64 registration_id_;
int64 version_id_;
int64 resource_id1_;
uint64 resource_id1_size_;
int64 resource_id2_;
uint64 resource_id2_size_;
scoped_refptr<ServiceWorkerRegistration> registration_;
};
......
......@@ -69,6 +69,7 @@ void ServiceWorkerWriteToCacheJob::Kill() {
if (did_notify_started_ && !did_notify_finished_) {
version_->script_cache_map()->NotifyFinishedCaching(
url_,
-1,
net::URLRequestStatus(net::URLRequestStatus::FAILED, net::ERR_ABORTED));
did_notify_finished_ = true;
}
......@@ -128,7 +129,8 @@ bool ServiceWorkerWriteToCacheJob::ReadRawData(
// No more data to process, the job is complete.
io_buffer_ = NULL;
version_->script_cache_map()->NotifyFinishedCaching(url_, status);
version_->script_cache_map()->NotifyFinishedCaching(
url_, writer_->amount_written(), net::URLRequestStatus());
did_notify_finished_ = true;
return status.is_success();
}
......@@ -373,7 +375,7 @@ void ServiceWorkerWriteToCacheJob::OnReadCompleted(
DCHECK(request->status().is_success());
io_buffer_ = NULL;
version_->script_cache_map()->NotifyFinishedCaching(
url_, net::URLRequestStatus());
url_, writer_->amount_written(), net::URLRequestStatus());
did_notify_finished_ = true;
SetStatus(net::URLRequestStatus()); // Clear the IO_PENDING status
NotifyReadComplete(0);
......@@ -383,7 +385,11 @@ void ServiceWorkerWriteToCacheJob::AsyncNotifyDoneHelper(
const net::URLRequestStatus& status) {
DCHECK(!status.is_io_pending());
DCHECK(!did_notify_finished_);
version_->script_cache_map()->NotifyFinishedCaching(url_, status);
int size = -1;
if (writer_.get()) {
size = writer_->amount_written();
}
version_->script_cache_map()->NotifyFinishedCaching(url_, size, status);
did_notify_finished_ = true;
SetStatus(status);
NotifyDone(status);
......
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