Commit 100b2e7e authored by satorux@chromium.org's avatar satorux@chromium.org

Database support for GDataDirectoryService.

* Add methods InitFromDB and SaveToDB to GDataDirectoryService, along with other helper methods to save/load the directory service from level db instead of from a proto file.
* Add a wrapper class GDataDirectoryServiceDB to hold the level db, with methods Create, Save, Read, Truncate, etc. This object lives on the blocking thread.
* Add CreateDBParams to facilitate creation of GDataDirectoryServiceDB on the blocking thread.
* Add GDataDirectoryService::FromProtoString to create a GDataEntry from a string saved in the db.
* Add unit tests for the db methods.
* Move LoadRootFeedParams to gdata_params. Move typedefs before struct definitions.
* Add a timer to measure the time to restore the filesystem from db or proto. For hugefileman, it's 3000 msec for db, and 2500 for proto, with debug code on a z600. Measurements on device TBD.

BUG=127856
TEST=unit tests, manual tests with hugefileman.
TBR=sky@chromium.org

Review URL: https://chromiumcodereview.appspot.com/10800092
Patch from Achuith Bhandarkar <achuith@chromium.org>.

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@150022 0039d316-1c4b-4281-b951-d872f2087c98
parent ebb38be8
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include <utility> #include <utility>
#include "base/bind.h" #include "base/bind.h"
#include "base/command_line.h"
#include "base/file_util.h" #include "base/file_util.h"
#include "base/json/json_file_value_serializer.h" #include "base/json/json_file_value_serializer.h"
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
...@@ -27,6 +28,7 @@ ...@@ -27,6 +28,7 @@
#include "chrome/browser/chromeos/gdata/gdata_util.h" #include "chrome/browser/chromeos/gdata/gdata_util.h"
#include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/chrome_notification_types.h" #include "chrome/common/chrome_notification_types.h"
#include "chrome/common/pref_names.h" #include "chrome/common/pref_names.h"
#include "content/public/browser/browser_thread.h" #include "content/public/browser/browser_thread.h"
...@@ -45,6 +47,8 @@ const FilePath::CharType kAccountMetadataFile[] = ...@@ -45,6 +47,8 @@ const FilePath::CharType kAccountMetadataFile[] =
FILE_PATH_LITERAL("account_metadata.json"); FILE_PATH_LITERAL("account_metadata.json");
const FilePath::CharType kFilesystemProtoFile[] = const FilePath::CharType kFilesystemProtoFile[] =
FILE_PATH_LITERAL("file_system.pb"); FILE_PATH_LITERAL("file_system.pb");
const FilePath::CharType kResourceMetadataDBFile[] =
FILE_PATH_LITERAL("resource_metadata.db");
const char kEmptyFilePath[] = "/dev/null"; const char kEmptyFilePath[] = "/dev/null";
...@@ -78,28 +82,6 @@ SerializationTimetable kSerializeTimetable[] = { ...@@ -78,28 +82,6 @@ SerializationTimetable kSerializeTimetable[] = {
#endif #endif
}; };
// Defines set of parameters sent to callback OnProtoLoaded().
struct LoadRootFeedParams {
LoadRootFeedParams(
FilePath search_file_path,
bool should_load_from_server,
const FindEntryCallback& callback)
: search_file_path(search_file_path),
should_load_from_server(should_load_from_server),
load_error(GDATA_FILE_OK),
callback(callback) {
}
~LoadRootFeedParams() {
}
FilePath search_file_path;
bool should_load_from_server;
std::string proto;
GDataFileError load_error;
base::Time last_modified;
const FindEntryCallback callback;
};
// Returns true if file system is due to be serialized on disk based on it // Returns true if file system is due to be serialized on disk based on it
// |serialized_size| and |last_serialized| timestamp. // |serialized_size| and |last_serialized| timestamp.
bool ShouldSerializeFileSystemNow(size_t serialized_size, bool ShouldSerializeFileSystemNow(size_t serialized_size,
...@@ -273,6 +255,11 @@ void SaveFeedOnBlockingPoolForDebugging( ...@@ -273,6 +255,11 @@ void SaveFeedOnBlockingPoolForDebugging(
} }
} }
bool UseLevelDB() {
return CommandLine::ForCurrentProcess()->HasSwitch(
switches::kUseLevelDBForGData);
}
// Gets the file size of |local_file|. // Gets the file size of |local_file|.
void GetLocalFileSizeOnBlockingPool(const FilePath& local_file, void GetLocalFileSizeOnBlockingPool(const FilePath& local_file,
GDataFileError* error, GDataFileError* error,
...@@ -995,6 +982,9 @@ void GDataWapiFeedLoader::ReloadFromServerIfNeeded( ...@@ -995,6 +982,9 @@ void GDataWapiFeedLoader::ReloadFromServerIfNeeded(
const FindEntryCallback& callback) { const FindEntryCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DVLOG(1) << "ReloadFeedFromServerIfNeeded local_changestamp="
<< local_changestamp << ", initial_origin=" << initial_origin;
// First fetch the latest changestamp to see if there were any new changes // First fetch the latest changestamp to see if there were any new changes
// there at all. // there at all.
documents_service_->GetAccountMetadata( documents_service_->GetAccountMetadata(
...@@ -1162,7 +1152,7 @@ void GDataWapiFeedLoader::OnFeedFromServerLoaded(GetDocumentsParams* params, ...@@ -1162,7 +1152,7 @@ void GDataWapiFeedLoader::OnFeedFromServerLoaded(GetDocumentsParams* params,
} }
// Save file system metadata to disk. // Save file system metadata to disk.
SaveFileSystemAsProto(); SaveFileSystem();
// If we had someone to report this too, then this retrieval was done in a // If we had someone to report this too, then this retrieval was done in a
// context of search... so continue search. // context of search... so continue search.
...@@ -2996,17 +2986,25 @@ void GDataWapiFeedLoader::LoadFromCache( ...@@ -2996,17 +2986,25 @@ void GDataWapiFeedLoader::LoadFromCache(
const FindEntryCallback& callback) { const FindEntryCallback& callback) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
const FilePath path =
cache_->GetCacheDirectoryPath(GDataCache::CACHE_TYPE_META).Append(
kFilesystemProtoFile);
LoadRootFeedParams* params = new LoadRootFeedParams(search_file_path, LoadRootFeedParams* params = new LoadRootFeedParams(search_file_path,
should_load_from_server, should_load_from_server,
callback); callback);
BrowserThread::GetBlockingPool()->PostTaskAndReply(FROM_HERE, FilePath path = cache_->GetCacheDirectoryPath(GDataCache::CACHE_TYPE_META);
base::Bind(&LoadProtoOnBlockingPool, path, params), if (UseLevelDB()) {
base::Bind(&GDataWapiFeedLoader::OnProtoLoaded, path = path.Append(kResourceMetadataDBFile);
weak_ptr_factory_.GetWeakPtr(), directory_service_->InitFromDB(path, blocking_task_runner_,
base::Owned(params))); base::Bind(
&GDataWapiFeedLoader::ContinueWithInitializedDirectoryService,
weak_ptr_factory_.GetWeakPtr(),
base::Owned(params)));
} else {
path = path.Append(kFilesystemProtoFile);
BrowserThread::GetBlockingPool()->PostTaskAndReply(FROM_HERE,
base::Bind(&LoadProtoOnBlockingPool, path, params),
base::Bind(&GDataWapiFeedLoader::OnProtoLoaded,
weak_ptr_factory_.GetWeakPtr(),
base::Owned(params)));
}
} }
void GDataFileSystem::OnDirectoryChanged(const FilePath& directory_path) { void GDataFileSystem::OnDirectoryChanged(const FilePath& directory_path) {
...@@ -3058,7 +3056,6 @@ void GDataWapiFeedLoader::OnProtoLoaded(LoadRootFeedParams* params) { ...@@ -3058,7 +3056,6 @@ void GDataWapiFeedLoader::OnProtoLoaded(LoadRootFeedParams* params) {
if (directory_service_->origin() == FROM_SERVER) if (directory_service_->origin() == FROM_SERVER)
return; return;
int local_changestamp = 0;
// Update directory structure only if everything is OK and we haven't yet // Update directory structure only if everything is OK and we haven't yet
// received the feed from the server yet. // received the feed from the server yet.
if (params->load_error == GDATA_FILE_OK) { if (params->load_error == GDATA_FILE_OK) {
...@@ -3066,16 +3063,27 @@ void GDataWapiFeedLoader::OnProtoLoaded(LoadRootFeedParams* params) { ...@@ -3066,16 +3063,27 @@ void GDataWapiFeedLoader::OnProtoLoaded(LoadRootFeedParams* params) {
if (directory_service_->ParseFromString(params->proto)) { if (directory_service_->ParseFromString(params->proto)) {
directory_service_->set_last_serialized(params->last_modified); directory_service_->set_last_serialized(params->last_modified);
directory_service_->set_serialized_size(params->proto.size()); directory_service_->set_serialized_size(params->proto.size());
local_changestamp = directory_service_->largest_changestamp();
} else { } else {
params->load_error = GDATA_FILE_ERROR_FAILED; params->load_error = GDATA_FILE_ERROR_FAILED;
LOG(WARNING) << "Parse of cached proto file failed"; LOG(WARNING) << "Parse of cached proto file failed";
} }
} }
ContinueWithInitializedDirectoryService(params, params->load_error);
}
void GDataWapiFeedLoader::ContinueWithInitializedDirectoryService(
LoadRootFeedParams* params,
GDataFileError error) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DVLOG(1) << "Time elapsed to load directory service from disk="
<< (base::Time::Now() - params->load_start_time).InMilliseconds()
<< " milliseconds";
FindEntryCallback callback = params->callback; FindEntryCallback callback = params->callback;
// If we got feed content from cache, try search over it. // If we got feed content from cache, try search over it.
if (params->load_error == GDATA_FILE_OK && !callback.is_null()) { if (error == GDATA_FILE_OK && !callback.is_null()) {
// Continue file content search operation if the delegate hasn't terminated // Continue file content search operation if the delegate hasn't terminated
// this search branch already. // this search branch already.
directory_service_->FindEntryByPathAndRunSync(params->search_file_path, directory_service_->FindEntryByPathAndRunSync(params->search_file_path,
...@@ -3103,33 +3111,35 @@ void GDataWapiFeedLoader::OnProtoLoaded(LoadRootFeedParams* params) { ...@@ -3103,33 +3111,35 @@ void GDataWapiFeedLoader::OnProtoLoaded(LoadRootFeedParams* params) {
// |reported| to the original callback, then we just need to refresh the // |reported| to the original callback, then we just need to refresh the
// content without continuing search upon operation completion. // content without continuing search upon operation completion.
ReloadFromServerIfNeeded(initial_origin, ReloadFromServerIfNeeded(initial_origin,
local_changestamp, directory_service_->largest_changestamp(),
params->search_file_path, params->search_file_path,
callback); callback);
} }
void GDataWapiFeedLoader::SaveFileSystemAsProto() { void GDataWapiFeedLoader::SaveFileSystem() {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DVLOG(1) << "SaveFileSystemAsProto";
if (!ShouldSerializeFileSystemNow(directory_service_->serialized_size(), if (!ShouldSerializeFileSystemNow(directory_service_->serialized_size(),
directory_service_->last_serialized())) { directory_service_->last_serialized())) {
return; return;
} }
const FilePath path = if (UseLevelDB()) {
cache_->GetCacheDirectoryPath(GDataCache::CACHE_TYPE_META).Append( directory_service_->SaveToDB();
kFilesystemProtoFile); } else {
scoped_ptr<std::string> serialized_proto(new std::string()); const FilePath path =
directory_service_->SerializeToString(serialized_proto.get()); cache_->GetCacheDirectoryPath(GDataCache::CACHE_TYPE_META).Append(
directory_service_->set_last_serialized(base::Time::Now()); kFilesystemProtoFile);
directory_service_->set_serialized_size(serialized_proto->size()); scoped_ptr<std::string> serialized_proto(new std::string());
PostBlockingPoolSequencedTask( directory_service_->SerializeToString(serialized_proto.get());
FROM_HERE, directory_service_->set_last_serialized(base::Time::Now());
blocking_task_runner_, directory_service_->set_serialized_size(serialized_proto->size());
base::Bind(&SaveProtoOnBlockingPool, path, PostBlockingPoolSequencedTask(
base::Passed(serialized_proto.Pass()))); FROM_HERE,
blocking_task_runner_,
base::Bind(&SaveProtoOnBlockingPool, path,
base::Passed(serialized_proto.Pass())));
}
} }
void GDataFileSystem::OnFilePathUpdated(const FileOperationCallback& callback, void GDataFileSystem::OnFilePathUpdated(const FileOperationCallback& callback,
...@@ -3524,10 +3534,11 @@ void GDataFileSystem::RunAndNotifyInitialLoadFinished( ...@@ -3524,10 +3534,11 @@ void GDataFileSystem::RunAndNotifyInitialLoadFinished(
GDataEntry* entry) { GDataEntry* entry) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
DVLOG(1) << "Initial load finished";
if (!callback.is_null()) if (!callback.is_null())
callback.Run(error, entry); callback.Run(error, entry);
DVLOG(1) << "RunAndNotifyInitialLoadFinished";
// Notify the observers that root directory has been initialized. // Notify the observers that root directory has been initialized.
FOR_EACH_OBSERVER(GDataFileSystemInterface::Observer, observers_, FOR_EACH_OBSERVER(GDataFileSystemInterface::Observer, observers_,
OnInitialLoadFinished()); OnInitialLoadFinished());
......
...@@ -38,10 +38,6 @@ struct GetDocumentsParams; ...@@ -38,10 +38,6 @@ struct GetDocumentsParams;
struct GetDocumentsUiState; struct GetDocumentsUiState;
struct UploadFileInfo; struct UploadFileInfo;
namespace {
struct LoadRootFeedParams;
} // namespace
// Callback run as a response to LoadFromServer. // Callback run as a response to LoadFromServer.
// //
// TODO(satorux): Move this to a new file: crbug.com/138268 // TODO(satorux): Move this to a new file: crbug.com/138268
...@@ -145,6 +141,11 @@ class GDataWapiFeedLoader { ...@@ -145,6 +141,11 @@ class GDataWapiFeedLoader {
// Callback for handling root directory refresh from the cache. // Callback for handling root directory refresh from the cache.
void OnProtoLoaded(LoadRootFeedParams* params); void OnProtoLoaded(LoadRootFeedParams* params);
// Continues handling root directory refresh after the directory service
// is fully loaded.
void ContinueWithInitializedDirectoryService(LoadRootFeedParams* params,
GDataFileError error);
// Helper callback for handling results of metadata retrieval initiated from // Helper callback for handling results of metadata retrieval initiated from
// ReloadFeedFromServerIfNeeded(). This method makes a decision about fetching // ReloadFeedFromServerIfNeeded(). This method makes a decision about fetching
// the content of the root feed during the root directory refresh process. // the content of the root feed during the root directory refresh process.
...@@ -174,13 +175,13 @@ class GDataWapiFeedLoader { ...@@ -174,13 +175,13 @@ class GDataWapiFeedLoader {
GDataErrorCode status, GDataErrorCode status,
scoped_ptr<base::Value> data); scoped_ptr<base::Value> data);
// Save filesystem to disk.
void SaveFileSystem();
// Callback for handling UI updates caused by document fetching. // Callback for handling UI updates caused by document fetching.
void OnNotifyDocumentFeedFetched( void OnNotifyDocumentFeedFetched(
base::WeakPtr<GetDocumentsUiState> ui_state); base::WeakPtr<GetDocumentsUiState> ui_state);
// Save filesystem as proto file.
void SaveFileSystemAsProto();
GDataDirectoryService* directory_service_; // Not owned. GDataDirectoryService* directory_service_; // Not owned.
DocumentsServiceInterface* documents_service_; // Not owned. DocumentsServiceInterface* documents_service_; // Not owned.
DriveWebAppsRegistryInterface* webapps_registry_; // Not owned. DriveWebAppsRegistryInterface* webapps_registry_; // Not owned.
......
...@@ -21,11 +21,17 @@ ...@@ -21,11 +21,17 @@
#include "chrome/browser/profiles/profile_keyed_service.h" #include "chrome/browser/profiles/profile_keyed_service.h"
#include "chrome/browser/profiles/profile_keyed_service_factory.h" #include "chrome/browser/profiles/profile_keyed_service_factory.h"
namespace base {
class SequencedTaskRunner;
}
namespace gdata { namespace gdata {
struct CreateDBParams;
class GDataFile; class GDataFile;
class GDataDirectory; class GDataDirectory;
class GDataDirectoryService; class GDataDirectoryService;
class ResourceMetadataDB;
class GDataEntryProto; class GDataEntryProto;
class GDataDirectoryProto; class GDataDirectoryProto;
...@@ -102,7 +108,7 @@ class GDataEntry { ...@@ -102,7 +108,7 @@ class GDataEntry {
PlatformFileInfoProto* proto); PlatformFileInfoProto* proto);
// Converts to/from proto. Only handles the common part (i.e. does not // Converts to/from proto. Only handles the common part (i.e. does not
// touch |file_specific_info| and |directory_specific_info|. // touch |file_specific_info|).
bool FromProto(const GDataEntryProto& proto) WARN_UNUSED_RESULT; bool FromProto(const GDataEntryProto& proto) WARN_UNUSED_RESULT;
void ToProto(GDataEntryProto* proto) const; void ToProto(GDataEntryProto* proto) const;
...@@ -332,12 +338,17 @@ class GDataDirectory : public GDataEntry { ...@@ -332,12 +338,17 @@ class GDataDirectory : public GDataEntry {
DISALLOW_COPY_AND_ASSIGN(GDataDirectory); DISALLOW_COPY_AND_ASSIGN(GDataDirectory);
}; };
// TODO(achuith,hashimoto,satorux): Move this to a separate file.
// crbug.com/140317.
// Class to handle GDataEntry* lookups, add/remove GDataEntry*. // Class to handle GDataEntry* lookups, add/remove GDataEntry*.
class GDataDirectoryService { class GDataDirectoryService {
public: public:
// Callback for GetEntryByResourceIdAsync. // Callback for GetEntryByResourceIdAsync.
typedef base::Callback<void(GDataEntry* entry)> GetEntryByResourceIdCallback; typedef base::Callback<void(GDataEntry* entry)> GetEntryByResourceIdCallback;
// Map of resource id and serialized GDataEntry.
typedef std::map<std::string, std::string> SerializedMap;
GDataDirectoryService(); GDataDirectoryService();
~GDataDirectoryService(); ~GDataDirectoryService();
...@@ -401,18 +412,45 @@ class GDataDirectoryService { ...@@ -401,18 +412,45 @@ class GDataDirectoryService {
void SerializeToString(std::string* serialized_proto) const; void SerializeToString(std::string* serialized_proto) const;
bool ParseFromString(const std::string& serialized_proto); bool ParseFromString(const std::string& serialized_proto);
// Restores from and saves to database.
void InitFromDB(const FilePath& db_path,
base::SequencedTaskRunner* blocking_task_runner,
const FileOperationCallback& callback);
void SaveToDB();
private: private:
// A map table of file's resource string to its GDataFile* entry. // A map table of file's resource string to its GDataFile* entry.
typedef std::map<std::string, GDataEntry*> ResourceMap; typedef std::map<std::string, GDataEntry*> ResourceMap;
scoped_ptr<GDataDirectory> root_; // Stored in the serialized proto. // Initializes the resource map using serialized_resources fetched from the
// database.
void InitResourceMap(CreateDBParams* create_params,
const FileOperationCallback& callback);
// Clears root_ and the resource map.
void ClearRoot();
// Creates GDataEntry from serialized string.
scoped_ptr<GDataEntry> FromProtoString(
const std::string& serialized_proto);
// Private data members.
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner_;
scoped_ptr<ResourceMetadataDB> directory_service_db_;
ResourceMap resource_map_; ResourceMap resource_map_;
scoped_ptr<GDataDirectory> root_; // Stored in the serialized proto.
base::Time last_serialized_; base::Time last_serialized_;
size_t serialized_size_; size_t serialized_size_;
int largest_changestamp_; // Stored in the serialized proto. int largest_changestamp_; // Stored in the serialized proto.
ContentOrigin origin_; ContentOrigin origin_;
// This should remain the last member so it'll be destroyed first and
// invalidate its weak pointers before other members are destroyed.
base::WeakPtrFactory<GDataDirectoryService> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(GDataDirectoryService); DISALLOW_COPY_AND_ASSIGN(GDataDirectoryService);
}; };
......
...@@ -7,19 +7,179 @@ ...@@ -7,19 +7,179 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include "base/sequenced_task_runner.h"
#include "base/string_number_conversions.h"
#include "base/threading/sequenced_worker_pool.h"
#include "base/message_loop.h" #include "base/message_loop.h"
#include "chrome/browser/chromeos/gdata/gdata.pb.h" #include "chrome/browser/chromeos/gdata/gdata.pb.h"
#include "chrome/browser/chromeos/gdata/gdata_cache.h"
#include "chrome/browser/chromeos/gdata/gdata_test_util.h" #include "chrome/browser/chromeos/gdata/gdata_test_util.h"
#include "chrome/test/base/testing_profile.h"
#include "content/public/test/test_browser_thread.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
namespace gdata { namespace gdata {
namespace { namespace {
// See gdata.proto for the difference between the two URLs. // See gdata.proto for the difference between the two URLs.
const char kResumableEditMediaUrl[] = "http://resumable-edit-media/"; const char kResumableEditMediaUrl[] = "http://resumable-edit-media/";
const char kResumableCreateMediaUrl[] = "http://resumable-create-media/"; const char kResumableCreateMediaUrl[] = "http://resumable-create-media/";
// Add a directory to |parent| and return that directory. The name and
// resource_id are determined by the incrementing counter |sequence_id|.
GDataDirectory* AddDirectory(GDataDirectory* parent,
GDataDirectoryService* directory_service,
int sequence_id) {
GDataDirectory* dir = new GDataDirectory(parent, directory_service);
const std::string dir_name = "dir" + base::IntToString(sequence_id);
const std::string resource_id = std::string("dir_resource_id:") +
dir_name;
dir->set_title(dir_name);
dir->set_resource_id(resource_id);
GDataFileError error = GDATA_FILE_ERROR_FAILED;
directory_service->AddEntryToDirectory(
parent->GetFilePath(),
dir,
base::Bind(&test_util::CopyErrorCodeFromFileOperationCallback, &error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(GDATA_FILE_OK, error);
return dir;
}
// Add a file to |parent| and return that file. The name and
// resource_id are determined by the incrementing counter |sequence_id|.
GDataFile* AddFile(GDataDirectory* parent,
GDataDirectoryService* directory_service,
int sequence_id) {
GDataFile* file = new GDataFile(parent, directory_service);
const std::string title = "file" + base::IntToString(sequence_id);
const std::string resource_id = std::string("file_resource_id:") +
title;
file->set_title(title);
file->set_resource_id(resource_id);
file->set_file_md5(std::string("file_md5:") + title);
GDataFileError error = GDATA_FILE_ERROR_FAILED;
directory_service->AddEntryToDirectory(
parent->GetFilePath(),
file,
base::Bind(&test_util::CopyErrorCodeFromFileOperationCallback, &error));
test_util::RunBlockingPoolTask();
EXPECT_EQ(GDATA_FILE_OK, error);
return file;
}
// Creates the following files/directories
// drive/dir1/
// drive/dir2/
// drive/dir1/dir3/
// drive/dir1/file4
// drive/dir1/file5
// drive/dir2/file6
// drive/dir2/file7
// drive/dir2/file8
// drive/dir1/dir3/file9
// drive/dir1/dir3/file10
void InitDirectoryService(GDataDirectoryService* directory_service) {
int sequence_id = 1;
GDataDirectory* dir1 = AddDirectory(directory_service->root(),
directory_service, sequence_id++);
GDataDirectory* dir2 = AddDirectory(directory_service->root(),
directory_service, sequence_id++);
GDataDirectory* dir3 = AddDirectory(dir1, directory_service, sequence_id++);
AddFile(dir1, directory_service, sequence_id++);
AddFile(dir1, directory_service, sequence_id++);
AddFile(dir2, directory_service, sequence_id++);
AddFile(dir2, directory_service, sequence_id++);
AddFile(dir2, directory_service, sequence_id++);
AddFile(dir3, directory_service, sequence_id++);
AddFile(dir3, directory_service, sequence_id++);
}
// Find directory by path.
GDataDirectory* FindDirectory(GDataDirectoryService* directory_service,
const char* path) {
return directory_service->FindEntryByPathSync(
FilePath(path))->AsGDataDirectory();
}
// Find file by path.
GDataFile* FindFile(GDataDirectoryService* directory_service,
const char* path) {
return directory_service->FindEntryByPathSync(FilePath(path))->AsGDataFile();
}
// Verify that the recreated directory service matches what we created in
// InitDirectoryService.
void VerifyDirectoryService(GDataDirectoryService* directory_service) {
ASSERT_TRUE(directory_service->root());
GDataDirectory* dir1 = FindDirectory(directory_service, "drive/dir1");
ASSERT_TRUE(dir1);
GDataDirectory* dir2 = FindDirectory(directory_service, "drive/dir2");
ASSERT_TRUE(dir2);
GDataDirectory* dir3 = FindDirectory(directory_service, "drive/dir1/dir3");
ASSERT_TRUE(dir3);
GDataFile* file4 = FindFile(directory_service, "drive/dir1/file4");
ASSERT_TRUE(file4);
EXPECT_EQ(file4->parent(), dir1);
GDataFile* file5 = FindFile(directory_service, "drive/dir1/file5");
ASSERT_TRUE(file5);
EXPECT_EQ(file5->parent(), dir1);
GDataFile* file6 = FindFile(directory_service, "drive/dir2/file6");
ASSERT_TRUE(file6);
EXPECT_EQ(file6->parent(), dir2);
GDataFile* file7 = FindFile(directory_service, "drive/dir2/file7");
ASSERT_TRUE(file7);
EXPECT_EQ(file7->parent(), dir2);
GDataFile* file8 = FindFile(directory_service, "drive/dir2/file8");
ASSERT_TRUE(file8);
EXPECT_EQ(file8->parent(), dir2);
GDataFile* file9 = FindFile(directory_service, "drive/dir1/dir3/file9");
ASSERT_TRUE(file9);
EXPECT_EQ(file9->parent(), dir3);
GDataFile* file10 = FindFile(directory_service, "drive/dir1/dir3/file10");
ASSERT_TRUE(file10);
EXPECT_EQ(file10->parent(), dir3);
EXPECT_EQ(dir1, directory_service->GetEntryByResourceId(
"dir_resource_id:dir1"));
EXPECT_EQ(dir2, directory_service->GetEntryByResourceId(
"dir_resource_id:dir2"));
EXPECT_EQ(dir3, directory_service->GetEntryByResourceId(
"dir_resource_id:dir3"));
EXPECT_EQ(file4, directory_service->GetEntryByResourceId(
"file_resource_id:file4"));
EXPECT_EQ(file5, directory_service->GetEntryByResourceId(
"file_resource_id:file5"));
EXPECT_EQ(file6, directory_service->GetEntryByResourceId(
"file_resource_id:file6"));
EXPECT_EQ(file7, directory_service->GetEntryByResourceId(
"file_resource_id:file7"));
EXPECT_EQ(file8, directory_service->GetEntryByResourceId(
"file_resource_id:file8"));
EXPECT_EQ(file9, directory_service->GetEntryByResourceId(
"file_resource_id:file9"));
EXPECT_EQ(file10, directory_service->GetEntryByResourceId(
"file_resource_id:file10"));
}
// Callback for GDataDirectoryService::InitFromDB.
void InitFromDBCallback(GDataFileError expected_error,
GDataFileError actual_error) {
EXPECT_EQ(expected_error, actual_error);
}
} // namespace } // namespace
TEST(GDataEntryTest, FromProto_DetectBadUploadUrl) { TEST(GDataEntryTest, FromProto_DetectBadUploadUrl) {
...@@ -276,4 +436,38 @@ TEST(GDataRootDirectoryTest, GetEntryByResourceId_RootDirectory) { ...@@ -276,4 +436,38 @@ TEST(GDataRootDirectoryTest, GetEntryByResourceId_RootDirectory) {
EXPECT_EQ(kGDataRootDirectoryResourceId, entry->resource_id()); EXPECT_EQ(kGDataRootDirectoryResourceId, entry->resource_id());
} }
TEST(GDataRootDirectoryTest, DBTest) {
MessageLoopForUI message_loop;
content::TestBrowserThread ui_thread(content::BrowserThread::UI,
&message_loop);
scoped_ptr<TestingProfile> profile(new TestingProfile);
scoped_refptr<base::SequencedWorkerPool> pool =
content::BrowserThread::GetBlockingPool();
scoped_refptr<base::SequencedTaskRunner> blocking_task_runner =
pool->GetSequencedTaskRunner(pool->GetSequenceToken());
GDataDirectoryService directory_service;
FilePath db_path(GDataCache::GetCacheRootPath(profile.get()).
AppendASCII("meta").AppendASCII("resource_metadata.db"));
// InitFromDB should fail with GDATA_FILE_ERROR_NOT_FOUND since the db
// doesn't exist.
directory_service.InitFromDB(db_path, blocking_task_runner,
base::Bind(&InitFromDBCallback, GDATA_FILE_ERROR_NOT_FOUND));
test_util::RunBlockingPoolTask();
InitDirectoryService(&directory_service);
// Write the filesystem to db.
directory_service.SaveToDB();
test_util::RunBlockingPoolTask();
GDataDirectoryService directory_service2;
// InitFromDB should succeed with GDATA_FILE_OK as the db now exists.
directory_service2.InitFromDB(db_path, blocking_task_runner,
base::Bind(&InitFromDBCallback, GDATA_FILE_OK));
test_util::RunBlockingPoolTask();
VerifyDirectoryService(&directory_service2);
}
} // namespace gdata } // namespace gdata
...@@ -56,4 +56,18 @@ ResumeUploadParams::ResumeUploadParams( ...@@ -56,4 +56,18 @@ ResumeUploadParams::ResumeUploadParams(
ResumeUploadParams::~ResumeUploadParams() { ResumeUploadParams::~ResumeUploadParams() {
} }
LoadRootFeedParams::LoadRootFeedParams(
FilePath search_file_path,
bool should_load_from_server,
const FindEntryCallback& callback)
: search_file_path(search_file_path),
should_load_from_server(should_load_from_server),
load_error(GDATA_FILE_OK),
load_start_time(base::Time::Now()),
callback(callback) {
}
LoadRootFeedParams::~LoadRootFeedParams() {
}
} // namespace gdata } // namespace gdata
...@@ -22,6 +22,50 @@ ...@@ -22,6 +22,50 @@
namespace gdata { namespace gdata {
class GDataEntry; class GDataEntry;
struct ResumeUploadResponse;
// Different callback types for various functionalities in DocumentsService.
// Callback type for authentication related DocumentService calls.
typedef base::Callback<void(GDataErrorCode error,
const std::string& token)> AuthStatusCallback;
// Callback type for DocumentServiceInterface::GetDocuments.
// Note: feed_data argument should be passed using base::Passed(&feed_data), not
// feed_data.Pass().
typedef base::Callback<void(GDataErrorCode error,
scoped_ptr<base::Value> feed_data)> GetDataCallback;
// Callback type for Delete/Move DocumentServiceInterface calls.
typedef base::Callback<void(GDataErrorCode error,
const GURL& document_url)> EntryActionCallback;
// Callback type for DownloadDocument/DownloadFile DocumentServiceInterface
// calls.
typedef base::Callback<void(GDataErrorCode error,
const GURL& content_url,
const FilePath& temp_file)> DownloadActionCallback;
// Callback type for getting download data from DownloadFile
// DocumentServiceInterface calls.
typedef base::Callback<void(
GDataErrorCode error,
scoped_ptr<std::string> download_data)> GetDownloadDataCallback;
// Callback type for DocumentServiceInterface::InitiateUpload.
typedef base::Callback<void(GDataErrorCode error,
const GURL& upload_url)> InitiateUploadCallback;
// Callback type for DocumentServiceInterface::ResumeUpload.
typedef base::Callback<void(
const ResumeUploadResponse& response,
scoped_ptr<gdata::DocumentEntry> new_entry)> ResumeUploadCallback;
// Callback type used to get result of file search.
// If |error| is not PLATFORM_FILE_OK, |entry| is set to NULL.
typedef base::Callback<void(GDataFileError error, GDataEntry* entry)>
FindEntryCallback;
// Struct for response to ResumeUpload. // Struct for response to ResumeUpload.
struct ResumeUploadResponse { struct ResumeUploadResponse {
...@@ -88,47 +132,23 @@ struct InitiateUploadParams { ...@@ -88,47 +132,23 @@ struct InitiateUploadParams {
const FilePath& virtual_path; const FilePath& virtual_path;
}; };
// Different callback types for various functionalities in DocumentsService. // Defines set of parameters sent to callback OnProtoLoaded().
struct LoadRootFeedParams {
// Callback type for authentication related DocumentService calls. LoadRootFeedParams(
typedef base::Callback<void(GDataErrorCode error, FilePath search_file_path,
const std::string& token)> AuthStatusCallback; bool should_load_from_server,
const FindEntryCallback& callback);
// Callback type for DocumentServiceInterface::GetDocuments. ~LoadRootFeedParams();
// Note: feed_data argument should be passed using base::Passed(&feed_data), not
// feed_data.Pass(). FilePath search_file_path;
typedef base::Callback<void(GDataErrorCode error, bool should_load_from_server;
scoped_ptr<base::Value> feed_data)> GetDataCallback; std::string proto;
GDataFileError load_error;
// Callback type for Delete/Move DocumentServiceInterface calls. base::Time last_modified;
typedef base::Callback<void(GDataErrorCode error, // Time when filesystem began to be loaded from disk.
const GURL& document_url)> EntryActionCallback; base::Time load_start_time;
const FindEntryCallback callback;
// Callback type for DownloadDocument/DownloadFile DocumentServiceInterface };
// calls.
typedef base::Callback<void(GDataErrorCode error,
const GURL& content_url,
const FilePath& temp_file)> DownloadActionCallback;
// Callback type for getting download data from DownloadFile
// DocumentServiceInterface calls.
typedef base::Callback<void(
GDataErrorCode error,
scoped_ptr<std::string> download_data)> GetDownloadDataCallback;
// Callback type for DocumentServiceInterface::InitiateUpload.
typedef base::Callback<void(GDataErrorCode error,
const GURL& upload_url)> InitiateUploadCallback;
// Callback type for DocumentServiceInterface::ResumeUpload.
typedef base::Callback<void(
const ResumeUploadResponse& response,
scoped_ptr<gdata::DocumentEntry> new_entry)> ResumeUploadCallback;
// Callback type used to get result of file search.
// If |error| is not PLATFORM_FILE_OK, |entry| is set to NULL.
typedef base::Callback<void(GDataFileError error, GDataEntry* entry)>
FindEntryCallback;
} // namespace gdata } // namespace gdata
......
...@@ -1369,6 +1369,9 @@ const char kEnableDevicePolicy[] = "enable-device-policy"; ...@@ -1369,6 +1369,9 @@ const char kEnableDevicePolicy[] = "enable-device-policy";
// Enables Drive v2 API instead of Google Documents List API. // Enables Drive v2 API instead of Google Documents List API.
const char kEnableDriveV2Api[] = "enable-drive-v2-api"; const char kEnableDriveV2Api[] = "enable-drive-v2-api";
// Use level db for drive metadata storage.
const char kUseLevelDBForGData[] = "use-leveldb-for-gdata";
// Enables the redirection of viewable document requests to the Google Document // Enables the redirection of viewable document requests to the Google Document
// Viewer. // Viewer.
const char kEnableGView[] = "enable-gview"; const char kEnableGView[] = "enable-gview";
......
...@@ -373,6 +373,7 @@ extern const char kEnableTouchpadThreeFingerClick[]; ...@@ -373,6 +373,7 @@ extern const char kEnableTouchpadThreeFingerClick[];
extern const char kSkipOAuthLogin[]; extern const char kSkipOAuthLogin[];
extern const char kEnableDevicePolicy[]; extern const char kEnableDevicePolicy[];
extern const char kEnableDriveV2Api[]; extern const char kEnableDriveV2Api[];
extern const char kUseLevelDBForGData[];
extern const char kEnableGView[]; extern const char kEnableGView[];
extern const char kEnableKioskMode[]; extern const char kEnableKioskMode[];
extern const char kEnableONCPolicy[]; extern const char kEnableONCPolicy[];
......
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