blob: 624acfaf69bee8f77efff418ebd6541a8f59d783 [file] [log] [blame]
// Copyright 2017 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 "modules/indexeddb/IDBRequestQueueItem.h"
#include <memory>
#include <utility>
#include "base/memory/scoped_refptr.h"
#include "core/dom/DOMException.h"
#include "modules/indexeddb/IDBKey.h"
#include "modules/indexeddb/IDBRequest.h"
#include "modules/indexeddb/IDBRequestLoader.h"
#include "modules/indexeddb/IDBValue.h"
#include "public/platform/modules/indexeddb/WebIDBCursor.h"
namespace blink {
IDBRequestQueueItem::IDBRequestQueueItem(
IDBRequest* request,
DOMException* error,
base::OnceClosure on_result_load_complete)
: request_(request),
error_(error),
on_result_load_complete_(std::move(on_result_load_complete)),
response_type_(kError),
ready_(true) {
DCHECK(on_result_load_complete_);
DCHECK_EQ(request->queue_item_, nullptr);
request_->queue_item_ = this;
}
IDBRequestQueueItem::IDBRequestQueueItem(
IDBRequest* request,
int64_t value,
base::OnceClosure on_result_load_complete)
: request_(request),
on_result_load_complete_(std::move(on_result_load_complete)),
int64_value_(value),
response_type_(kNumber),
ready_(true) {
DCHECK(on_result_load_complete_);
DCHECK_EQ(request->queue_item_, nullptr);
request_->queue_item_ = this;
}
IDBRequestQueueItem::IDBRequestQueueItem(
IDBRequest* request,
base::OnceClosure on_result_load_complete)
: request_(request),
on_result_load_complete_(std::move(on_result_load_complete)),
response_type_(kVoid),
ready_(true) {
DCHECK(on_result_load_complete_);
DCHECK_EQ(request->queue_item_, nullptr);
request_->queue_item_ = this;
}
IDBRequestQueueItem::IDBRequestQueueItem(
IDBRequest* request,
std::unique_ptr<IDBKey> key,
base::OnceClosure on_result_load_complete)
: request_(request),
key_(std::move(key)),
on_result_load_complete_(std::move(on_result_load_complete)),
response_type_(kKey),
ready_(true) {
DCHECK(on_result_load_complete_);
DCHECK_EQ(request->queue_item_, nullptr);
request_->queue_item_ = this;
}
IDBRequestQueueItem::IDBRequestQueueItem(
IDBRequest* request,
std::unique_ptr<IDBValue> value,
bool attach_loader,
base::OnceClosure on_result_load_complete)
: request_(request),
on_result_load_complete_(std::move(on_result_load_complete)),
response_type_(kValue),
ready_(!attach_loader) {
DCHECK(on_result_load_complete_);
DCHECK_EQ(request->queue_item_, nullptr);
request_->queue_item_ = this;
values_.push_back(std::move(value));
if (attach_loader)
loader_ = std::make_unique<IDBRequestLoader>(this, values_);
}
IDBRequestQueueItem::IDBRequestQueueItem(
IDBRequest* request,
Vector<std::unique_ptr<IDBValue>> values,
bool attach_loader,
base::OnceClosure on_result_load_complete)
: request_(request),
values_(std::move(values)),
on_result_load_complete_(std::move(on_result_load_complete)),
response_type_(kValueArray),
ready_(!attach_loader) {
DCHECK(on_result_load_complete_);
DCHECK_EQ(request->queue_item_, nullptr);
request_->queue_item_ = this;
if (attach_loader)
loader_ = std::make_unique<IDBRequestLoader>(this, values_);
}
IDBRequestQueueItem::IDBRequestQueueItem(
IDBRequest* request,
std::unique_ptr<IDBKey> key,
std::unique_ptr<IDBKey> primary_key,
std::unique_ptr<IDBValue> value,
bool attach_loader,
base::OnceClosure on_result_load_complete)
: request_(request),
key_(std::move(key)),
primary_key_(std::move(primary_key)),
on_result_load_complete_(std::move(on_result_load_complete)),
response_type_(kKeyPrimaryKeyValue),
ready_(!attach_loader) {
DCHECK(on_result_load_complete_);
DCHECK_EQ(request->queue_item_, nullptr);
request_->queue_item_ = this;
values_.push_back(std::move(value));
if (attach_loader)
loader_ = std::make_unique<IDBRequestLoader>(this, values_);
}
IDBRequestQueueItem::IDBRequestQueueItem(
IDBRequest* request,
std::unique_ptr<WebIDBCursor> cursor,
std::unique_ptr<IDBKey> key,
std::unique_ptr<IDBKey> primary_key,
std::unique_ptr<IDBValue> value,
bool attach_loader,
base::OnceClosure on_result_load_complete)
: request_(request),
key_(std::move(key)),
primary_key_(std::move(primary_key)),
cursor_(std::move(cursor)),
on_result_load_complete_(std::move(on_result_load_complete)),
response_type_(kCursorKeyPrimaryKeyValue),
ready_(!attach_loader) {
DCHECK(on_result_load_complete_);
DCHECK_EQ(request->queue_item_, nullptr);
request_->queue_item_ = this;
values_.push_back(std::move(value));
if (attach_loader)
loader_ = std::make_unique<IDBRequestLoader>(this, values_);
}
IDBRequestQueueItem::~IDBRequestQueueItem() {
#if DCHECK_IS_ON()
DCHECK(ready_);
DCHECK(callback_fired_);
#endif // DCHECK_IS_ON()
}
void IDBRequestQueueItem::OnResultLoadComplete() {
DCHECK(!ready_);
ready_ = true;
DCHECK(on_result_load_complete_);
std::move(on_result_load_complete_).Run();
}
void IDBRequestQueueItem::OnResultLoadComplete(DOMException* error) {
DCHECK(!ready_);
DCHECK(response_type_ != kError);
response_type_ = kError;
error_ = error;
// This is not necessary, but releases non-trivial amounts of memory early.
values_.clear();
OnResultLoadComplete();
}
void IDBRequestQueueItem::StartLoading() {
if (request_->request_aborted_) {
// The backing store can get the result back to the request after it's been
// aborted due to a transaction abort. In this case, we can't rely on
// IDBRequest::Abort() to call CancelLoading().
// Setting loader_ to null here makes sure we don't call Cancel() on a
// IDBRequestLoader that hasn't been Start()ed. The current implementation
// behaves well even if Cancel() is called without Start() being called, but
// this reset makes the IDBRequestLoader lifecycle easier to reason about.
loader_.reset();
CancelLoading();
return;
}
if (loader_) {
DCHECK(!ready_);
loader_->Start();
}
}
void IDBRequestQueueItem::CancelLoading() {
if (ready_)
return;
if (loader_) {
loader_->Cancel();
loader_.reset();
// IDBRequestLoader::Cancel() should not call any of the EnqueueResponse
// variants.
DCHECK(!ready_);
}
// Mark this item as ready so the transaction's result queue can be drained.
response_type_ = kCanceled;
values_.clear();
OnResultLoadComplete();
}
void IDBRequestQueueItem::EnqueueResponse() {
DCHECK(ready_);
#if DCHECK_IS_ON()
DCHECK(!callback_fired_);
callback_fired_ = true;
#endif // DCHECK_IS_ON()
DCHECK_EQ(request_->queue_item_, this);
request_->queue_item_ = nullptr;
switch (response_type_) {
case kCanceled:
DCHECK_EQ(values_.size(), 0U);
break;
case kCursorKeyPrimaryKeyValue:
DCHECK_EQ(values_.size(), 1U);
request_->EnqueueResponse(std::move(cursor_), std::move(key_),
std::move(primary_key_),
std::move(values_.front()));
break;
case kError:
DCHECK(error_);
request_->EnqueueResponse(error_);
break;
case kKeyPrimaryKeyValue:
DCHECK_EQ(values_.size(), 1U);
request_->EnqueueResponse(std::move(key_), std::move(primary_key_),
std::move(values_.front()));
break;
case kKey:
DCHECK_EQ(values_.size(), 0U);
request_->EnqueueResponse(std::move(key_));
break;
case kNumber:
DCHECK_EQ(values_.size(), 0U);
request_->EnqueueResponse(int64_value_);
break;
case kValue:
DCHECK_EQ(values_.size(), 1U);
request_->EnqueueResponse(std::move(values_.front()));
break;
case kValueArray:
request_->EnqueueResponse(std::move(values_));
break;
case kVoid:
DCHECK_EQ(values_.size(), 0U);
request_->EnqueueResponse();
break;
}
}
} // namespace blink