Commit e16a744f authored by kinuko@chromium.org's avatar kinuko@chromium.org

Add 'Dump Database' tab to syncfs-internals (only for v2 for now)

Screenshot: https://drive.google.com/a/google.com/file/d/0B6X0ebzoaRahOEFxVVVrZFMzMnc/view

BUG=none
TEST=manual

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@239200 0039d316-1c4b-4281-b951-d872f2087c98
parent 4e407557
<script src="chrome://syncfs-internals/dump_database.js"></script>
<button id="refresh-database-dump">Refresh</button>
<div id="dump-database-placeholder"></div>
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* Handles DumpDatabase tab for syncfs-internals.
*/
var DumpDatabase = (function() {
'use strict';
var DumpDatabase = {};
/**
* Get the database dump.
*/
function getDatabaseDump() {
chrome.send('getDatabaseDump');
}
/**
* Creates an element named |elementName| containing the content |text|.
* @param {string} elementName Name of the new element to be created.
* @param {string} text Text to be contained in the new element.
* @return {HTMLElement} The newly created HTML element.
*/
function createElementFromText(elementName, text) {
var element = document.createElement(elementName);
element.appendChild(document.createTextNode(text));
return element;
}
/**
* Creates a table by filling |header| and |body|.
* @param {HTMLElement} div The outer container of the table to be renderered.
* @param {HTMLElement} header The table header element to be fillied by
* this function.
* @param {HTMLElement} body The table body element to be filled by this
* function.
* @param {Array} databaseDump List of dictionaries for the database dump.
* The first element must have metadata of the entry.
* The remaining elements must be dictionaries for the database dump,
* which can be iterated using the 'keys' fields given by the first
* element.
*/
function createDatabaseDumpTable(div, header, body, databaseDump) {
var metadata = databaseDump.shift();
div.appendChild(createElementFromText('h3', metadata['title']));
var tr = document.createElement('tr');
for (var i = 0; i < metadata.keys.length; ++i)
tr.appendChild(createElementFromText('td', metadata.keys[i]));
header.appendChild(tr);
for (var i = 0; i < databaseDump.length; i++) {
var entry = databaseDump[i];
var tr = document.createElement('tr');
for (var k = 0; k < metadata.keys.length; ++k)
tr.appendChild(createElementFromText('td', entry[metadata.keys[k]]));
body.appendChild(tr);
}
}
/**
* Handles callback from onGetDatabaseDump.
* @param {Array} databaseDump List of lists for the database dump.
*/
DumpDatabase.onGetDatabaseDump = function(databaseDump) {
var placeholder = $('dump-database-placeholder');
placeholder.innerHTML = '';
for (var i = 0; i < databaseDump.length; ++i) {
var div = document.createElement('div');
var table = document.createElement('table');
var header = document.createElement('thead');
var body = document.createElement('tbody');
createDatabaseDumpTable(div, header, body, databaseDump[i]);
table.appendChild(header);
table.appendChild(body);
div.appendChild(table);
placeholder.appendChild(div);
}
}
function main() {
getDatabaseDump();
$('refresh-database-dump').addEventListener('click', getDatabaseDump);
}
document.addEventListener('DOMContentLoaded', main);
return DumpDatabase;
})();
......@@ -26,6 +26,7 @@ found in the LICENSE file.
<tab>Sync Service</tab>
<tab>Extension Statuses</tab>
<tab>File Metadata</tab>
<tab>Database Dump</tab>
</tabs>
<tabpanels>
<tabpanel>
......@@ -37,6 +38,9 @@ found in the LICENSE file.
<tabpanel>
<include src="file_metadata.html" />
</tabpanel>
<tabpanel>
<include src="dump_database.html" />
</tabpanel>
</tabpanels>
</tabbox>
......
......@@ -13,6 +13,7 @@
<include name="IDR_SYNC_FILE_SYSTEM_INTERNALS_UTILS_JS" file="sync_file_system_internals/utils.js" type="BINDATA" />
<include name="IDR_SYNC_FILE_SYSTEM_INTERNALS_EXTENSION_STATUSES_JS" file="sync_file_system_internals/extension_statuses.js" type="BINDATA" />
<include name="IDR_SYNC_FILE_SYSTEM_INTERNALS_FILE_METADATA_JS" file="sync_file_system_internals/file_metadata.js" type="BINDATA" />
<include name="IDR_SYNC_FILE_SYSTEM_INTERNALS_DUMP_DATABASE_JS" file="sync_file_system_internals/dump_database.js" type="BINDATA" />
<include name="IDR_SYNC_FILE_SYSTEM_INTERNALS_MAIN_HTML" file="sync_file_system_internals/main.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" />
<include name="IDR_SYNC_FILE_SYSTEM_INTERNALS_SYNC_SERVICE_JS" file="sync_file_system_internals/sync_service.js" type="BINDATA" />
</includes>
......
......@@ -756,6 +756,23 @@ bool MetadataDatabase::BuildPathForTracker(int64 tracker_id,
return true;
}
base::FilePath MetadataDatabase::BuildDisplayPathForTracker(
const FileTracker& tracker) const {
base::FilePath path;
if (tracker.active()) {
BuildPathForTracker(tracker.tracker_id(), &path);
return path;
}
BuildPathForTracker(tracker.parent_tracker_id(), &path);
if (tracker.has_synced_details()) {
path = path.Append(
base::FilePath::FromUTF8Unsafe(tracker.synced_details().title()));
} else {
path = path.Append(FILE_PATH_LITERAL("<unknown>"));
}
return path;
}
bool MetadataDatabase::FindNearestActiveAncestor(
const std::string& app_id,
const base::FilePath& full_path,
......@@ -1834,18 +1851,7 @@ scoped_ptr<base::ListValue> MetadataDatabase::DumpFiles(
FileTracker* tracker = tracker_by_id_[tracker_id];
base::DictionaryValue* file = new DictionaryValue;
base::FilePath path;
if (tracker->active()) {
BuildPathForTracker(tracker->tracker_id(), &path);
} else {
BuildPathForTracker(tracker->parent_tracker_id(), &path);
if (tracker->has_synced_details()) {
path = path.Append(
base::FilePath::FromUTF8Unsafe(tracker->synced_details().title()));
} else {
path = path.Append(FILE_PATH_LITERAL("unknown"));
}
}
base::FilePath path = BuildDisplayPathForTracker(*tracker);
file->SetString("path", path.AsUTF8Unsafe());
if (tracker->has_synced_details()) {
file->SetString("title", tracker->synced_details().title());
......@@ -1869,6 +1875,13 @@ scoped_ptr<base::ListValue> MetadataDatabase::DumpFiles(
return files.Pass();
}
scoped_ptr<base::ListValue> MetadataDatabase::DumpDatabase() {
scoped_ptr<base::ListValue> list(new base::ListValue);
list->Append(DumpTrackers().release());
list->Append(DumpMetadata().release());
return list.Pass();
}
bool MetadataDatabase::HasNewerFileMetadata(const std::string& file_id,
int64 change_id) {
FileByID::const_iterator found = file_by_id_.find(file_id);
......@@ -1878,5 +1891,101 @@ bool MetadataDatabase::HasNewerFileMetadata(const std::string& file_id,
return found->second->details().change_id() >= change_id;
}
scoped_ptr<base::ListValue> MetadataDatabase::DumpTrackers() {
scoped_ptr<base::ListValue> trackers(new base::ListValue);
// Append the first element for metadata.
base::DictionaryValue* metadata = new DictionaryValue;
const char *trackerKeys[] = {
"tracker_id", "path", "file_id", "tracker_kind", "app_id",
"active", "dirty", "folder_listing",
"title", "kind", "md5", "etag", "missing", "change_id",
};
std::vector<std::string> key_strings(
trackerKeys, trackerKeys + ARRAYSIZE_UNSAFE(trackerKeys));
base::ListValue* keys = new ListValue;
keys->AppendStrings(key_strings);
metadata->SetString("title", "Trackers");
metadata->Set("keys", keys);
trackers->Append(metadata);
// Append tracker data.
for (TrackerByID::const_iterator itr = tracker_by_id_.begin();
itr != tracker_by_id_.end(); ++itr) {
const FileTracker& tracker = *itr->second;
base::DictionaryValue* dict = new DictionaryValue;
base::FilePath path = BuildDisplayPathForTracker(tracker);
dict->SetString("tracker_id", base::Int64ToString(tracker.tracker_id()));
dict->SetString("path", path.AsUTF8Unsafe());
dict->SetString("file_id", tracker.file_id());
TrackerKind tracker_kind = tracker.tracker_kind();
dict->SetString(
"tracker_kind",
tracker_kind == TRACKER_KIND_APP_ROOT ? "AppRoot" :
tracker_kind == TRACKER_KIND_DISABLED_APP_ROOT ? "Disabled App" :
tracker.tracker_id() == GetSyncRootTrackerID() ? "SyncRoot" :
"Regular");
dict->SetString("app_id", tracker.app_id());
dict->SetString("active", tracker.active() ? "true" : "false");
dict->SetString("dirty", tracker.dirty() ? "true" : "false");
dict->SetString("folder_listing",
tracker.needs_folder_listing() ? "needed" : "no");
if (tracker.has_synced_details()) {
const FileDetails& details = tracker.synced_details();
dict->SetString("title", details.title());
dict->SetString("kind", FileKindToString(details.file_kind()));
dict->SetString("md5", details.md5());
dict->SetString("etag", details.etag());
dict->SetString("missing", details.missing() ? "true" : "false");
dict->SetString("change_id", base::Int64ToString(details.change_id()));
}
trackers->Append(dict);
}
return trackers.Pass();
}
scoped_ptr<base::ListValue> MetadataDatabase::DumpMetadata() {
scoped_ptr<base::ListValue> files(new base::ListValue);
// Append the first element for metadata.
base::DictionaryValue* metadata = new DictionaryValue;
const char *fileKeys[] = {
"file_id", "title", "type", "md5", "etag", "missing",
"change_id", "parents"
};
std::vector<std::string> key_strings(
fileKeys, fileKeys + ARRAYSIZE_UNSAFE(fileKeys));
base::ListValue* keys = new ListValue;
keys->AppendStrings(key_strings);
metadata->SetString("title", "Metadata");
metadata->Set("keys", keys);
files->Append(metadata);
// Append metadata data.
for (FileByID::const_iterator itr = file_by_id_.begin();
itr != file_by_id_.end(); ++itr) {
const FileMetadata& file = *itr->second;
base::DictionaryValue* dict = new DictionaryValue;
dict->SetString("file_id", file.file_id());
if (file.has_details()) {
const FileDetails& details = file.details();
dict->SetString("title", details.title());
dict->SetString("type", FileKindToString(details.file_kind()));
dict->SetString("md5", details.md5());
dict->SetString("etag", details.etag());
dict->SetString("missing", details.missing() ? "true" : "false");
dict->SetString("change_id", base::Int64ToString(details.change_id()));
std::vector<std::string> parents;
for (int i = 0; i < details.parent_folder_ids_size(); ++i)
parents.push_back(details.parent_folder_ids(i));
dict->SetString("parents", JoinString(parents, ","));
}
files->Append(dict);
}
return files.Pass();
}
} // namespace drive_backend
} // namespace sync_file_system
......@@ -134,6 +134,9 @@ class MetadataDatabase {
// Returns all file metadata for the given |app_id|.
scoped_ptr<base::ListValue> DumpFiles(const std::string& app_id);
// Returns all database data.
scoped_ptr<base::ListValue> DumpDatabase();
// TODO(tzik): Move GetLargestKnownChangeID() to private section, and hide its
// handling in the class, instead of letting user do.
//
......@@ -226,6 +229,11 @@ class MetadataDatabase {
// The file path is relative to app-root and have a leading path separator.
bool BuildPathForTracker(int64 tracker_id, base::FilePath* path) const;
// Builds the file path for the given tracker for display purpose.
// This may return a path ending with '<unknown>' if the given tracker does
// not have title information (yet). This may return an empty path.
base::FilePath BuildDisplayPathForTracker(const FileTracker& tracker) const;
// Returns false if no registered app exists associated to |app_id|.
// If |full_path| is active, assigns the tracker of |full_path| to |tracker|.
// Otherwise, assigns the nearest active ancestor to |full_path| to |tracker|.
......@@ -414,6 +422,9 @@ class MetadataDatabase {
bool HasNewerFileMetadata(const std::string& file_id, int64 change_id);
scoped_ptr<base::ListValue> DumpTrackers();
scoped_ptr<base::ListValue> DumpMetadata();
scoped_refptr<base::SequencedTaskRunner> task_runner_;
scoped_ptr<leveldb::DB> db_;
......
......@@ -239,6 +239,12 @@ scoped_ptr<base::ListValue> SyncEngine::DumpFiles(const GURL& origin) {
return metadata_database_->DumpFiles(origin.host());
}
scoped_ptr<base::ListValue> SyncEngine::DumpDatabase() {
if (!metadata_database_)
return scoped_ptr<base::ListValue>();
return metadata_database_->DumpDatabase();
}
void SyncEngine::SetSyncEnabled(bool enabled) {
if (sync_enabled_ == enabled)
return;
......
......@@ -78,6 +78,7 @@ class SyncEngine : public RemoteFileSyncService,
virtual RemoteServiceState GetCurrentState() const OVERRIDE;
virtual void GetOriginStatusMap(OriginStatusMap* status_map) OVERRIDE;
virtual scoped_ptr<base::ListValue> DumpFiles(const GURL& origin) OVERRIDE;
virtual scoped_ptr<base::ListValue> DumpDatabase() OVERRIDE;
virtual void SetSyncEnabled(bool enabled) OVERRIDE;
virtual SyncStatusCode SetConflictResolutionPolicy(
ConflictResolutionPolicy policy) OVERRIDE;
......
......@@ -250,6 +250,11 @@ scoped_ptr<base::ListValue> DriveFileSyncService::DumpFiles(
return metadata_store_->DumpFiles(origin);
}
scoped_ptr<base::ListValue> DriveFileSyncService::DumpDatabase() {
// Not implemented (yet).
return scoped_ptr<base::ListValue>();
}
void DriveFileSyncService::SetSyncEnabled(bool enabled) {
if (sync_enabled_ == enabled)
return;
......
......@@ -111,6 +111,7 @@ class DriveFileSyncService : public RemoteFileSyncService,
virtual RemoteServiceState GetCurrentState() const OVERRIDE;
virtual void GetOriginStatusMap(OriginStatusMap* status_map) OVERRIDE;
virtual scoped_ptr<base::ListValue> DumpFiles(const GURL& origin) OVERRIDE;
virtual scoped_ptr<base::ListValue> DumpDatabase() OVERRIDE;
virtual void SetSyncEnabled(bool enabled) OVERRIDE;
virtual SyncStatusCode SetConflictResolutionPolicy(
ConflictResolutionPolicy policy) OVERRIDE;
......
......@@ -53,6 +53,10 @@ scoped_ptr<base::ListValue> MockRemoteFileSyncService::DumpFiles(
return scoped_ptr<base::ListValue>();
}
scoped_ptr<base::ListValue> MockRemoteFileSyncService::DumpDatabase() {
return scoped_ptr<base::ListValue>();
}
void MockRemoteFileSyncService::SetServiceState(RemoteServiceState state) {
state_ = state;
}
......
......@@ -66,6 +66,7 @@ class MockRemoteFileSyncService : public RemoteFileSyncService {
const DownloadVersionCallback&));
virtual scoped_ptr<base::ListValue> DumpFiles(const GURL& origin) OVERRIDE;
virtual scoped_ptr<base::ListValue> DumpDatabase() OVERRIDE;
void SetServiceState(RemoteServiceState state);
......
......@@ -192,6 +192,9 @@ class RemoteFileSyncService {
// Returns file metadata for |origin|.
virtual scoped_ptr<base::ListValue> DumpFiles(const GURL& origin) = 0;
// Returns the dump of internal database.
virtual scoped_ptr<base::ListValue> DumpDatabase() = 0;
// Enables or disables the background sync.
// Setting this to false should disable the synchronization (and make
// the service state to REMOTE_SERVICE_DISABLED), while setting this to
......
......@@ -324,6 +324,10 @@ void SyncFileSystemService::DumpFiles(const GURL& origin,
AsWeakPtr(), origin, callback));
}
scoped_ptr<base::ListValue> SyncFileSystemService::DumpDatabase() {
return remote_service_->DumpDatabase();
}
void SyncFileSystemService::GetFileSyncStatus(
const FileSystemURL& url, const SyncFileStatusCallback& callback) {
DCHECK(local_service_);
......
......@@ -18,7 +18,6 @@
#include "chrome/browser/sync/profile_sync_service_observer.h"
#include "chrome/browser/sync_file_system/conflict_resolution_policy.h"
#include "chrome/browser/sync_file_system/file_status_observer.h"
#include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
#include "chrome/browser/sync_file_system/remote_file_sync_service.h"
#include "chrome/browser/sync_file_system/sync_callbacks.h"
#include "chrome/browser/sync_file_system/sync_service_state.h"
......@@ -27,6 +26,7 @@
#include "content/public/browser/notification_registrar.h"
#include "url/gurl.h"
class Profile;
class ProfileSyncServiceBase;
namespace fileapi {
......@@ -35,6 +35,7 @@ class FileSystemContext;
namespace sync_file_system {
class LocalFileSyncService;
class LocalSyncRunner;
class RemoteSyncRunner;
class SyncEventObserver;
......@@ -60,6 +61,7 @@ class SyncFileSystemService
SyncServiceState GetSyncServiceState();
void GetExtensionStatusMap(std::map<GURL, std::string>* status_map);
void DumpFiles(const GURL& origin, const DumpFilesCallback& callback);
scoped_ptr<base::ListValue> DumpDatabase();
// Returns the file |url|'s sync status.
void GetFileSyncStatus(
......
......@@ -6,6 +6,7 @@
#include "base/command_line.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync_file_system/local/local_file_sync_service.h"
#include "chrome/browser/sync_file_system/sync_file_system_service.h"
#include "chrome/browser/sync_file_system/syncable_file_system_util.h"
#include "components/browser_context_keyed_service/browser_context_dependency_manager.h"
......
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/sync_file_system_internals/dump_database_handler.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync_file_system/sync_file_system_service.h"
#include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
#include "content/public/browser/web_ui.h"
#include "content/public/browser/web_ui_data_source.h"
using sync_file_system::SyncFileSystemServiceFactory;
namespace syncfs_internals {
DumpDatabaseHandler::DumpDatabaseHandler(Profile* profile)
: profile_(profile) {}
DumpDatabaseHandler::~DumpDatabaseHandler() {}
void DumpDatabaseHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"getDatabaseDump",
base::Bind(&DumpDatabaseHandler::GetDatabaseDump,
base::Unretained(this)));
}
void DumpDatabaseHandler::GetDatabaseDump(const base::ListValue* args) {
scoped_ptr<base::ListValue> list =
SyncFileSystemServiceFactory::GetForProfile(profile_)->DumpDatabase();
web_ui()->CallJavascriptFunction("DumpDatabase.onGetDatabaseDump",
*list.get());
}
} // namespace syncfs_internals
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_SYNC_FILE_SYSTEM_INTERNALS_DUMP_DATABASE_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_SYNC_FILE_SYSTEM_INTERNALS_DUMP_DATABASE_HANDLER_H_
#include "base/compiler_specific.h"
#include "content/public/browser/web_ui_message_handler.h"
class Profile;
namespace syncfs_internals {
class DumpDatabaseHandler : public content::WebUIMessageHandler {
public:
explicit DumpDatabaseHandler(Profile* profile);
virtual ~DumpDatabaseHandler();
// WebUIMessageHandler implementation.
virtual void RegisterMessages() OVERRIDE;
private:
void GetDatabaseDump(const base::ListValue* args);
Profile* profile_;
DISALLOW_COPY_AND_ASSIGN(DumpDatabaseHandler);
};
} // namespace syncfs_internals
#endif // CHROME_BROWSER_UI_WEBUI_SYNC_FILE_SYSTEM_INTERNALS_DUMP_DATABASE_HANDLER_H_
......@@ -5,6 +5,7 @@
#include "chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_ui.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/sync_file_system_internals/dump_database_handler.h"
#include "chrome/browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h"
#include "chrome/browser/ui/webui/sync_file_system_internals/file_metadata_handler.h"
#include "chrome/browser/ui/webui/sync_file_system_internals/sync_file_system_internals_handler.h"
......@@ -31,6 +32,8 @@ content::WebUIDataSource* CreateSyncFileSystemInternalsHTMLSource() {
"file_metadata.js", IDR_SYNC_FILE_SYSTEM_INTERNALS_FILE_METADATA_JS);
source->AddResourcePath(
"sync_service.js", IDR_SYNC_FILE_SYSTEM_INTERNALS_SYNC_SERVICE_JS);
source->AddResourcePath(
"dump_database.js", IDR_SYNC_FILE_SYSTEM_INTERNALS_DUMP_DATABASE_JS);
source->AddResourcePath("file.png", IDR_DEFAULT_FAVICON);
source->AddResourcePath("folder_closed.png", IDR_FOLDER_CLOSED);
source->SetDefaultResource(IDR_SYNC_FILE_SYSTEM_INTERNALS_MAIN_HTML);
......@@ -42,12 +45,14 @@ content::WebUIDataSource* CreateSyncFileSystemInternalsHTMLSource() {
SyncFileSystemInternalsUI::SyncFileSystemInternalsUI(content::WebUI* web_ui)
: WebUIController(web_ui) {
Profile* profile = Profile::FromWebUI(web_ui);
web_ui->AddMessageHandler(
new syncfs_internals::SyncFileSystemInternalsHandler(profile));
web_ui->AddMessageHandler(
new syncfs_internals::ExtensionStatusesHandler(profile));
web_ui->AddMessageHandler(
new syncfs_internals::FileMetadataHandler(profile));
web_ui->AddMessageHandler(
new syncfs_internals::SyncFileSystemInternalsHandler(profile));
new syncfs_internals::DumpDatabaseHandler(profile));
content::WebUIDataSource::Add(profile,
CreateSyncFileSystemInternalsHTMLSource());
}
......
......@@ -2549,6 +2549,8 @@
'browser/ui/webui/suggestions_internals/suggestions_internals_ui.h',
'browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.cc',
'browser/ui/webui/suggestions_internals/suggestions_internals_ui_handler.h',
'browser/ui/webui/sync_file_system_internals/dump_database_handler.cc',
'browser/ui/webui/sync_file_system_internals/dump_database_handler.h',
'browser/ui/webui/sync_file_system_internals/extension_statuses_handler.cc',
'browser/ui/webui/sync_file_system_internals/extension_statuses_handler.h',
'browser/ui/webui/sync_file_system_internals/file_metadata_handler.cc',
......
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