| Index: storage/browser/blob/blob_storage_context.h
 | 
| diff --git a/storage/browser/blob/blob_storage_context.h b/storage/browser/blob/blob_storage_context.h
 | 
| index 8553d0266d2d8b6338a176f4e9d9ce9d7675fa85..c64581e91c7278109256607ecabe763e89761430 100644
 | 
| --- a/storage/browser/blob/blob_storage_context.h
 | 
| +++ b/storage/browser/blob/blob_storage_context.h
 | 
| @@ -19,17 +19,18 @@
 | 
|  #include "base/memory/ref_counted.h"
 | 
|  #include "base/memory/weak_ptr.h"
 | 
|  #include "storage/browser/blob/blob_data_handle.h"
 | 
| +#include "storage/browser/blob/blob_entry.h"
 | 
| +#include "storage/browser/blob/blob_memory_controller.h"
 | 
|  #include "storage/browser/blob/blob_storage_registry.h"
 | 
| -#include "storage/browser/blob/internal_blob_data.h"
 | 
|  #include "storage/browser/storage_browser_export.h"
 | 
|  #include "storage/common/blob_storage/blob_storage_constants.h"
 | 
| -#include "storage/common/data_element.h"
 | 
|  
 | 
|  class GURL;
 | 
|  
 | 
|  namespace base {
 | 
|  class FilePath;
 | 
|  class Time;
 | 
| +class TaskRunner;
 | 
|  }
 | 
|  
 | 
|  namespace content {
 | 
| @@ -38,130 +39,212 @@ class BlobDispatcherHostTest;
 | 
|  }
 | 
|  
 | 
