Skip to content

Commit

Permalink
IndexedDB: Added IDBObjectStore.getAll() implementation.
Browse files Browse the repository at this point in the history
This is the experimental IDBObjectStore.getAll implementation for
retrieving multiple values in a single request as proposed in
https://www.w3.org/2008/webapps/wiki/IndexedDatabaseFeatures

In order to use run Chrome with: --enable-experimental-web-platform-features

BUG=457450

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

Cr-Commit-Position: refs/heads/master@{#329848}
  • Loading branch information
cmumford authored and Commit bot committed May 14, 2015
1 parent 9bea0b5 commit b86405e
Show file tree
Hide file tree
Showing 16 changed files with 347 additions and 11 deletions.
61 changes: 61 additions & 0 deletions content/browser/indexed_db/indexed_db_callbacks.cc
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,22 @@ static void BlobLookupForCursorPrefetch(
new IndexedDBMsg_CallbacksSuccessCursorPrefetch(*params));
}

static void BlobLookupForGetAll(
IndexedDBMsg_CallbacksSuccessArray_Params* params,
scoped_refptr<IndexedDBDispatcherHost> dispatcher_host,
const std::vector<IndexedDBReturnValue>& values) {
DCHECK_CURRENTLY_ON(BrowserThread::IO);
DCHECK_EQ(values.size(), params->values.size());

for (size_t i = 0; i < values.size(); ++i) {
if (!CreateAllBlobs(values[i].blob_info,
&params->values[i].blob_or_file_info, dispatcher_host))
return;
}

dispatcher_host->Send(new IndexedDBMsg_CallbacksSuccessArray(*params));
}

