Commit 19f69e90 authored by kristipark's avatar kristipark Committed by Commit Bot

[DevTools] [Quota] Display usage per storage type

Bug: 729772
Change-Id: I34b16707b790f65faba01bdcc44bbd98c911b93b
Reviewed-on: https://chromium-review.googlesource.com/541981
Commit-Queue: Kristi Park <kristipark@chromium.org>
Reviewed-by: default avatarDmitry Gozman <dgozman@chromium.org>
Cr-Commit-Position: refs/heads/master@{#481713}
parent 26834276
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "content/browser/frame_host/render_frame_host_impl.h" #include "content/browser/frame_host/render_frame_host_impl.h"
#include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host.h"
#include "content/public/browser/storage_partition.h" #include "content/public/browser/storage_partition.h"
#include "storage/browser/quota/quota_client.h"
#include "storage/browser/quota/quota_manager.h" #include "storage/browser/quota/quota_manager.h"
#include "storage/common/quota/quota_status_code.h" #include "storage/common/quota/quota_status_code.h"
...@@ -19,40 +20,61 @@ namespace content { ...@@ -19,40 +20,61 @@ namespace content {
namespace protocol { namespace protocol {
namespace { namespace {
static const char kAppCache[] = "appcache"; Storage::StorageType GetTypeName(storage::QuotaClient::ID id) {
static const char kCookies[] = "cookies"; switch (id) {
static const char kFileSystems[] = "filesystems"; case storage::QuotaClient::kFileSystem:
static const char kIndexedDB[] = "indexeddb"; return Storage::StorageTypeEnum::File_systems;
static const char kLocalStorage[] = "local_storage"; case storage::QuotaClient::kDatabase:
static const char kShaderCache[] = "shader_cache"; return Storage::StorageTypeEnum::Websql;
static const char kWebSQL[] = "websql"; case storage::QuotaClient::kAppcache:
static const char kServiceWorkers[] = "service_workers"; return Storage::StorageTypeEnum::Appcache;
static const char kCacheStorage[] = "cache_storage"; case storage::QuotaClient::kIndexedDatabase:
static const char kAll[] = "all"; return Storage::StorageTypeEnum::Indexeddb;
case storage::QuotaClient::kServiceWorkerCache:
return Storage::StorageTypeEnum::Cache_storage;
case storage::QuotaClient::kServiceWorker:
return Storage::StorageTypeEnum::Service_workers;
default:
return Storage::StorageTypeEnum::Other;
}
}
void ReportUsageAndQuotaDataOnUIThread( void ReportUsageAndQuotaDataOnUIThread(
std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback, std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback,
storage::QuotaStatusCode code, storage::QuotaStatusCode code,
int64_t usage, int64_t usage,
int64_t quota) { int64_t quota,
base::flat_map<storage::QuotaClient::ID, int64_t> usage_breakdown) {
DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK_CURRENTLY_ON(BrowserThread::UI);
if (code != storage::kQuotaStatusOk) { if (code != storage::kQuotaStatusOk) {
return callback->sendFailure( return callback->sendFailure(
Response::Error("Quota information is not available")); Response::Error("Quota information is not available"));
} }
callback->sendSuccess(usage, quota);
std::unique_ptr<Array<Storage::UsageForType>> usageList =
Array<Storage::UsageForType>::create();
for (const auto& usage : usage_breakdown) {
std::unique_ptr<Storage::UsageForType> entry =
Storage::UsageForType::Create()
.SetStorageType(GetTypeName(usage.first))
.SetUsage(usage.second)
.Build();
usageList->addItem(std::move(entry));
}
callback->sendSuccess(usage, quota, std::move(usageList));
} }
void GotUsageAndQuotaDataCallback( void GotUsageAndQuotaDataCallback(
std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback, std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback,
storage::QuotaStatusCode code, storage::QuotaStatusCode code,
int64_t usage, int64_t usage,
int64_t quota) { int64_t quota,
base::flat_map<storage::QuotaClient::ID, int64_t> usage_breakdown) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
BrowserThread::PostTask( BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
BrowserThread::UI, FROM_HERE,
base::Bind(ReportUsageAndQuotaDataOnUIThread, base::Bind(ReportUsageAndQuotaDataOnUIThread,
base::Passed(std::move(callback)), code, usage, quota)); base::Passed(std::move(callback)), code,
usage, quota, std::move(usage_breakdown)));
} }
void GetUsageAndQuotaOnIOThread( void GetUsageAndQuotaOnIOThread(
...@@ -60,7 +82,7 @@ void GetUsageAndQuotaOnIOThread( ...@@ -60,7 +82,7 @@ void GetUsageAndQuotaOnIOThread(
const GURL& url, const GURL& url,
std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback) { std::unique_ptr<StorageHandler::GetUsageAndQuotaCallback> callback) {
DCHECK_CURRENTLY_ON(BrowserThread::IO); DCHECK_CURRENTLY_ON(BrowserThread::IO);
manager->GetUsageAndQuotaForWebApps( manager->GetUsageAndQuotaWithBreakdown(
url, storage::kStorageTypeTemporary, url, storage::kStorageTypeTemporary,
base::Bind(&GotUsageAndQuotaDataCallback, base::Bind(&GotUsageAndQuotaDataCallback,
base::Passed(std::move(callback)))); base::Passed(std::move(callback))));
...@@ -93,25 +115,25 @@ Response StorageHandler::ClearDataForOrigin( ...@@ -93,25 +115,25 @@ Response StorageHandler::ClearDataForOrigin(
storage_types, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY); storage_types, ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_NONEMPTY);
std::unordered_set<std::string> set(types.begin(), types.end()); std::unordered_set<std::string> set(types.begin(), types.end());
uint32_t remove_mask = 0; uint32_t remove_mask = 0;
if (set.count(kAppCache)) if (set.count(Storage::StorageTypeEnum::Appcache))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE; remove_mask |= StoragePartition::REMOVE_DATA_MASK_APPCACHE;
if (set.count(kCookies)) if (set.count(Storage::StorageTypeEnum::Cookies))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES; remove_mask |= StoragePartition::REMOVE_DATA_MASK_COOKIES;
if (set.count(kFileSystems)) if (set.count(Storage::StorageTypeEnum::File_systems))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS; remove_mask |= StoragePartition::REMOVE_DATA_MASK_FILE_SYSTEMS;
if (set.count(kIndexedDB)) if (set.count(Storage::StorageTypeEnum::Indexeddb))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB; remove_mask |= StoragePartition::REMOVE_DATA_MASK_INDEXEDDB;
if (set.count(kLocalStorage)) if (set.count(Storage::StorageTypeEnum::Local_storage))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE; remove_mask |= StoragePartition::REMOVE_DATA_MASK_LOCAL_STORAGE;
if (set.count(kShaderCache)) if (set.count(Storage::StorageTypeEnum::Shader_cache))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE; remove_mask |= StoragePartition::REMOVE_DATA_MASK_SHADER_CACHE;
if (set.count(kWebSQL)) if (set.count(Storage::StorageTypeEnum::Websql))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL; remove_mask |= StoragePartition::REMOVE_DATA_MASK_WEBSQL;
if (set.count(kServiceWorkers)) if (set.count(Storage::StorageTypeEnum::Service_workers))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS; remove_mask |= StoragePartition::REMOVE_DATA_MASK_SERVICE_WORKERS;
if (set.count(kCacheStorage)) if (set.count(Storage::StorageTypeEnum::Cache_storage))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_CACHE_STORAGE; remove_mask |= StoragePartition::REMOVE_DATA_MASK_CACHE_STORAGE;
if (set.count(kAll)) if (set.count(Storage::StorageTypeEnum::All))
remove_mask |= StoragePartition::REMOVE_DATA_MASK_ALL; remove_mask |= StoragePartition::REMOVE_DATA_MASK_ALL;
if (!remove_mask) if (!remove_mask)
......
...@@ -5,8 +5,11 @@ Tests quota reporting. ...@@ -5,8 +5,11 @@ Tests quota reporting.
Tree element found: true Tree element found: true
Clear storage view is visible: true Clear storage view is visible: true
0 B storage quota used out of - 0 B used out of -- storage quota
Usage breakdown:
Running: Now with data Running: Now with data
9.5 MB storage quota used out of - 9.5 MB used out of -- storage quota
Usage breakdown:
IndexedDB: 9.5 MB
...@@ -30,8 +30,21 @@ async function test() { ...@@ -30,8 +30,21 @@ async function test() {
}); });
// Quota will vary between setups, rather strip it altogether // Quota will vary between setups, rather strip it altogether
var clean = view._quotaRow.innerHTML.replace(/\&nbsp;/g, ' '); var clean = view._quotaRow.innerHTML.replace(/\&nbsp;/g, ' ');
var quotaStripped = clean.replace(/(.*) \d+ .?B([^\d]*)/, '$1 -$2'); var quotaStripped = clean.replace(/(.*) \d+ .?B([^\d]*)/, '$1 --$2');
InspectorTest.addResult(quotaStripped); InspectorTest.addResult(quotaStripped);
InspectorTest.addResult('Usage breakdown:');
for (var i = 0; i < view._pieChartLegend.children.length; i++) {
var typeUsage = ': ';
var children = view._pieChartLegend.children[i].children;
for (var j = 0; j < children.length; j++) {
if (children[j].classList.contains('usage-breakdown-legend-title'))
typeUsage = children[j].textContent + typeUsage;
if (children[j].classList.contains('usage-breakdown-legend-value'))
typeUsage = typeUsage + children[j].textContent;
}
InspectorTest.addResult(typeUsage);
}
} }
UI.viewManager.showView('resources'); UI.viewManager.showView('resources');
......
...@@ -4593,9 +4593,19 @@ ...@@ -4593,9 +4593,19 @@
"websql", "websql",
"service_workers", "service_workers",
"cache_storage", "cache_storage",
"all" "all",
"other"
], ],
"description": "Enum of possible storage types." "description": "Enum of possible storage types."
},
{
"id": "UsageForType",
"type": "object",
"description": "Usage for a storage type.",
"properties": [
{ "name": "storageType", "$ref": "StorageType", "description": "Name of storage type." },
{ "name": "usage", "type": "number", "description": "Storage usage (bytes)." }
]
} }
], ],
"commands": [ "commands": [
...@@ -4614,7 +4624,8 @@ ...@@ -4614,7 +4624,8 @@
], ],
"returns": [ "returns": [
{ "name": "usage", "type": "number", "description": "Storage usage (bytes)." }, { "name": "usage", "type": "number", "description": "Storage usage (bytes)." },
{ "name": "quota", "type": "number", "description": "Storage quota (bytes)." } { "name": "quota", "type": "number", "description": "Storage quota (bytes)." },
{ "name": "usageBreakdown", "type": "array", "items": { "$ref": "UsageForType" }, "description": "Storage usage per type (bytes)." }
], ],
"description": "Returns usage and quota in bytes." "description": "Returns usage and quota in bytes."
} }
......
...@@ -7,6 +7,15 @@ ...@@ -7,6 +7,15 @@
Resources.ClearStorageView = class extends UI.ThrottledWidget { Resources.ClearStorageView = class extends UI.ThrottledWidget {
constructor() { constructor() {
super(true, 1000); super(true, 1000);
this._pieColors = [
'rgba(110, 161, 226, 1)', // blue
'rgba(229, 113, 113, 1)', // red
'rgba(239, 196, 87, 1)', // yellow
'rgba(155, 127, 230, 1)', // purple
'rgba(116, 178, 102, 1)', // green
'rgba(255, 167, 36, 1)', // orange
'rgba(203, 220, 56, 1)', // lime
];
this._reportView = new UI.ReportView(Common.UIString('Clear storage')); this._reportView = new UI.ReportView(Common.UIString('Clear storage'));
this._reportView.registerRequiredCSS('resources/clearStorageView.css'); this._reportView.registerRequiredCSS('resources/clearStorageView.css');
...@@ -27,13 +36,18 @@ Resources.ClearStorageView = class extends UI.ThrottledWidget { ...@@ -27,13 +36,18 @@ Resources.ClearStorageView = class extends UI.ThrottledWidget {
var quota = this._reportView.appendSection(Common.UIString('Usage')); var quota = this._reportView.appendSection(Common.UIString('Usage'));
this._quotaRow = quota.appendRow(); this._quotaRow = quota.appendRow();
this._pieChart = new PerfUI.PieChart(110, Number.bytesToString, true);
this._pieChartLegend = createElementWithClass('div', 'legend');
var usageBreakdownRow = quota.appendRow();
usageBreakdownRow.appendChild(this._pieChart.element);
usageBreakdownRow.appendChild(this._pieChartLegend);
var application = this._reportView.appendSection(Common.UIString('Application')); var application = this._reportView.appendSection(Common.UIString('Application'));
this._appendItem(application, Common.UIString('Unregister service workers'), 'service_workers'); this._appendItem(application, Common.UIString('Unregister service workers'), 'service_workers');
var storage = this._reportView.appendSection(Common.UIString('Storage')); var storage = this._reportView.appendSection(Common.UIString('Storage'));
this._appendItem(storage, Common.UIString('Local and session storage'), 'local_storage'); this._appendItem(storage, Common.UIString('Local and session storage'), 'local_storage');
this._appendItem(storage, Common.UIString('Indexed DB'), 'indexeddb'); this._appendItem(storage, Common.UIString('IndexedDB'), 'indexeddb');
this._appendItem(storage, Common.UIString('Web SQL'), 'websql'); this._appendItem(storage, Common.UIString('Web SQL'), 'websql');
this._appendItem(storage, Common.UIString('Cookies'), 'cookies'); this._appendItem(storage, Common.UIString('Cookies'), 'cookies');
...@@ -176,19 +190,82 @@ Resources.ClearStorageView = class extends UI.ThrottledWidget { ...@@ -176,19 +190,82 @@ Resources.ClearStorageView = class extends UI.ThrottledWidget {
var response = await this._target.storageAgent().invoke_getUsageAndQuota({origin: securityOrigin}); var response = await this._target.storageAgent().invoke_getUsageAndQuota({origin: securityOrigin});
if (response[Protocol.Error]) { if (response[Protocol.Error]) {
this._quotaRow.textContent = ''; this._quotaRow.textContent = '';
this._resetPieChart(0);
return; return;
} }
this._quotaRow.textContent = Common.UIString( this._quotaRow.textContent = Common.UIString(
'%s storage quota used out of %s', Number.bytesToString(response.usage), Number.bytesToString(response.quota)); '%s used out of %s storage quota', Number.bytesToString(response.usage), Number.bytesToString(response.quota));
this._usageUpdatedForTest(response.usage, response.quota); this._resetPieChart(response.usage);
var colorIndex = 0;
for (var usageForType of response.usageBreakdown) {
if (!usageForType.usage)
continue;
if (colorIndex === this._pieColors.length)
colorIndex = 0;
this._appendLegendRow(
this._getStorageTypeName(usageForType.storageType), usageForType.usage, this._pieColors[colorIndex++]);
}
this._usageUpdatedForTest(response.usage, response.quota, response.usageBreakdown);
this.update(); this.update();
} }
_formatPieChartBytes(value) {
return Number.bytesToString(value);
}
/**
* @param {number} total
*/
_resetPieChart(total) {
this._pieChart.setTotal(total);
this._pieChartLegend.removeChildren();
}
/**
* @param {string} title
* @param {number} value
* @param {string} color
*/
_appendLegendRow(title, value, color) {
if (!value)
return;
this._pieChart.addSlice(value, color);
var rowElement = this._pieChartLegend.createChild('div');
rowElement.createChild('span', 'usage-breakdown-legend-value').textContent = Number.bytesToString(value);
rowElement.createChild('span', 'usage-breakdown-legend-swatch').style.backgroundColor = color;
rowElement.createChild('span', 'usage-breakdown-legend-title').textContent = title;
}
/**
* @param {string} type
* @return {string}
*/
_getStorageTypeName(type) {
switch (type) {
case Protocol.Storage.StorageType.File_systems:
return Common.UIString('File System');
case Protocol.Storage.StorageType.Websql:
return Common.UIString('Web SQL');
case Protocol.Storage.StorageType.Appcache:
return Common.UIString('Application Cache');
case Protocol.Storage.StorageType.Indexeddb:
return Common.UIString('IndexedDB');
case Protocol.Storage.StorageType.Cache_storage:
return Common.UIString('Cache Storage');
case Protocol.Storage.StorageType.Service_workers:
return Common.UIString('Service Workers');
default:
return Common.UIString('Other');
}
}
/** /**
* @param {number} usage * @param {number} usage
* @param {number} quota * @param {number} quota
* @param {!Array<!Protocol.Storage.UsageForType>} usageBreakdown
*/ */
_usageUpdatedForTest(usage, quota) { _usageUpdatedForTest(usage, quota, usageBreakdown) {
} }
}; };
...@@ -22,3 +22,23 @@ ...@@ -22,3 +22,23 @@
.report-row:hover .link { .report-row:hover .link {
display: inline; display: inline;
} }
.usage-breakdown-legend-title {
display: inline-block;
}
.usage-breakdown-legend-value {
display: inline-block;
width: 70px;
text-align: right;
}
.usage-breakdown-legend-swatch {
display: inline-block;
width: 11px;
height: 11px;
margin: 0 6px;
position: relative;
top: 1px;
border: 1px solid rgba(0, 0, 0, 0.2);
}
...@@ -23,6 +23,7 @@ ...@@ -23,6 +23,7 @@
"data_grid", "data_grid",
"components", "components",
"object_ui", "object_ui",
"perf_ui",
"mobile_throttling" "mobile_throttling"
], ],
"scripts": [ "scripts": [
......
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