|  namespace storage {
 | 
| -
 | 
|  class BlobDataBuilder;
 | 
| +class BlobDataHandle;
 | 
|  class BlobDataItem;
 | 
|  class BlobDataSnapshot;
 | 
|  class ShareableBlobDataItem;
 | 
|  
 | 
| -// This class handles the logistics of blob Storage within the browser process,
 | 
| -// and maintains a mapping from blob uuid to the data. The class is single
 | 
| -// threaded and should only be used on the IO thread.
 | 
| -// In chromium, there is one instance per profile.
 | 
| -class STORAGE_EXPORT BlobStorageContext
 | 
| -    : public base::SupportsWeakPtr<BlobStorageContext> {
 | 
| +// This class handles the logistics of blob storage within the browser process.
 | 
| +// We are single threaded and should only be used on the IO thread. In Chromium
 | 
| +// there is one instance per profile.
 | 
| +class STORAGE_EXPORT BlobStorageContext {
 | 
|   public:
 | 
| +  using TransportAllowedCallback = BlobEntry::TransportAllowedCallback;
 | 
| +
 | 
| +  // Initializes the context without disk support.
 | 
|    BlobStorageContext();
 | 
|    ~BlobStorageContext();
 | 
|  
 | 
|    std::unique_ptr<BlobDataHandle> GetBlobDataFromUUID(const std::string& uuid);
 | 
|    std::unique_ptr<BlobDataHandle> GetBlobDataFromPublicURL(const GURL& url);
 | 
|  
 | 
| -  // Useful for coining blobs from within the browser process. If the
 | 
| -  // blob cannot be added due to memory consumption, returns NULL.
 | 
| -  // A builder should not be used twice to create blobs, as the internal
 | 
| -  // resources are refcounted instead of copied for memory efficiency.
 | 
| -  // To cleanly use a builder multiple times, please call Clone() on the
 | 
| -  // builder, or even better for memory savings, clear the builder and append
 | 
| -  // the previously constructed blob.
 | 
| +  // Always returns a handle to a blob. Use BlobStatus::GetBlobStatus() and
 | 
| +  // BlobStatus::RunOnConstructionComplete(callback) to determine construction
 | 
| +  // completion and possible errors.
 | 
|    std::unique_ptr<BlobDataHandle> AddFinishedBlob(
 | 
|        const BlobDataBuilder& builder);
 | 
|  
 | 
| -  // Deprecated, use const ref version above.
 | 
| +  // Deprecated, use const ref version above or BuildBlob below.
 | 
|    std::unique_ptr<BlobDataHandle> AddFinishedBlob(
 | 
|        const BlobDataBuilder* builder);
 | 
|  
 | 
| +  std::unique_ptr<BlobDataHandle> AddBrokenBlob(
 | 
| +      const std::string& uuid,
 | 
| +      const std::string& content_type,
 | 
| +      const std::string& content_disposition,
 | 
| +      BlobStatus reason);
 | 
| +
 | 
|    // Useful for coining blob urls from within the browser process.
 | 
|    bool RegisterPublicBlobURL(const GURL& url, const std::string& uuid);
 | 
|    void RevokePublicBlobURL(const GURL& url);
 | 
|  
 | 
| -  size_t memory_usage() const { return memory_usage_; }
 | 
|    size_t blob_count() const { return registry_.blob_count(); }
 | 
| -  size_t memory_available() const {
 | 
| -    return kBlobStorageMaxMemoryUsage - memory_usage_;
 | 
| -  }
 | 
|  
 | 
|    const BlobStorageRegistry& registry() { return registry_; }
 | 
|  
 | 
| - private:
 | 
| -  using BlobRegistryEntry = BlobStorageRegistry::Entry;
 | 
| -  using BlobConstructedCallback = BlobStorageRegistry::BlobConstructedCallback;
 | 
| +  // This builds a blob with the given |input_builder| and returns a handle to
 | 
| +  // the constructed Blob. Blob metadata and data should be accessed through
 | 
| +  // this handle.
 | 
| +  // If there is data present that needs further population then we will call
 | 
| +  // |transport_allowed_callback| when we're ready for the user data to be
 | 
| +  // populated with the PENDING_DATA_POPULATION status. This can happen
 | 
| +  // synchronously or asynchronously. Otherwise |transport_allowed_callback|
 | 
| +  // should be null. In the further population case, the caller must call either
 | 
| +  // NotifyTransportComplete or CancelBuildingBlob after
 | 
| +  // |transport_allowed_callback| is called to signify the data is finished
 | 
| +  // populating or an error occurred (respectively).
 | 
| +  // If the returned handle is broken, then the possible error cases are:
 | 
| +  // * OUT_OF_MEMORY if we don't have enough memory to store the blob,
 | 
| +  // * REFERENCED_BLOB_BROKEN if a referenced blob is broken or we're
 | 
| +  //   referencing ourself.
 | 
| +  std::unique_ptr<BlobDataHandle> BuildBlob(
 | 
| +      const BlobDataBuilder& input_builder,
 | 
| +      const TransportAllowedCallback& transport_allowed_callback);
 | 
| +
 | 
| +  // This breaks a blob that is currently being built by using the BuildBlob
 | 
| +  // method above. Any callbacks waiting on this blob, including the
 | 
| +  // |transport_allowed_callback| callback given to BuildBlob, will be called
 | 
| +  // with this status code.
 | 
| +  void CancelBuildingBlob(const std::string& uuid, BlobStatus code);
 | 
| +
 | 
| +  // After calling BuildBlob above, the caller should call this method to
 | 
| +  // notify the construction system that the unpopulated data in the given blob
 | 
| +  // has been. populated. Caller must have all pending items populated in the
 | 
| +  // original builder |input_builder| given in BuildBlob or we'll check-fail.
 | 
| +  // If there is no pending data in the |input_builder| for the BuildBlob call,
 | 
| +  // then this method doesn't need to be called.
 | 
| +  void NotifyTransportComplete(const std::string& uuid);
 | 
| +
 | 
| +  const BlobMemoryController& memory_controller() { return memory_controller_; }
 | 
| +
 | 
| +  base::WeakPtr<BlobStorageContext> AsWeakPtr() {
 | 
| +    return ptr_factory_.GetWeakPtr();
 | 
| +  }
 | 
| +
 | 
| + protected:
 | 
|    friend class content::BlobDispatcherHost;
 | 
| -  friend class BlobAsyncBuilderHost;
 | 
| -  friend class BlobAsyncBuilderHostTest;
 | 
| +  friend class content::BlobDispatcherHostTest;
 | 
| +  friend class BlobTransportHost;
 | 
| +  friend class BlobTransportHostTest;
 | 
|    friend class BlobDataHandle;
 | 
|    friend class BlobDataHandle::BlobDataHandleShared;
 | 
| -  friend class BlobReaderTest;
 | 
| -  FRIEND_TEST_ALL_PREFIXES(BlobReaderTest, HandleBeforeAsyncCancel);
 | 
| -  FRIEND_TEST_ALL_PREFIXES(BlobReaderTest, ReadFromIncompleteBlob);
 | 
| +  friend class BlobFlattenerTest;
 | 
| +  friend class BlobSliceTest;
 | 
|    friend class BlobStorageContextTest;
 | 
| -  FRIEND_TEST_ALL_PREFIXES(BlobStorageContextTest, IncrementDecrementRef);
 | 
| -  FRIEND_TEST_ALL_PREFIXES(BlobStorageContextTest, OnCancelBuildingBlob);
 | 
| -  FRIEND_TEST_ALL_PREFIXES(BlobStorageContextTest, PublicBlobUrls);
 | 
| -  FRIEND_TEST_ALL_PREFIXES(BlobStorageContextTest,
 | 
| -                           TestUnknownBrokenAndBuildingBlobReference);
 | 
| -  friend class ViewBlobInternalsJob;
 | 
| -
 | 
| -  // CompletePendingBlob or CancelPendingBlob should be called after this.
 | 
| -  void CreatePendingBlob(const std::string& uuid,
 | 
| -                         const std::string& content_type,
 | 
| -                         const std::string& content_disposition);
 | 
| -
 | 
| -  // This includes resolving blob references in the builder. This will run the
 | 
| -  // callbacks given in RunOnConstructionComplete.
 | 
| -  void CompletePendingBlob(const BlobDataBuilder& external_builder);
 | 
| -
 | 
| -  // This will run the callbacks given in RunOnConstructionComplete.
 | 
| -  void CancelPendingBlob(const std::string& uuid,
 | 
| -                         IPCBlobCreationCancelCode reason);
 | 
| +
 | 
| +  // Transforms a BlobDataBuilder into a BlobEntry with no blob references.
 | 
| +  // BlobSlice is used to flatten out these references. Records the total size
 | 
| +  // and items for memory and file quota requests.
 | 
| +  // Exposed in the header file for testing.
 | 
| +  struct STORAGE_EXPORT BlobFlattener {
 | 
| +    BlobFlattener(const BlobDataBuilder& input_builder,
 | 
| +                  BlobEntry* output_blob,
 | 
| +                  BlobStorageRegistry* registry);
 | 
| +    ~BlobFlattener();
 | 
| +
 | 
| +    // This can be:
 | 
| +    // * PENDING_QUOTA if we need memory quota, if we're populated and don't
 | 
| +    // need quota.
 | 
| +    // * PENDING_INTERNALS if we're waiting on dependent blobs or we're done.
 | 
| +    // * INVALID_CONSTRUCTION_ARGUMENTS if we have invalid input.
 | 
| +    // * REFERENCED_BLOB_BROKEN if one of the referenced blobs is broken or we
 | 
| +    //   reference ourself.
 | 
| +    BlobStatus status = BlobStatus::ERR_INVALID_CONSTRUCTION_ARGUMENTS;
 | 
| +
 | 
| +    // This is the total size of the blob, including all memory, files, etc.
 | 
| +    uint64_t total_size = 0;
 | 
| +    // Total memory size of the blob (not including files, etc).
 | 
| +    uint64_t total_memory_size = 0;
 | 
| +
 | 
| +    std::vector<std::pair<std::string, BlobEntry*>> dependent_blobs;
 | 
| +
 | 
| +    uint64_t memory_quota_needed = 0;
 | 
| +    std::vector<scoped_refptr<ShareableBlobDataItem>> pending_memory_items;
 | 
| +
 | 
| +    std::vector<ShareableBlobDataItem*> transport_items;
 | 
| +
 | 
| +    // These record all future copies we'll need to do from referenced blobs.
 | 
| +    // This
 | 
| +    // happens when we do a partial slice from a pending data or file item.
 | 
| +    std::vector<BlobEntry::ItemCopyEntry> copies;
 | 
| +
 | 
| +   private:
 | 
| +    DISALLOW_COPY_AND_ASSIGN(BlobFlattener);
 | 
| +  };
 | 
| +
 | 
| +  // Used when a blob reference has a size and offset. Records the source items
 | 
| +  // and memory we need to copy if either side of slice intersects an item.
 | 
| +  // Exposed in the header file for testing.
 | 
| +  struct STORAGE_EXPORT BlobSlice {
 | 
| +    BlobSlice(const BlobEntry& source,
 | 
| +              uint64_t slice_offset,
 | 
| +              uint64_t slice_size);
 | 
| +    ~BlobSlice();
 | 
| +
 | 
| +    // Size of memory copying from the source blob.
 | 
| +    base::CheckedNumeric<size_t> copying_memory_size = 0;
 | 
| +    // Size of all memory for UMA stats.
 | 
| +    base::CheckedNumeric<size_t> total_memory_size = 0;
 | 
| +
 | 
| +    size_t first_item_slice_offset = 0;
 | 
| +    // Populated if our first slice item is a temporary item that we'll copy to
 | 
| +    // later from this |first_source_item|, at offset |first_item_slice_offset|.
 | 
| +    scoped_refptr<ShareableBlobDataItem> first_source_item;
 | 
| +    // Populated if our last slice item is a temporary item that we'll copy to
 | 
| +    // later from this |last_source_item|.
 | 
| +    scoped_refptr<ShareableBlobDataItem> last_source_item;
 | 
| +
 | 
| +    std::vector<scoped_refptr<ShareableBlobDataItem>> dest_items;
 | 
| +
 | 
| +   private:
 | 
| +    DISALLOW_COPY_AND_ASSIGN(BlobSlice);
 | 
| +  };
 | 
|  
 | 
|    void IncrementBlobRefCount(const std::string& uuid);
 | 
|    void DecrementBlobRefCount(const std::string& uuid);
 | 
|  
 | 
| -  // Methods called by BlobDataHandle:
 | 
|    // This will return an empty snapshot until the blob is complete.
 | 
|    // TODO(dmurph): After we make the snapshot method in BlobHandle private, then
 | 
|    // make this DCHECK on the blob not being complete.
 | 
|    std::unique_ptr<BlobDataSnapshot> CreateSnapshot(const std::string& uuid);
 | 
| -  bool IsBroken(const std::string& uuid) const;
 | 
| -  bool IsBeingBuilt(const std::string& uuid) const;
 | 
| -  // Runs |done| when construction completes, with true if it was successful,
 | 
| -  // and false if there was an error, which is reported in the second argument
 | 
| -  // of the callback.
 | 
| +
 | 
| +  BlobStatus GetBlobStatus(const std::string& uuid) const;
 | 
| +
 | 
| +  // Runs |done| when construction completes with the final status of the blob.
 | 
|    void RunOnConstructionComplete(const std::string& uuid,
 | 
| -                                 const BlobConstructedCallback& done);
 | 
| -
 | 
| -  // Appends the given blob item to the blob builder.  The new blob
 | 
| -  // retains ownership of data_item if applicable, and returns false if there
 | 
| -  // was an error and pouplates the error_code.  We can either have an error of:
 | 
| -  // OUT_OF_MEMORY: We are out of memory to store this blob.
 | 
| -  // REFERENCED_BLOB_BROKEN: One of the referenced blobs is broken.
 | 
| -  bool AppendAllocatedBlobItem(const std::string& target_blob_uuid,
 | 
| -                               scoped_refptr<BlobDataItem> data_item,
 | 
| -                               InternalBlobData::Builder* target_blob_data,
 | 
| -                               IPCBlobCreationCancelCode* error_code);
 | 
| -
 | 
| -  // Allocates a shareable blob data item, with blob references resolved.  If
 | 
| -  // there isn't enough memory, then a nullptr is returned.
 | 
| -  scoped_refptr<ShareableBlobDataItem> AllocateShareableBlobDataItem(
 | 
| -      const std::string& target_blob_uuid,
 | 
| -      scoped_refptr<BlobDataItem> data_item);
 | 
| -
 | 
| -  // Deconstructs the blob and appends it's contents to the target blob.  Items
 | 
| -  // are shared if possible, and copied if the given offset and length
 | 
| -  // have to split an item.
 | 
| -  bool AppendBlob(const std::string& target_blob_uuid,
 | 
| -                  const InternalBlobData& blob,
 | 
| -                  uint64_t offset,
 | 
| -                  uint64_t length,
 | 
| -                  InternalBlobData::Builder* target_blob_data);
 | 
| +                                 const BlobStatusCallback& done_callback);
 | 
|  
 | 
| -  BlobStorageRegistry registry_;
 | 
| +  BlobStorageRegistry* mutable_registry() { return ®istry_; }
 | 
|  
 | 
| -  // Used to keep track of how much memory is being utilized for blob data,
 | 
| -  // we count only the items of TYPE_DATA which are held in memory and not
 | 
| -  // items of TYPE_FILE.
 | 
| -  size_t memory_usage_;
 | 
| +  BlobMemoryController* mutable_memory_controller() {
 | 
| +    return &memory_controller_;
 | 
| +  }
 | 
| +
 | 
| + private:
 | 
| +  std::unique_ptr<BlobDataHandle> CreateHandle(const std::string& uuid,
 | 
| +                                               BlobEntry* entry);
 | 
| +
 | 
| +  void NotifyTransportCompleteInternal(BlobEntry* entry);
 | 
| +
 | 
| +  void CancelBuildingBlobInternal(BlobEntry* entry, BlobStatus reason);
 | 
| +
 | 
| +  void FinishBuilding(BlobEntry* entry);
 | 
| +
 | 
| +  void RequestTransport(
 | 
| +      BlobEntry* entry,
 | 
| +      std::vector<BlobMemoryController::FileCreationInfo> files);
 | 
| +
 | 
| +  void OnEnoughSizeForMemory(const std::string& uuid, bool can_fit);
 | 
| +
 | 
| +  void OnDependentBlobFinished(const std::string& owning_blob_uuid,
 | 
| +                               BlobStatus reason);
 | 
| +
 | 
| +  void ClearAndFreeMemory(BlobEntry* entry);
 | 
| +
 | 
| +  BlobStorageRegistry registry_;
 | 
| +  BlobMemoryController memory_controller_;
 | 
| +  base::WeakPtrFactory<BlobStorageContext> ptr_factory_;
 | 
|  
 | 
|    DISALLOW_COPY_AND_ASSIGN(BlobStorageContext);
 | 
|  };
 | 
| 
 |