static void FillInBlobData(
const std::vector<IndexedDBBlobInfo>& blob_info,
std::vector<IndexedDBMsg_BlobOrFileInfo>* blob_or_file_info) {
Expand Down Expand Up @@ -504,6 +520,51 @@ void IndexedDBCallbacks::OnSuccess(IndexedDBReturnValue* value) {
dispatcher_host_ = NULL;
}

void IndexedDBCallbacks::OnSuccessArray(
std::vector<IndexedDBReturnValue>* values,
const IndexedDBKeyPath& key_path) {
DCHECK(dispatcher_host_.get());

DCHECK_EQ(kNoTransaction, host_transaction_id_);
DCHECK_EQ(kNoDatabase, ipc_database_id_);
DCHECK_EQ(kNoDatabaseCallbacks, ipc_database_callbacks_id_);
DCHECK_EQ(blink::WebIDBDataLossNone, data_loss_);

scoped_ptr<IndexedDBMsg_CallbacksSuccessArray_Params> params(
new IndexedDBMsg_CallbacksSuccessArray_Params());
params->ipc_thread_id = ipc_thread_id_;
params->ipc_callbacks_id = ipc_callbacks_id_;
params->values.resize(values->size());

bool found_blob_info = false;
for (size_t i = 0; i < values->size(); ++i) {
IndexedDBMsg_ReturnValue& pvalue = params->values[i];
IndexedDBReturnValue& value = (*values)[i];
pvalue.bits.swap(value.bits);
if (!value.blob_info.empty()) {
found_blob_info = true;
FillInBlobData(value.blob_info, &pvalue.blob_or_file_info);
for (const auto& blob_info : value.blob_info) {
if (!blob_info.mark_used_callback().is_null())
blob_info.mark_used_callback().Run();
}
}
pvalue.primary_key = value.primary_key;
pvalue.key_path = key_path;
}

if (found_blob_info) {
BrowserThread::PostTask(
BrowserThread::IO, FROM_HERE,
base::Bind(BlobLookupForGetAll, base::Owned(params.release()),
dispatcher_host_, *values));
} else {
dispatcher_host_->Send(
new IndexedDBMsg_CallbacksSuccessArray(*params.get()));
}
dispatcher_host_ = NULL;
}

void IndexedDBCallbacks::OnSuccess(const IndexedDBKey& value) {
DCHECK(dispatcher_host_.get());

Expand Down
4 changes: 4 additions & 0 deletions content/browser/indexed_db/indexed_db_callbacks.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ class CONTENT_EXPORT IndexedDBCallbacks
// IndexedDBCursor::Advance
virtual void OnSuccess(IndexedDBReturnValue* value);

// IndexedDBDatabase::GetAll
virtual void OnSuccessArray(std::vector<IndexedDBReturnValue>* values,
const IndexedDBKeyPath& key_path);

// IndexedDBDatabase::Put / IndexedDBCursor::Update
virtual void OnSuccess(const IndexedDBKey& key);

Expand Down
1 change: 1 addition & 0 deletions content/browser/indexed_db/indexed_db_cursor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ void IndexedDBCursor::CursorPrefetchIterationOperation(
std::vector<IndexedDBValue> found_values;

saved_cursor_.reset();
// TODO(cmumford): Use IPC::Channel::kMaximumMessageSize
const size_t max_size_estimate = 10 * 1024 * 1024;
size_t size_estimate = 0;
leveldb::Status s;
Expand Down
112 changes: 112 additions & 0 deletions content/browser/indexed_db/indexed_db_database.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include "content/browser/indexed_db/indexed_db_database.h"

#include <math.h>
#include <limits>
#include <set>

#include "base/auto_reset.h"
Expand All @@ -26,6 +27,7 @@
#include "content/browser/indexed_db/indexed_db_tracing.h"
#include "content/browser/indexed_db/indexed_db_transaction.h"
#include "content/browser/indexed_db/indexed_db_value.h"
#include "content/common/indexed_db/indexed_db_constants.h"
#include "content/common/indexed_db/indexed_db_key_path.h"
#include "content/common/indexed_db/indexed_db_key_range.h"
#include "storage/browser/blob/blob_data_handle.h"
Expand Down Expand Up @@ -531,6 +533,24 @@ void IndexedDBDatabase::Abort(int64 transaction_id,
transaction->Abort(error);
}

void IndexedDBDatabase::GetAll(int64 transaction_id,
int64 object_store_id,
scoped_ptr<IndexedDBKeyRange> key_range,
int64 max_count,
scoped_refptr<IndexedDBCallbacks> callbacks) {
IDB_TRACE1("IndexedDBDatabase::GetAll", "txn.id", transaction_id);
IndexedDBTransaction* transaction = GetTransaction(transaction_id);
if (!transaction)
return;

if (!ValidateObjectStoreId(object_store_id))
return;

transaction->ScheduleTask(
base::Bind(&IndexedDBDatabase::GetAllOperation, this, object_store_id,
Passed(&key_range), max_count, callbacks));
}

void IndexedDBDatabase::Get(int64 transaction_id,
int64 object_store_id,
int64 index_id,
Expand Down Expand Up @@ -717,6 +737,98 @@ void IndexedDBDatabase::GetOperation(
callbacks->OnSuccess(&value);
}

void IndexedDBDatabase::GetAllOperation(
int64 object_store_id,
scoped_ptr<IndexedDBKeyRange> key_range,
int64 max_count,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction) {
IDB_TRACE1("IndexedDBDatabase::GetAllOperation", "txn.id", transaction->id());

DCHECK_GE(max_count, 0);
if (!max_count)
max_count = std::numeric_limits<decltype(max_count)>::max();

DCHECK(metadata_.object_stores.find(object_store_id) !=
metadata_.object_stores.end());
const IndexedDBObjectStoreMetadata& object_store_metadata =
metadata_.object_stores[object_store_id];

leveldb::Status s;

scoped_ptr<IndexedDBBackingStore::Cursor> cursor =
backing_store_->OpenObjectStoreCursor(
transaction->BackingStoreTransaction(), id(), object_store_id,
*key_range, blink::WebIDBCursorDirectionNext, &s);

if (!s.ok()) {
DLOG(ERROR) << "Unable to open cursor operation: " << s.ToString();
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error in GetAllOperation");
callbacks->OnError(error);
if (s.IsCorruption()) {
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
}
return;
}

std::vector<IndexedDBReturnValue> found_values;
if (!cursor) {
callbacks->OnSuccessArray(&found_values, object_store_metadata.key_path);
return;
}

bool did_first_seek = false;
bool generated_key = object_store_metadata.auto_increment &&
!object_store_metadata.key_path.IsNull();

size_t response_size = kMaxIDBMessageOverhead;
do {
bool cursor_valid;
if (did_first_seek) {
cursor_valid = cursor->Continue(&s);
} else {
cursor_valid = cursor->FirstSeek(&s);
did_first_seek = true;
}
if (!s.ok()) {
IndexedDBDatabaseError error(blink::WebIDBDatabaseExceptionUnknownError,
"Internal error in GetAllOperation.");
callbacks->OnError(error);

if (s.IsCorruption())
factory_->HandleBackingStoreCorruption(backing_store_->origin_url(),
error);
return;
}

if (!cursor_valid)
break;

IndexedDBReturnValue return_value;
return_value.swap(*cursor->value());

size_t value_estimated_size = return_value.SizeEstimate();

if (generated_key) {
return_value.primary_key = cursor->primary_key();
value_estimated_size += return_value.primary_key.size_estimate();
}

if (response_size + value_estimated_size >
IPC::Channel::kMaximumMessageSize) {
// TODO(cmumford): Reach this limit in more gracefully (crbug.com/478949)
break;
}

found_values.push_back(return_value);
response_size += value_estimated_size;
} while (found_values.size() < static_cast<size_t>(max_count));

callbacks->OnSuccessArray(&found_values, object_store_metadata.key_path);
}

static scoped_ptr<IndexedDBKey> GenerateKey(
IndexedDBBackingStore* backing_store,
IndexedDBTransaction* transaction,
Expand Down
10 changes: 10 additions & 0 deletions content/browser/indexed_db/indexed_db_database.h
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,11 @@ class CONTENT_EXPORT IndexedDBDatabase
scoped_ptr<IndexedDBKeyRange> key_range,
bool key_only,
scoped_refptr<IndexedDBCallbacks> callbacks);
void GetAll(int64 transaction_id,
int64 object_store_id,
scoped_ptr<IndexedDBKeyRange> key_range,
int64 max_count,
scoped_refptr<IndexedDBCallbacks> callbacks);
void Put(int64 transaction_id,
int64 object_store_id,
IndexedDBValue* value,
Expand Down Expand Up @@ -200,6 +205,11 @@ class CONTENT_EXPORT IndexedDBDatabase
indexed_db::CursorType cursor_type,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
void GetAllOperation(int64 object_store_id,
scoped_ptr<IndexedDBKeyRange> key_range,
int64 max_count,
scoped_refptr<IndexedDBCallbacks> callbacks,
IndexedDBTransaction* transaction);
struct PutOperationParams;
void PutOperation(scoped_ptr<PutOperationParams> params,
IndexedDBTransaction* transaction);
Expand Down
18 changes: 18 additions & 0 deletions content/browser/indexed_db/indexed_db_dispatcher_host.cc
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ bool IndexedDBDispatcherHost::DatabaseDispatcherHost::OnMessageReceived(
OnVersionChangeIgnored)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseDestroyed, OnDestroyed)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGet, OnGet)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseGetAll, OnGetAll)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabasePut, OnPutWrapper)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexKeys, OnSetIndexKeys)
IPC_MESSAGE_HANDLER(IndexedDBHostMsg_DatabaseSetIndexesReady,
Expand Down Expand Up @@ -646,6 +647,23 @@ void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGet(
callbacks);
}

