text: // 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 IDBRequestQueueItem_h
  #define IDBRequestQueueItem_h
  
  #include <memory>
  
  #include "platform/heap/Handle.h"
  #include "platform/wtf/Allocator.h"
  #include "platform/wtf/RefPtr.h"
  #include "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*,
                        WTF::Closure on_result_load_complete);
    IDBRequestQueueItem(IDBRequest*,
                        int64_t,
                        WTF::Closure on_result_load_complete);
    IDBRequestQueueItem(IDBRequest*, WTF::Closure on_result_load_complete);
    IDBRequestQueueItem(IDBRequest*,
                        IDBKey*,
                        WTF::Closure on_result_load_complete);
    IDBRequestQueueItem(IDBRequest*,
                        RefPtr<IDBValue>,
                        bool attach_loader,
                        WTF::Closure on_load_complete);
    IDBRequestQueueItem(IDBRequest*,
                        const Vector<RefPtr<IDBValue>>&,
                        bool attach_loader,
                        WTF::Closure on_result_load_complete);
    IDBRequestQueueItem(IDBRequest*,
                        IDBKey*,
                        IDBKey* primary_key,
                        RefPtr<IDBValue>,
                        bool attach_loader,
                        WTF::Closure on_result_load_complete);
    IDBRequestQueueItem(IDBRequest*,
                        std::unique_ptr<WebIDBCursor>,
                        IDBKey*,
                        IDBKey* primary_key,
                        RefPtr<IDBValue>,
                        bool attach_loader,
                        WTF::Closure 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 key argument to the IDBRequest callback.
    //
    // Only used if mode_ is kKeyPrimaryKeyValue.
    Persistent<IDBKey> key_;
  
    // The primary_key argument to the IDBRequest callback.
    //
    // Only used if mode_ is kKeyPrimaryKeyValue.
    Persistent<IDBKey> primary_key_;
  
    // The error argument to the IDBRequest callback.
    //
    // Only used if the mode_ is kError.
    Persistent<DOMException> error_;
  
    // All the values that will be passed back to the IDBRequest.
    Vector<RefPtr<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.
    WTF::Closure 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  // IDBRequestQueueItem_h
  