blob: 16b7ca15502c5a502ef3e7a46dafb0ffc20cc51c [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.
#ifndef THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_REQUEST_QUEUE_ITEM_H_
#define THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_REQUEST_QUEUE_ITEM_H_
#include <memory>
#include "base/callback.h"
#include "third_party/blink/renderer/platform/heap/persistent.h"
#include "third_party/blink/renderer/platform/wtf/allocator.h"
#include "third_party/blink/renderer/platform/wtf/vector.h"
namespace blink {
class DOMException;
class IDBKey;
class IDBRequest;
class IDBRequestLoader;
class IDBValue;
class WebIDBCursor;
// Queues up a transaction's IDBRequest results for orderly delivery.
//
// The IndexedDB specification requires that the events corresponding to IDB
// request results fire in the order in which the requests were issued. The
// browser-side backend processes requests in order, but the Blink side may need
// to perform post-processing on the results (e.g. large value unwrapping).
// When a result needs post-processing, this queue captures all results received
// during the post-processing steps. The events for these results may only fire
// after the post-processed result's event is fired.
//
// A queue item holds a Persistent (not garbage-collected) reference to the
// IDBRequest whose result it will deliver. This creates a reference cycle,
// because IDBRequest holds a pointer to its IDBTransaction, and IDBTransaction
// stores all pending IDBRequestQueueItem instances for its requests in a queue
// via non-garbage-collected pointers (std::unique_ptr). To avoid leaks, the
// request-processing code must ensure that IDBTransaction's queue gets drained
// at some point, even if the transaction's ExecutionContext goes away. The
// lifecycle tests in IDBTransactionTest aim to cover this requirement.
//
// Given that the cycle above exists, the closures passed to IDBRequestQueueItem
// can safely store Persistent pointers the IDBRequest or to the IDBTransaction.
class IDBRequestQueueItem {
USING_FAST_MALLOC(IDBRequestQueueItem);
public:
IDBRequestQueueItem(IDBRequest*,
DOMException*,
base::OnceClosure on_result_load_complete);
IDBRequestQueueItem(IDBRequest*,
int64_t,
base::OnceClosure on_result_load_complete);
IDBRequestQueueItem(IDBRequest*, base::OnceClosure on_result_load_complete);
IDBRequestQueueItem(IDBRequest*,
std::unique_ptr<IDBKey>,
base::OnceClosure on_result_load_complete);
IDBRequestQueueItem(IDBRequest*,
std::unique_ptr<IDBValue>,
bool attach_loader,
base::OnceClosure on_load_complete);
IDBRequestQueueItem(IDBRequest*,
Vector<std::unique_ptr<IDBValue>>,
bool attach_loader,
base::OnceClosure on_result_load_complete);
IDBRequestQueueItem(IDBRequest*,
std::unique_ptr<IDBKey>,
std::unique_ptr<IDBKey> primary_key,
std::unique_ptr<IDBValue>,
bool attach_loader,
base::OnceClosure on_result_load_complete);
IDBRequestQueueItem(IDBRequest*,
std::unique_ptr<WebIDBCursor>,
std::unique_ptr<IDBKey>,
std::unique_ptr<IDBKey> primary_key,
std::unique_ptr<IDBValue>,
bool attach_loader,
base::OnceClosure on_result_load_complete);
~IDBRequestQueueItem();
// False if this result still requires post-processing.
inline bool IsReady() { return ready_; }
// The request whose queued result is tracked by this item.
inline IDBRequest* Request() { return request_; }
// Starts post-processing the IDBRequest's result.
//
// This method must be called after the IDBRequestQueueItem is enqueued into
// the appropriate queue, because it is possible for the loading operation to
// complete synchronously, in which case IDBTransaction::OnResultReady() will
// be called with the (presumably) enqueued IDBRequest before this method
// returns.
void StartLoading();
// Stops post-processing the IDBRequest's result.
//
// This method may be called without an associated StartLoading().
void CancelLoading();
// Calls the correct EnqueueResponse overload on the associated request.
//
// This should only be called by the request's IDBTransaction.
void EnqueueResponse();
// Called by the associated IDBRequestLoader when result processing is done.
void OnResultLoadComplete();
// Called by the associated IDBRequestLoader when result processing fails.
void OnResultLoadComplete(DOMException* error);
private:
// The IDBRequest callback that will be called for this result.
enum ResponseType {
kCanceled,
kCursorKeyPrimaryKeyValue,
kError,
kNumber,
kKey,
kKeyPrimaryKeyValue,
kValue,
kValueArray,
kVoid,
};
// The IDBRequest that will receive a callback for this result.
Persistent<IDBRequest> request_;
// The error argument to the IDBRequest callback.
//
// Only used if the mode_ is kError.
Persistent<DOMException> error_;
// The key argument to the IDBRequest callback.
//
// Only used if mode_ is kKeyPrimaryKeyValue.
std::unique_ptr<IDBKey> key_;
// The primary_key argument to the IDBRequest callback.
//
// Only used if mode_ is kKeyPrimaryKeyValue.
std::unique_ptr<IDBKey> primary_key_;
// All the values that will be passed back to the IDBRequest.
Vector<std::unique_ptr<IDBValue>> values_;
// The cursor argument to the IDBRequest callback.
std::unique_ptr<WebIDBCursor> cursor_;
// Performs post-processing on this result.
//
// nullptr for results that do not require post-processing and for results
// whose post-processing has completed.
std::unique_ptr<IDBRequestLoader> loader_;
// Called when result post-processing has completed.
base::OnceClosure on_result_load_complete_;
// The integer value argument to the IDBRequest callback.
int64_t int64_value_;
// Identifies the IDBRequest::EnqueueResponse() overload that will be called.
ResponseType response_type_;
// False if this result still requires post-processing.
bool ready_;
#if DCHECK_IS_ON()
// True if the appropriate EnqueueResponse() method was called in IDBRequest.
//
// If CancelLoading() is called, the ResponseType might be kCanceled. In this
// case, callback_fired_ can be set to true even though no EnqueueResponse()
// call occurs.
bool callback_fired_ = false;
#endif // DCHECK_IS_ON()
};
using IDBRequestQueue = Deque<std::unique_ptr<IDBRequestQueueItem>>;
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_MODULES_INDEXEDDB_IDB_REQUEST_QUEUE_ITEM_H_