void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnGetAll(
const IndexedDBHostMsg_DatabaseGetAll_Params& params) {
DCHECK(
parent_->indexed_db_context_->TaskRunner()->RunsTasksOnCurrentThread());
IndexedDBConnection* connection =
parent_->GetOrTerminateProcess(&map_, params.ipc_database_id);
if (!connection || !connection->IsConnected())
return;

scoped_refptr<IndexedDBCallbacks> callbacks(new IndexedDBCallbacks(
parent_, params.ipc_thread_id, params.ipc_callbacks_id));
connection->database()->GetAll(
parent_->HostTransactionId(params.transaction_id), params.object_store_id,
make_scoped_ptr(new IndexedDBKeyRange(params.key_range)),
params.max_count, callbacks);
}

void IndexedDBDispatcherHost::DatabaseDispatcherHost::OnPutWrapper(
const IndexedDBHostMsg_DatabasePut_Params& params) {
std::vector<storage::BlobDataHandle*> handles;
Expand Down
2 changes: 2 additions & 0 deletions content/browser/indexed_db/indexed_db_dispatcher_host.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct IndexedDBHostMsg_DatabaseCreateObjectStore_Params;
struct IndexedDBHostMsg_DatabaseCreateTransaction_Params;
struct IndexedDBHostMsg_DatabaseDeleteRange_Params;
struct IndexedDBHostMsg_DatabaseGet_Params;
struct IndexedDBHostMsg_DatabaseGetAll_Params;
struct IndexedDBHostMsg_DatabaseOpenCursor_Params;
struct IndexedDBHostMsg_DatabasePut_Params;
struct IndexedDBHostMsg_DatabaseSetIndexKeys_Params;
Expand Down Expand Up @@ -163,6 +164,7 @@ class IndexedDBDispatcherHost : public BrowserMessageFilter {
void OnDestroyed(int32 ipc_database_id);

void OnGet(const IndexedDBHostMsg_DatabaseGet_Params& params);
void OnGetAll(const IndexedDBHostMsg_DatabaseGetAll_Params& params);
// OnPutWrapper starts on the IO thread so that it can grab BlobDataHandles
// before posting to the IDB TaskRunner for the rest of the job.
void OnPutWrapper(const IndexedDBHostMsg_DatabasePut_Params& params);
Expand Down
Loading

0 comments on commit b86405e

Please sign in to comment.