Commit de624f8b authored by ericu@chromium.org's avatar ericu@chromium.org

Add blob-writing functionality [as yet un-called] to IDB's backend.

BUG=108012
R=cmumford@chromium.org, jsbell@chromium.org

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@266916 0039d316-1c4b-4281-b951-d872f2087c98
parent 483d6929
...@@ -6,11 +6,13 @@ ...@@ -6,11 +6,13 @@
#include "base/file_util.h" #include "base/file_util.h"
#include "base/files/file_path.h" #include "base/files/file_path.h"
#include "base/format_macros.h"
#include "base/json/json_reader.h" #include "base/json/json_reader.h"
#include "base/json/json_writer.h" #include "base/json/json_writer.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/metrics/histogram.h" #include "base/metrics/histogram.h"
#include "base/strings/string_util.h" #include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/strings/utf_string_conversions.h" #include "base/strings/utf_string_conversions.h"
#include "content/browser/child_process_security_policy_impl.h" #include "content/browser/child_process_security_policy_impl.h"
#include "content/browser/indexed_db/indexed_db_blob_info.h" #include "content/browser/indexed_db/indexed_db_blob_info.h"
...@@ -26,18 +28,53 @@ ...@@ -26,18 +28,53 @@
#include "content/common/indexed_db/indexed_db_key.h" #include "content/common/indexed_db/indexed_db_key.h"
#include "content/common/indexed_db/indexed_db_key_path.h" #include "content/common/indexed_db/indexed_db_key_path.h"
#include "content/common/indexed_db/indexed_db_key_range.h" #include "content/common/indexed_db/indexed_db_key_range.h"
#include "content/public/browser/browser_thread.h"
#include "net/url_request/url_request_context.h"
#include "third_party/WebKit/public/platform/WebIDBTypes.h" #include "third_party/WebKit/public/platform/WebIDBTypes.h"
#include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h" #include "third_party/WebKit/public/web/WebSerializedScriptValueVersion.h"
#include "third_party/leveldatabase/env_chromium.h" #include "third_party/leveldatabase/env_chromium.h"
#include "webkit/browser/blob/blob_data_handle.h" #include "webkit/browser/blob/blob_data_handle.h"
#include "webkit/browser/fileapi/file_stream_writer.h"
#include "webkit/browser/fileapi/file_writer_delegate.h"
#include "webkit/browser/fileapi/local_file_stream_writer.h"
#include "webkit/common/database/database_identifier.h" #include "webkit/common/database/database_identifier.h"
using base::FilePath;
using base::StringPiece; using base::StringPiece;
using fileapi::FileWriterDelegate;
namespace content { namespace content {
namespace { namespace {
FilePath GetBlobDirectoryName(const FilePath& pathBase, int64 database_id) {
return pathBase.AppendASCII(base::StringPrintf("%" PRIx64, database_id));
}
FilePath GetBlobDirectoryNameForKey(const FilePath& pathBase,
int64 database_id,
int64 key) {
FilePath path = GetBlobDirectoryName(pathBase, database_id);
path = path.AppendASCII(base::StringPrintf(
"%02x", static_cast<int>(key & 0x000000000000ff00) >> 8));
return path;
}
FilePath GetBlobFileNameForKey(const FilePath& pathBase,
int64 database_id,
int64 key) {
FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key);
path = path.AppendASCII(base::StringPrintf("%" PRIx64, key));
return path;
}
bool MakeIDBBlobDirectory(const FilePath& pathBase,
int64 database_id,
int64 key) {
FilePath path = GetBlobDirectoryNameForKey(pathBase, database_id, key);
return base::CreateDirectory(path);
}
static std::string ComputeOriginIdentifier(const GURL& origin_url) { static std::string ComputeOriginIdentifier(const GURL& origin_url) {
return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1"; return webkit_database::GetIdentifierFromOrigin(origin_url) + "@1";
} }
...@@ -441,6 +478,7 @@ IndexedDBBackingStore::IndexedDBBackingStore( ...@@ -441,6 +478,7 @@ IndexedDBBackingStore::IndexedDBBackingStore(
IndexedDBFactory* indexed_db_factory, IndexedDBFactory* indexed_db_factory,
const GURL& origin_url, const GURL& origin_url,
const base::FilePath& blob_path, const base::FilePath& blob_path,
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db, scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator, scoped_ptr<LevelDBComparator> comparator,
base::TaskRunner* task_runner) base::TaskRunner* task_runner)
...@@ -448,6 +486,7 @@ IndexedDBBackingStore::IndexedDBBackingStore( ...@@ -448,6 +486,7 @@ IndexedDBBackingStore::IndexedDBBackingStore(
origin_url_(origin_url), origin_url_(origin_url),
blob_path_(blob_path), blob_path_(blob_path),
origin_identifier_(ComputeOriginIdentifier(origin_url)), origin_identifier_(ComputeOriginIdentifier(origin_url)),
request_context_(request_context),
task_runner_(task_runner), task_runner_(task_runner),
db_(db.Pass()), db_(db.Pass()),
comparator_(comparator.Pass()), comparator_(comparator.Pass()),
...@@ -506,6 +545,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( ...@@ -506,6 +545,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
IndexedDBFactory* indexed_db_factory, IndexedDBFactory* indexed_db_factory,
const GURL& origin_url, const GURL& origin_url,
const base::FilePath& path_base, const base::FilePath& path_base,
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss, blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message, std::string* data_loss_message,
bool* disk_full, bool* disk_full,
...@@ -515,6 +555,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( ...@@ -515,6 +555,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
return IndexedDBBackingStore::Open(indexed_db_factory, return IndexedDBBackingStore::Open(indexed_db_factory,
origin_url, origin_url,
path_base, path_base,
request_context,
data_loss, data_loss,
data_loss_message, data_loss_message,
disk_full, disk_full,
...@@ -655,6 +696,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( ...@@ -655,6 +696,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
IndexedDBFactory* indexed_db_factory, IndexedDBFactory* indexed_db_factory,
const GURL& origin_url, const GURL& origin_url,
const base::FilePath& path_base, const base::FilePath& path_base,
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss, blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message, std::string* data_loss_message,
bool* is_disk_full, bool* is_disk_full,
...@@ -780,6 +822,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open( ...@@ -780,6 +822,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Open(
return Create(indexed_db_factory, return Create(indexed_db_factory,
origin_url, origin_url,
blob_path, blob_path,
request_context,
db.Pass(), db.Pass(),
comparator.Pass(), comparator.Pass(),
task_runner); task_runner);
...@@ -815,6 +858,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory( ...@@ -815,6 +858,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::OpenInMemory(
return Create(NULL /* indexed_db_factory */, return Create(NULL /* indexed_db_factory */,
origin_url, origin_url,
base::FilePath(), base::FilePath(),
NULL /* request_context */,
db.Pass(), db.Pass(),
comparator.Pass(), comparator.Pass(),
task_runner); task_runner);
...@@ -825,15 +869,16 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create( ...@@ -825,15 +869,16 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBBackingStore::Create(
IndexedDBFactory* indexed_db_factory, IndexedDBFactory* indexed_db_factory,
const GURL& origin_url, const GURL& origin_url,
const base::FilePath& blob_path, const base::FilePath& blob_path,
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db, scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator, scoped_ptr<LevelDBComparator> comparator,
base::TaskRunner* task_runner) { base::TaskRunner* task_runner) {
// TODO(jsbell): Handle comparator name changes. // TODO(jsbell): Handle comparator name changes.
scoped_refptr<IndexedDBBackingStore> backing_store( scoped_refptr<IndexedDBBackingStore> backing_store(
new IndexedDBBackingStore(indexed_db_factory, new IndexedDBBackingStore(indexed_db_factory,
origin_url, origin_url,
blob_path, blob_path,
request_context,
db.Pass(), db.Pass(),
comparator.Pass(), comparator.Pass(),
task_runner)); task_runner));
...@@ -1693,6 +1738,204 @@ leveldb::Status IndexedDBBackingStore::KeyExistsInObjectStore( ...@@ -1693,6 +1738,204 @@ leveldb::Status IndexedDBBackingStore::KeyExistsInObjectStore(
return s; return s;
} }
class IndexedDBBackingStore::Transaction::ChainedBlobWriterImpl
: public IndexedDBBackingStore::Transaction::ChainedBlobWriter {
public:
typedef IndexedDBBackingStore::Transaction::WriteDescriptorVec
WriteDescriptorVec;
ChainedBlobWriterImpl(
int64 database_id,
IndexedDBBackingStore* backingStore,
WriteDescriptorVec& blobs,
scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback)
: waiting_for_callback_(false),
database_id_(database_id),
backing_store_(backingStore),
callback_(callback),
aborted_(false) {
blobs_.swap(blobs);
iter_ = blobs_.begin();
WriteNextFile();
}
virtual void set_delegate(scoped_ptr<FileWriterDelegate> delegate) OVERRIDE {
delegate_.reset(delegate.release());
}
virtual void ReportWriteCompletion(bool succeeded,
int64 bytes_written) OVERRIDE {
// TODO(ericu): Check bytes_written against the blob's snapshot value.
DCHECK(waiting_for_callback_);
DCHECK(!succeeded || bytes_written >= 0);
waiting_for_callback_ = false;
if (delegate_.get()) // Only present for Blob, not File.
content::BrowserThread::DeleteSoon(
content::BrowserThread::IO, FROM_HERE, delegate_.release());
if (aborted_) {
self_ref_ = NULL;
return;
}
if (succeeded)
WriteNextFile();
else
callback_->Run(false);
}
virtual void Abort() OVERRIDE {
if (!waiting_for_callback_)
return;
self_ref_ = this;
aborted_ = true;
}
private:
virtual ~ChainedBlobWriterImpl() {}
void WriteNextFile() {
DCHECK(!waiting_for_callback_);
DCHECK(!aborted_);
if (iter_ == blobs_.end()) {
DCHECK(!self_ref_);
callback_->Run(true);
return;
} else {
if (!backing_store_->WriteBlobFile(database_id_, *iter_, this)) {
callback_->Run(false);
return;
}
waiting_for_callback_ = true;
++iter_;
}
}
bool waiting_for_callback_;
scoped_refptr<ChainedBlobWriterImpl> self_ref_;
WriteDescriptorVec blobs_;
WriteDescriptorVec::const_iterator iter_;
int64 database_id_;
IndexedDBBackingStore* backing_store_;
scoped_refptr<IndexedDBBackingStore::BlobWriteCallback> callback_;
scoped_ptr<FileWriterDelegate> delegate_;
bool aborted_;
};
class LocalWriteClosure : public FileWriterDelegate::DelegateWriteCallback,
public base::RefCounted<LocalWriteClosure> {
public:
LocalWriteClosure(IndexedDBBackingStore::Transaction::ChainedBlobWriter*
chained_blob_writer_,
base::TaskRunner* task_runner)
: chained_blob_writer_(chained_blob_writer_),
task_runner_(task_runner),
bytes_written_(-1) {}
void Run(base::File::Error rv,
int64 bytes,
FileWriterDelegate::WriteProgressStatus write_status) {
if (write_status == FileWriterDelegate::SUCCESS_IO_PENDING)
return; // We don't care about progress events.
if (rv == base::File::FILE_OK) {
DCHECK(bytes >= 0);
DCHECK(write_status == FileWriterDelegate::SUCCESS_COMPLETED);
bytes_written_ = bytes;
} else {
DCHECK(write_status == FileWriterDelegate::ERROR_WRITE_STARTED ||
write_status == FileWriterDelegate::ERROR_WRITE_NOT_STARTED);
}
task_runner_->PostTask(
FROM_HERE,
base::Bind(&LocalWriteClosure::callBlobCallbackOnIDBTaskRunner,
this,
write_status == FileWriterDelegate::SUCCESS_COMPLETED));
}
void writeBlobToFileOnIOThread(const FilePath& file_path,
const GURL& blob_url,
net::URLRequestContext* request_context) {
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO));
scoped_ptr<fileapi::FileStreamWriter> writer(
fileapi::FileStreamWriter::CreateForLocalFile(
task_runner_, file_path, 0,
fileapi::FileStreamWriter::CREATE_NEW_FILE));
scoped_ptr<FileWriterDelegate> delegate(
new FileWriterDelegate(writer.Pass()));
DCHECK(blob_url.is_valid());
scoped_ptr<net::URLRequest> blob_request(request_context->CreateRequest(
blob_url, net::DEFAULT_PRIORITY, delegate.get(), NULL));
delegate->Start(blob_request.Pass(),
base::Bind(&LocalWriteClosure::Run, this));
chained_blob_writer_->set_delegate(delegate.Pass());
}
private:
virtual ~LocalWriteClosure() {}
friend class base::RefCounted<LocalWriteClosure>;
void callBlobCallbackOnIDBTaskRunner(bool succeeded) {
DCHECK(task_runner_->RunsTasksOnCurrentThread());
chained_blob_writer_->ReportWriteCompletion(succeeded, bytes_written_);
}
IndexedDBBackingStore::Transaction::ChainedBlobWriter* chained_blob_writer_;
base::TaskRunner* task_runner_;
int64 bytes_written_;
};
bool IndexedDBBackingStore::WriteBlobFile(
int64 database_id,
const Transaction::WriteDescriptor& descriptor,
Transaction::ChainedBlobWriter* chained_blob_writer) {
if (!MakeIDBBlobDirectory(blob_path_, database_id, descriptor.key()))
return false;
FilePath path = GetBlobFileName(database_id, descriptor.key());
if (descriptor.is_file()) {
DCHECK(!descriptor.file_path().empty());
if (!base::CopyFile(descriptor.file_path(), path))
return false;
base::File::Info info;
if (base::GetFileInfo(descriptor.file_path(), &info)) {
// TODO(ericu): Validate the snapshot date here. Expand WriteDescriptor
// to include snapshot date and file size, and check both.
if (!base::TouchFile(path, info.last_accessed, info.last_modified)) {
// TODO(ericu): Complain quietly; timestamp's probably not vital.
}
} else {
// TODO(ericu): Complain quietly; timestamp's probably not vital.
}
task_runner_->PostTask(
FROM_HERE,
base::Bind(&Transaction::ChainedBlobWriter::ReportWriteCompletion,
chained_blob_writer,
true,
info.size));
} else {
DCHECK(descriptor.url().is_valid());
scoped_refptr<LocalWriteClosure> write_closure(
new LocalWriteClosure(chained_blob_writer, task_runner_));
content::BrowserThread::PostTask(
content::BrowserThread::IO,
FROM_HERE,
base::Bind(&LocalWriteClosure::writeBlobToFileOnIOThread,
write_closure.get(),
path,
descriptor.url(),
request_context_));
}
return true;
}
// This assumes a file path of dbId/second-to-LSB-of-counter/counter.
FilePath IndexedDBBackingStore::GetBlobFileName(int64 database_id, int64 key) {
return GetBlobFileNameForKey(blob_path_, database_id, key);
}
static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it, static bool CheckIndexAndMetaDataKey(const LevelDBIterator* it,
const std::string& stop_key, const std::string& stop_key,
int64 index_id, int64 index_id,
...@@ -1809,6 +2052,16 @@ leveldb::Status IndexedDBBackingStore::GetIndexes( ...@@ -1809,6 +2052,16 @@ leveldb::Status IndexedDBBackingStore::GetIndexes(
return s; return s;
} }
bool IndexedDBBackingStore::RemoveBlobFile(int64 database_id, int64 key) {
FilePath fileName = GetBlobFileName(database_id, key);
return base::DeleteFile(fileName, false);
}
bool IndexedDBBackingStore::RemoveBlobDirectory(int64 database_id) {
FilePath dirName = GetBlobDirectoryName(blob_path_, database_id);
return base::DeleteFile(dirName, true);
}
WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId( WARN_UNUSED_RESULT static leveldb::Status SetMaxIndexId(
LevelDBTransaction* transaction, LevelDBTransaction* transaction,
int64 database_id, int64 database_id,
...@@ -2946,9 +3199,59 @@ leveldb::Status IndexedDBBackingStore::Transaction::Commit() { ...@@ -2946,9 +3199,59 @@ leveldb::Status IndexedDBBackingStore::Transaction::Commit() {
return s; return s;
} }
class IndexedDBBackingStore::Transaction::BlobWriteCallbackWrapper
: public IndexedDBBackingStore::BlobWriteCallback {
public:
BlobWriteCallbackWrapper(IndexedDBBackingStore::Transaction* transaction,
scoped_refptr<BlobWriteCallback> callback)
: transaction_(transaction), callback_(callback) {}
virtual void Run(bool succeeded) OVERRIDE {
callback_->Run(succeeded);
transaction_->chained_blob_writer_ = NULL;
}
private:
virtual ~BlobWriteCallbackWrapper() {}
friend class base::RefCounted<IndexedDBBackingStore::BlobWriteCallback>;
IndexedDBBackingStore::Transaction* transaction_;
scoped_refptr<BlobWriteCallback> callback_;
};
void IndexedDBBackingStore::Transaction::WriteNewBlobs(
BlobEntryKeyValuePairVec& new_blob_entries,
WriteDescriptorVec& new_files_to_write,
scoped_refptr<BlobWriteCallback> callback) {
DCHECK_GT(new_files_to_write.size(), 0UL);
DCHECK_GT(database_id_, 0);
BlobEntryKeyValuePairVec::iterator blob_entry_iter;
for (blob_entry_iter = new_blob_entries.begin();
blob_entry_iter != new_blob_entries.end();
++blob_entry_iter) {
// Add the new blob-table entry for each blob to the main transaction, or
// remove any entry that may exist if there's no new one.
if (!blob_entry_iter->second.size())
transaction_->Remove(blob_entry_iter->first.Encode());
else
transaction_->Put(blob_entry_iter->first.Encode(),
&blob_entry_iter->second);
}
// Creating the writer will start it going asynchronously.
chained_blob_writer_ =
new ChainedBlobWriterImpl(database_id_,
backing_store_,
new_files_to_write,
new BlobWriteCallbackWrapper(this, callback));
}
void IndexedDBBackingStore::Transaction::Rollback() { void IndexedDBBackingStore::Transaction::Rollback() {
IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback"); IDB_TRACE("IndexedDBBackingStore::Transaction::Rollback");
DCHECK(transaction_.get()); DCHECK(transaction_.get());
if (chained_blob_writer_) {
chained_blob_writer_->Abort();
chained_blob_writer_ = NULL;
}
transaction_->Rollback(); transaction_->Rollback();
transaction_ = NULL; transaction_ = NULL;
} }
...@@ -3004,4 +3307,14 @@ void IndexedDBBackingStore::Transaction::PutBlobInfo( ...@@ -3004,4 +3307,14 @@ void IndexedDBBackingStore::Transaction::PutBlobInfo(
DCHECK(!handles || !handles->size()); DCHECK(!handles || !handles->size());
} }
IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
const GURL& url,
int64_t key)
: is_file_(false), url_(url), key_(key) {}
IndexedDBBackingStore::Transaction::WriteDescriptor::WriteDescriptor(
const FilePath& file_path,
int64_t key)
: is_file_(true), file_path_(file_path), key_(key) {}
} // namespace content } // namespace content
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include "content/browser/indexed_db/indexed_db.h" #include "content/browser/indexed_db/indexed_db.h"
#include "content/browser/indexed_db/indexed_db_active_blob_registry.h" #include "content/browser/indexed_db/indexed_db_active_blob_registry.h"
#include "content/browser/indexed_db/indexed_db_blob_info.h" #include "content/browser/indexed_db/indexed_db_blob_info.h"
#include "content/browser/indexed_db/indexed_db_leveldb_coding.h"
#include "content/browser/indexed_db/indexed_db_metadata.h" #include "content/browser/indexed_db/indexed_db_metadata.h"
#include "content/browser/indexed_db/leveldb/leveldb_iterator.h" #include "content/browser/indexed_db/leveldb/leveldb_iterator.h"
#include "content/browser/indexed_db/leveldb/leveldb_transaction.h" #include "content/browser/indexed_db/leveldb/leveldb_transaction.h"
...@@ -33,6 +34,14 @@ namespace base { ...@@ -33,6 +34,14 @@ namespace base {
class TaskRunner; class TaskRunner;
} }
namespace fileapi {
class FileWriterDelegate;
}
namespace net {
class URLRequestContext;
}
namespace content { namespace content {
class IndexedDBFactory; class IndexedDBFactory;
...@@ -76,6 +85,7 @@ class CONTENT_EXPORT IndexedDBBackingStore ...@@ -76,6 +85,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
IndexedDBFactory* indexed_db_factory, IndexedDBFactory* indexed_db_factory,
const GURL& origin_url, const GURL& origin_url,
const base::FilePath& path_base, const base::FilePath& path_base,
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss, blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message, std::string* data_loss_message,
bool* disk_full, bool* disk_full,
...@@ -85,6 +95,7 @@ class CONTENT_EXPORT IndexedDBBackingStore ...@@ -85,6 +95,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
IndexedDBFactory* indexed_db_factory, IndexedDBFactory* indexed_db_factory,
const GURL& origin_url, const GURL& origin_url,
const base::FilePath& path_base, const base::FilePath& path_base,
net::URLRequestContext* request_context,
blink::WebIDBDataLoss* data_loss, blink::WebIDBDataLoss* data_loss,
std::string* data_loss_message, std::string* data_loss_message,
bool* disk_full, bool* disk_full,
...@@ -160,6 +171,14 @@ class CONTENT_EXPORT IndexedDBBackingStore ...@@ -160,6 +171,14 @@ class CONTENT_EXPORT IndexedDBBackingStore
DISALLOW_COPY_AND_ASSIGN(RecordIdentifier); DISALLOW_COPY_AND_ASSIGN(RecordIdentifier);
}; };
class BlobWriteCallback : public base::RefCounted<BlobWriteCallback> {
public:
virtual void Run(bool succeeded) = 0;
protected:
virtual ~BlobWriteCallback() {}
friend class base::RefCounted<BlobWriteCallback>;
};
virtual leveldb::Status GetRecord( virtual leveldb::Status GetRecord(
IndexedDBBackingStore::Transaction* transaction, IndexedDBBackingStore::Transaction* transaction,
int64 database_id, int64 database_id,
...@@ -242,6 +261,8 @@ class CONTENT_EXPORT IndexedDBBackingStore ...@@ -242,6 +261,8 @@ class CONTENT_EXPORT IndexedDBBackingStore
// Public for IndexedDBActiveBlobRegistry::ReleaseBlobRef. // Public for IndexedDBActiveBlobRegistry::ReleaseBlobRef.
virtual void ReportBlobUnused(int64 database_id, int64 blob_key); virtual void ReportBlobUnused(int64 database_id, int64 blob_key);
base::FilePath GetBlobFileName(int64 database_id, int64 key);
class Cursor { class Cursor {
public: public:
virtual ~Cursor(); virtual ~Cursor();
...@@ -354,6 +375,53 @@ class CONTENT_EXPORT IndexedDBBackingStore ...@@ -354,6 +375,53 @@ class CONTENT_EXPORT IndexedDBBackingStore
LevelDBTransaction* transaction() { return transaction_; } LevelDBTransaction* transaction() { return transaction_; }
// This holds a BlobEntryKey and the encoded IndexedDBBlobInfo vector stored
// under that key.
typedef std::vector<std::pair<BlobEntryKey, std::string> >
BlobEntryKeyValuePairVec;
class WriteDescriptor {
public:
WriteDescriptor(const GURL& url, int64_t key);
WriteDescriptor(const base::FilePath& path, int64_t key);
bool is_file() const { return is_file_; }
const GURL& url() const {
DCHECK(!is_file_);
return url_;
}
const base::FilePath& file_path() const {
DCHECK(is_file_);
return file_path_;
}
int64_t key() const { return key_; }
private:
bool is_file_;
GURL url_;
base::FilePath file_path_;
int64_t key_;
};
class ChainedBlobWriter : public base::RefCounted<ChainedBlobWriter> {
public:
virtual void set_delegate(
scoped_ptr<fileapi::FileWriterDelegate> delegate) = 0;
// TODO(ericu): Add a reason in the event of failure.
virtual void ReportWriteCompletion(bool succeeded,
int64 bytes_written) = 0;
virtual void Abort() = 0;
protected:
virtual ~ChainedBlobWriter() {}
friend class base::RefCounted<ChainedBlobWriter>;
};
class ChainedBlobWriterImpl;
typedef std::vector<WriteDescriptor> WriteDescriptorVec;
private: private:
class BlobChangeRecord { class BlobChangeRecord {
public: public:
...@@ -371,29 +439,44 @@ class CONTENT_EXPORT IndexedDBBackingStore ...@@ -371,29 +439,44 @@ class CONTENT_EXPORT IndexedDBBackingStore
std::vector<IndexedDBBlobInfo> blob_info_; std::vector<IndexedDBBlobInfo> blob_info_;
ScopedVector<webkit_blob::BlobDataHandle> handles_; ScopedVector<webkit_blob::BlobDataHandle> handles_;
}; };
class BlobWriteCallbackWrapper;
typedef std::map<std::string, BlobChangeRecord*> BlobChangeMap; typedef std::map<std::string, BlobChangeRecord*> BlobChangeMap;
// The callback will be called eventually on success or failure.
void WriteNewBlobs(BlobEntryKeyValuePairVec& new_blob_entries,
WriteDescriptorVec& new_files_to_write,
scoped_refptr<BlobWriteCallback> callback);
IndexedDBBackingStore* backing_store_; IndexedDBBackingStore* backing_store_;
scoped_refptr<LevelDBTransaction> transaction_; scoped_refptr<LevelDBTransaction> transaction_;
BlobChangeMap blob_change_map_; BlobChangeMap blob_change_map_;
int64 database_id_; int64 database_id_;
scoped_refptr<ChainedBlobWriter> chained_blob_writer_;
}; };
protected: protected:
IndexedDBBackingStore(IndexedDBFactory* indexed_db_factory, IndexedDBBackingStore(IndexedDBFactory* indexed_db_factory,
const GURL& origin_url, const GURL& origin_url,
const base::FilePath& blob_path, const base::FilePath& blob_path,
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db, scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator, scoped_ptr<LevelDBComparator> comparator,
base::TaskRunner* task_runner); base::TaskRunner* task_runner);
virtual ~IndexedDBBackingStore(); virtual ~IndexedDBBackingStore();
friend class base::RefCounted<IndexedDBBackingStore>; friend class base::RefCounted<IndexedDBBackingStore>;
virtual bool WriteBlobFile(
int64 database_id,
const Transaction::WriteDescriptor& descriptor,
Transaction::ChainedBlobWriter* chained_blob_writer);
virtual bool RemoveBlobFile(int64 database_id, int64 key);
private: private:
static scoped_refptr<IndexedDBBackingStore> Create( static scoped_refptr<IndexedDBBackingStore> Create(
IndexedDBFactory* indexed_db_factory, IndexedDBFactory* indexed_db_factory,
const GURL& origin_url, const GURL& origin_url,
const base::FilePath& blob_path, const base::FilePath& blob_path,
net::URLRequestContext* request_context,
scoped_ptr<LevelDBDatabase> db, scoped_ptr<LevelDBDatabase> db,
scoped_ptr<LevelDBComparator> comparator, scoped_ptr<LevelDBComparator> comparator,
base::TaskRunner* task_runner); base::TaskRunner* task_runner);
...@@ -414,6 +497,7 @@ class CONTENT_EXPORT IndexedDBBackingStore ...@@ -414,6 +497,7 @@ class CONTENT_EXPORT IndexedDBBackingStore
int64 object_store_id, int64 object_store_id,
IndexedDBObjectStoreMetadata::IndexMap* map) IndexedDBObjectStoreMetadata::IndexMap* map)
WARN_UNUSED_RESULT; WARN_UNUSED_RESULT;
bool RemoveBlobDirectory(int64 database_id);
IndexedDBFactory* indexed_db_factory_; IndexedDBFactory* indexed_db_factory_;
const GURL origin_url_; const GURL origin_url_;
...@@ -426,6 +510,8 @@ class CONTENT_EXPORT IndexedDBBackingStore ...@@ -426,6 +510,8 @@ class CONTENT_EXPORT IndexedDBBackingStore
// this is redundant but necessary for backwards compatibility; the suffix // this is redundant but necessary for backwards compatibility; the suffix
// provides for future flexibility. // provides for future flexibility.
const std::string origin_identifier_; const std::string origin_identifier_;
net::URLRequestContext* request_context_;
base::TaskRunner* task_runner_; base::TaskRunner* task_runner_;
std::set<int> child_process_ids_granted_; std::set<int> child_process_ids_granted_;
......
...@@ -29,6 +29,10 @@ namespace content { ...@@ -29,6 +29,10 @@ namespace content {
class IndexedDBFactory; class IndexedDBFactory;
} }
namespace net {
class URLRequestContext;
}
namespace { namespace {
class BustedLevelDBDatabase : public LevelDBDatabase { class BustedLevelDBDatabase : public LevelDBDatabase {
...@@ -75,6 +79,7 @@ TEST(IndexedDBIOErrorTest, CleanUpTest) { ...@@ -75,6 +79,7 @@ TEST(IndexedDBIOErrorTest, CleanUpTest) {
base::ScopedTempDir temp_directory; base::ScopedTempDir temp_directory;
ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
const base::FilePath path = temp_directory.path(); const base::FilePath path = temp_directory.path();
net::URLRequestContext* request_context = NULL;
MockLevelDBFactory mock_leveldb_factory; MockLevelDBFactory mock_leveldb_factory;
blink::WebIDBDataLoss data_loss = blink::WebIDBDataLoss data_loss =
blink::WebIDBDataLossNone; blink::WebIDBDataLossNone;
...@@ -85,6 +90,7 @@ TEST(IndexedDBIOErrorTest, CleanUpTest) { ...@@ -85,6 +90,7 @@ TEST(IndexedDBIOErrorTest, CleanUpTest) {
IndexedDBBackingStore::Open(factory, IndexedDBBackingStore::Open(factory,
origin, origin,
path, path,
request_context,
&data_loss, &data_loss,
&data_loss_message, &data_loss_message,
&disk_full, &disk_full,
...@@ -128,6 +134,7 @@ class MockErrorLevelDBFactory : public LevelDBFactory { ...@@ -128,6 +134,7 @@ class MockErrorLevelDBFactory : public LevelDBFactory {
TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) { TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
content::IndexedDBFactory* factory = NULL; content::IndexedDBFactory* factory = NULL;
const GURL origin("http://localhost:81"); const GURL origin("http://localhost:81");
net::URLRequestContext* request_context = NULL;
base::ScopedTempDir temp_directory; base::ScopedTempDir temp_directory;
ASSERT_TRUE(temp_directory.CreateUniqueTempDir()); ASSERT_TRUE(temp_directory.CreateUniqueTempDir());
const base::FilePath path = temp_directory.path(); const base::FilePath path = temp_directory.path();
...@@ -142,6 +149,7 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) { ...@@ -142,6 +149,7 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
IndexedDBBackingStore::Open(factory, IndexedDBBackingStore::Open(factory,
origin, origin,
path, path,
request_context,
&data_loss, &data_loss,
&data_loss_reason, &data_loss_reason,
&disk_full, &disk_full,
...@@ -154,6 +162,7 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) { ...@@ -154,6 +162,7 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
IndexedDBBackingStore::Open(factory, IndexedDBBackingStore::Open(factory,
origin, origin,
path, path,
request_context,
&data_loss, &data_loss,
&data_loss_reason, &data_loss_reason,
&disk_full, &disk_full,
...@@ -165,6 +174,7 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) { ...@@ -165,6 +174,7 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
IndexedDBBackingStore::Open(factory, IndexedDBBackingStore::Open(factory,
origin, origin,
path, path,
request_context,
&data_loss, &data_loss,
&data_loss_reason, &data_loss_reason,
&disk_full, &disk_full,
...@@ -177,6 +187,7 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) { ...@@ -177,6 +187,7 @@ TEST(IndexedDBNonRecoverableIOErrorTest, NuancedCleanupTest) {
IndexedDBBackingStore::Open(factory, IndexedDBBackingStore::Open(factory,
origin, origin,
path, path,
request_context,
&data_loss, &data_loss,
&data_loss_reason, &data_loss_reason,
&disk_full, &disk_full,
......
...@@ -340,6 +340,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStore( ...@@ -340,6 +340,7 @@ scoped_refptr<IndexedDBBackingStore> IndexedDBFactory::OpenBackingStore(
backing_store = IndexedDBBackingStore::Open(this, backing_store = IndexedDBBackingStore::Open(this,
origin_url, origin_url,
data_directory, data_directory,
request_context,
data_loss, data_loss,
data_loss_message, data_loss_message,
disk_full, disk_full,
......
...@@ -13,6 +13,7 @@ IndexedDBFakeBackingStore::IndexedDBFakeBackingStore() ...@@ -13,6 +13,7 @@ IndexedDBFakeBackingStore::IndexedDBFakeBackingStore()
: IndexedDBBackingStore(NULL, : IndexedDBBackingStore(NULL,
GURL("http://localhost:81"), GURL("http://localhost:81"),
base::FilePath(), base::FilePath(),
NULL,
scoped_ptr<LevelDBDatabase>(), scoped_ptr<LevelDBDatabase>(),
scoped_ptr<LevelDBComparator>(), scoped_ptr<LevelDBComparator>(),
NULL) {} NULL) {}
...@@ -23,6 +24,7 @@ IndexedDBFakeBackingStore::IndexedDBFakeBackingStore( ...@@ -23,6 +24,7 @@ IndexedDBFakeBackingStore::IndexedDBFakeBackingStore(
: IndexedDBBackingStore(factory, : IndexedDBBackingStore(factory,
GURL("http://localhost:81"), GURL("http://localhost:81"),
base::FilePath(), base::FilePath(),
NULL,
scoped_ptr<LevelDBDatabase>(), scoped_ptr<LevelDBDatabase>(),
scoped_ptr<LevelDBComparator>(), scoped_ptr<LevelDBComparator>(),
task_runner) {} task_runner) {}
......
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