Chromium Code Reviews| Index: storage/browser/blob/blob_storage_context.cc |
| diff --git a/storage/browser/blob/blob_storage_context.cc b/storage/browser/blob/blob_storage_context.cc |
| index 27db3cf23708a8a2b8b048a32b6fc8be1c8902b8..b104de4e16e1d52891aebb047ddd4fe15be35522 100644 |
| --- a/storage/browser/blob/blob_storage_context.cc |
| +++ b/storage/browser/blob/blob_storage_context.cc |
| @@ -8,75 +8,38 @@ |
| #include <limits> |
| #include "base/bind.h" |
| +#include "base/callback.h" |
| #include "base/location.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| +#include "base/message_loop/message_loop.h" |
| #include "base/metrics/histogram.h" |
| -#include "base/stl_util.h" |
| #include "base/thread_task_runner_handle.h" |
| #include "base/trace_event/trace_event.h" |
| #include "storage/browser/blob/blob_data_builder.h" |
| -#include "storage/browser/blob/shareable_file_reference.h" |
| +#include "storage/browser/blob/blob_data_handle.h" |
| +#include "storage/browser/blob/blob_data_item.h" |
| +#include "storage/browser/blob/blob_data_snapshot.h" |
| +#include "storage/browser/blob/shareable_blob_data_item.h" |
| #include "url/gurl.h" |
| namespace storage { |
| +using BlobRegistryEntry = BlobStorageRegistry::Entry; |
| +using BlobState = BlobStorageRegistry::BlobState; |
| -namespace { |
| - |
| -// We can't use GURL directly for these hash fragment manipulations |
| -// since it doesn't have specific knowlege of the BlobURL format. GURL |
| -// treats BlobURLs as if they were PathURLs which don't support hash |
| -// fragments. |
| - |
| -bool BlobUrlHasRef(const GURL& url) { |
| - return url.spec().find('#') != std::string::npos; |
| -} |
| - |
| -GURL ClearBlobUrlRef(const GURL& url) { |
| - size_t hash_pos = url.spec().find('#'); |
| - if (hash_pos == std::string::npos) |
| - return url; |
| - return GURL(url.spec().substr(0, hash_pos)); |
| -} |
| - |
| -// TODO(michaeln): use base::SysInfo::AmountOfPhysicalMemoryMB() in some |
| -// way to come up with a better limit. |
| -static const int64 kMaxMemoryUsage = 500 * 1024 * 1024; // Half a gig. |
| - |
| -} // namespace |
| - |
| -BlobStorageContext::BlobMapEntry::BlobMapEntry() : refcount(0), flags(0) { |
| -} |
| - |
| -BlobStorageContext::BlobMapEntry::BlobMapEntry(int refcount, |
| - InternalBlobData::Builder* data) |
| - : refcount(refcount), flags(0), data_builder(data) { |
| -} |
| - |
| -BlobStorageContext::BlobMapEntry::~BlobMapEntry() { |
| -} |
| - |
| -bool BlobStorageContext::BlobMapEntry::IsBeingBuilt() { |
| - return data_builder; |
| -} |
| - |
| -BlobStorageContext::BlobStorageContext() : memory_usage_(0) { |
| -} |
| +BlobStorageContext::BlobStorageContext() : memory_usage_(0) {} |
| BlobStorageContext::~BlobStorageContext() { |
| - STLDeleteContainerPairSecondPointers(blob_map_.begin(), blob_map_.end()); |
| } |
| scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( |
| const std::string& uuid) { |
| scoped_ptr<BlobDataHandle> result; |
| - BlobMap::iterator found = blob_map_.find(uuid); |
| - if (found == blob_map_.end()) |
| + BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| + if (!entry || entry->state != BlobState::ACTIVE || entry->exceeded_memory) { |
|
michaeln
2015/12/15 02:40:48
If blobs can be passed around while they're being
dmurph
2015/12/18 03:22:50
Fixed. I put the type and disposition as part of t
|
| + LOG(ERROR) << "Could not find blob " << uuid; |
|
michaeln
2015/12/15 02:40:48
I don't think this warrants logging.
dmurph
2015/12/18 03:22:50
Done.
|
| return result.Pass(); |
| - auto* entry = found->second; |
| - if (entry->flags & EXCEEDED_MEMORY) |
| - return result.Pass(); |
| - DCHECK(!entry->IsBeingBuilt()); |
| + } |
| result.reset(new BlobDataHandle(uuid, entry->data->content_type(), |
| entry->data->content_disposition(), this, |
| base::ThreadTaskRunnerHandle::Get().get())); |
| @@ -85,34 +48,23 @@ scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromUUID( |
| scoped_ptr<BlobDataHandle> BlobStorageContext::GetBlobDataFromPublicURL( |
| const GURL& url) { |
| - BlobURLMap::iterator found = |
| - public_blob_urls_.find(BlobUrlHasRef(url) ? ClearBlobUrlRef(url) : url); |
| - if (found == public_blob_urls_.end()) |
| - return scoped_ptr<BlobDataHandle>(); |
| - return GetBlobDataFromUUID(found->second); |
| + scoped_ptr<BlobDataHandle> result; |
| + std::string uuid; |
| + BlobRegistryEntry* entry = registry_.GetEntryFromURL(url, &uuid); |
| + if (!entry) { |
| + LOG(ERROR) << "Could not find blob url " << url; |
|
michaeln
2015/12/15 02:40:48
Ditto doesn't need to be logged here and below.
dmurph
2015/12/18 03:22:50
Done.
|
| + return result.Pass(); |
| + } |
| + result.reset(new BlobDataHandle(uuid, entry->data->content_type(), |
| + entry->data->content_disposition(), this, |
| + base::ThreadTaskRunnerHandle::Get().get())); |
| + return result.Pass(); |
| } |
| scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( |
| const BlobDataBuilder& external_builder) { |
| TRACE_EVENT0("Blob", "Context::AddFinishedBlob"); |
| - StartBuildingBlob(external_builder.uuid_); |
| - BlobMap::iterator found = blob_map_.find(external_builder.uuid_); |
| - DCHECK(found != blob_map_.end()); |
| - BlobMapEntry* entry = found->second; |
| - InternalBlobData::Builder* target_blob_builder = entry->data_builder.get(); |
| - DCHECK(target_blob_builder); |
| - |
| - target_blob_builder->set_content_disposition( |
| - external_builder.content_disposition_); |
| - for (const auto& blob_item : external_builder.items_) { |
| - if (!AppendAllocatedBlobItem(external_builder.uuid_, blob_item, |
| - target_blob_builder)) { |
| - BlobEntryExceededMemory(entry); |
| - break; |
| - } |
| - } |
| - |
| - FinishBuildingBlob(external_builder.uuid_, external_builder.content_type_); |
| + BuildAndStoreBlob(external_builder); |
| scoped_ptr<BlobDataHandle> handle = |
| GetBlobDataFromUUID(external_builder.uuid_); |
| DecrementBlobRefCount(external_builder.uuid_); |
| @@ -127,32 +79,72 @@ scoped_ptr<BlobDataHandle> BlobStorageContext::AddFinishedBlob( |
| bool BlobStorageContext::RegisterPublicBlobURL(const GURL& blob_url, |
| const std::string& uuid) { |
| - DCHECK(!BlobUrlHasRef(blob_url)); |
| - DCHECK(IsInUse(uuid)); |
| - DCHECK(!IsUrlRegistered(blob_url)); |
| - if (!IsInUse(uuid) || IsUrlRegistered(blob_url)) |
| + if (!registry_.CreateUrlMapping(blob_url, uuid)) { |
| + LOG(ERROR) << "Could not register url"; |
| return false; |
| + } |
| IncrementBlobRefCount(uuid); |
| - public_blob_urls_[blob_url] = uuid; |
| return true; |
| } |
| void BlobStorageContext::RevokePublicBlobURL(const GURL& blob_url) { |
| - DCHECK(!BlobUrlHasRef(blob_url)); |
| - if (!IsUrlRegistered(blob_url)) |
| + std::string uuid; |
| + if (!registry_.DeleteURLMapping(blob_url, &uuid)) { |
| + LOG(ERROR) << "Could not revoke url"; |
| return; |
| - DecrementBlobRefCount(public_blob_urls_[blob_url]); |
| - public_blob_urls_.erase(blob_url); |
| + } |
| + DecrementBlobRefCount(uuid); |
| +} |
| + |
| +void BlobStorageContext::BuildAndStoreBlob( |
| + const BlobDataBuilder& external_builder) { |
| + BlobRegistryEntry* entry = registry_.GetEntry(external_builder.uuid()); |
| + if (!entry) { |
| + entry = registry_.CreateEntry(external_builder.uuid()); |
| + } |
| + DCHECK(entry->state == BlobState::RESERVED || |
| + entry->state == BlobState::ASYNC_TRANSPORTATION); |
| + entry->state = BlobState::CONSTRUCTION; |
| + InternalBlobData::Builder* builder = new InternalBlobData::Builder(); |
| + entry->data_builder.reset(builder); |
| + |
| + builder->set_content_disposition(external_builder.content_disposition_); |
| + for (const auto& blob_item : external_builder.items_) { |
| + if (!AppendAllocatedBlobItem(external_builder.uuid_, blob_item, builder)) { |
| + BlobEntryExceededMemory(entry); |
| + break; |
| + } |
| + } |
| + |
| + entry->data_builder->set_content_type(external_builder.content_type_); |
| + entry->data = entry->data_builder->Build(); |
| + entry->data_builder.reset(); |
| + entry->state = BlobState::ACTIVE; |
| + UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->data->items().size()); |
| + UMA_HISTOGRAM_BOOLEAN("Storage.Blob.ExceededMemory", entry->exceeded_memory); |
| + size_t total_memory = 0, nonshared_memory = 0; |
| + entry->data->GetMemoryUsage(&total_memory, &nonshared_memory); |
| + UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalSize", total_memory / 1024); |
| + UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalUnsharedSize", |
| + nonshared_memory / 1024); |
| + TRACE_COUNTER1("Blob", "MemoryStoreUsageBytes", memory_usage_); |
| + |
| + for (const auto& callback : entry->construction_complete_callbacks) { |
|
kinuko
2015/12/13 08:41:45
We've done just 'building' the blob per the method
dmurph
2015/12/18 03:22:50
Done.
|
| + base::MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(callback, true)); |
| + } |
| + entry->construction_complete_callbacks.clear(); |
| } |
| scoped_ptr<BlobDataSnapshot> BlobStorageContext::CreateSnapshot( |
| const std::string& uuid) { |
| scoped_ptr<BlobDataSnapshot> result; |
| - auto found = blob_map_.find(uuid); |
| - DCHECK(found != blob_map_.end()) |
| - << "Blob " << uuid << " should be in map, as the handle is still around"; |
| - BlobMapEntry* entry = found->second; |
| - DCHECK(!entry->IsBeingBuilt()); |
| + BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| + if (!entry || entry->state != BlobState::ACTIVE) { |
| + LOG(ERROR) << "Snapshot requested for incomplete blob"; |
| + return result.Pass(); |
| + } |
| + |
| const InternalBlobData& data = *entry->data; |
| scoped_ptr<BlobDataSnapshot> snapshot(new BlobDataSnapshot( |
| @@ -164,143 +156,84 @@ scoped_ptr<BlobDataSnapshot> BlobStorageContext::CreateSnapshot( |
| return snapshot; |
| } |
| -void BlobStorageContext::StartBuildingBlob(const std::string& uuid) { |
| - DCHECK(!IsInUse(uuid) && !uuid.empty()); |
| - blob_map_[uuid] = new BlobMapEntry(1, new InternalBlobData::Builder()); |
| +bool BlobStorageContext::IsBeingBuilt(const std::string& uuid) const { |
| + const BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| + if (!entry) { |
| + return false; |
| + } |
| + switch (entry->state) { |
| + case BlobState::ACTIVE: |
| + return false; |
| + case BlobState::RESERVED: |
| + case BlobState::CONSTRUCTION: |
| + case BlobState::ASYNC_TRANSPORTATION: |
| + return true; |
| + } |
| + return false; |
| } |
| -void BlobStorageContext::AppendBlobDataItem( |
| +void BlobStorageContext::RunOnConstructionComplete( |
| const std::string& uuid, |
| - const storage::DataElement& ipc_data_element) { |
| - TRACE_EVENT0("Blob", "Context::AppendBlobDataItem"); |
| - DCHECK(IsBeingBuilt(uuid)); |
| - BlobMap::iterator found = blob_map_.find(uuid); |
| - if (found == blob_map_.end()) |
| - return; |
| - BlobMapEntry* entry = found->second; |
| - if (entry->flags & EXCEEDED_MEMORY) |
| - return; |
| - InternalBlobData::Builder* target_blob_builder = entry->data_builder.get(); |
| - DCHECK(target_blob_builder); |
| - |
| - if (ipc_data_element.type() == DataElement::TYPE_BYTES && |
| - memory_usage_ + ipc_data_element.length() > kMaxMemoryUsage) { |
| - BlobEntryExceededMemory(entry); |
| + const base::Callback<void(bool)>& done) { |
|
kinuko
2015/12/13 08:41:45
If the caller's always check Context::IsBeingBuilt
dmurph
2015/12/18 03:22:50
Done, and also done for below.
|
| + BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| + if (!entry) { |
| + done.Run(false); |
| return; |
| } |
| - if (!AppendAllocatedBlobItem(uuid, AllocateBlobItem(uuid, ipc_data_element), |
| - target_blob_builder)) { |
| - BlobEntryExceededMemory(entry); |
| + switch (entry->state) { |
| + case BlobState::ACTIVE: |
| + done.Run(true); |
| + break; |
| + case BlobState::RESERVED: |
| + case BlobState::CONSTRUCTION: |
| + case BlobState::ASYNC_TRANSPORTATION: |
| + entry->construction_complete_callbacks.push_back(done); |
| + break; |
| } |
| } |
| -void BlobStorageContext::FinishBuildingBlob(const std::string& uuid, |
| - const std::string& content_type) { |
| - DCHECK(IsBeingBuilt(uuid)); |
| - BlobMap::iterator found = blob_map_.find(uuid); |
| - if (found == blob_map_.end()) |
| - return; |
| - BlobMapEntry* entry = found->second; |
| - entry->data_builder->set_content_type(content_type); |
| - entry->data = entry->data_builder->Build(); |
| - entry->data_builder.reset(); |
| - UMA_HISTOGRAM_COUNTS("Storage.Blob.ItemCount", entry->data->items().size()); |
| - UMA_HISTOGRAM_BOOLEAN("Storage.Blob.ExceededMemory", |
| - (entry->flags & EXCEEDED_MEMORY) == EXCEEDED_MEMORY); |
| - size_t total_memory = 0, nonshared_memory = 0; |
| - entry->data->GetMemoryUsage(&total_memory, &nonshared_memory); |
| - UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalSize", total_memory / 1024); |
| - UMA_HISTOGRAM_COUNTS("Storage.Blob.TotalUnsharedSize", |
| - nonshared_memory / 1024); |
| - TRACE_COUNTER1("Blob", "MemoryStoreUsageBytes", memory_usage_); |
| -} |
| - |
| -void BlobStorageContext::CancelBuildingBlob(const std::string& uuid) { |
| - DCHECK(IsBeingBuilt(uuid)); |
| - DecrementBlobRefCount(uuid); |
| -} |
| - |
| void BlobStorageContext::IncrementBlobRefCount(const std::string& uuid) { |
| - BlobMap::iterator found = blob_map_.find(uuid); |
| - if (found == blob_map_.end()) { |
| - DCHECK(false); |
| + BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| + if (!entry) { |
| return; |
| } |
| - ++(found->second->refcount); |
| + ++(entry->refcount); |
| } |
| void BlobStorageContext::DecrementBlobRefCount(const std::string& uuid) { |
| - BlobMap::iterator found = blob_map_.find(uuid); |
| - if (found == blob_map_.end()) |
| + BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| + if (!entry) |
| return; |
| - auto* entry = found->second; |
| if (--(entry->refcount) == 0) { |
| size_t memory_freeing = 0; |
| - if (entry->IsBeingBuilt()) { |
| - memory_freeing = entry->data_builder->GetNonsharedMemoryUsage(); |
| - entry->data_builder->RemoveBlobFromShareableItems(uuid); |
| - } else { |
| - memory_freeing = entry->data->GetUnsharedMemoryUsage(); |
| - entry->data->RemoveBlobFromShareableItems(uuid); |
| + switch (entry->state) { |
| + case BlobState::ACTIVE: |
| + memory_freeing = entry->data->GetUnsharedMemoryUsage(); |
| + entry->data->RemoveBlobFromShareableItems(uuid); |
| + break; |
| + case BlobState::CONSTRUCTION: |
|
michaeln
2015/12/15 02:40:48
How is this case reachable? Looks like the state t
dmurph
2015/12/18 03:22:50
It doesn't look reachable. I'll check fail.
|
| + memory_freeing = entry->data_builder->GetNonsharedMemoryUsage(); |
| + entry->data_builder->RemoveBlobFromShareableItems(uuid); |
| + break; |
| + case BlobState::ASYNC_TRANSPORTATION: |
| + case BlobState::RESERVED: |
| + break; |
| } |
| DCHECK_LE(memory_freeing, memory_usage_); |
| memory_usage_ -= memory_freeing; |
| - delete entry; |
| - blob_map_.erase(found); |
| + registry_.DeleteEntry(uuid); |
| } |
| } |
| -void BlobStorageContext::BlobEntryExceededMemory(BlobMapEntry* entry) { |
| +void BlobStorageContext::BlobEntryExceededMemory(BlobRegistryEntry* entry) { |
| // If we're using too much memory, drop this blob's data. |
| // TODO(michaeln): Blob memory storage does not yet spill over to disk, |
| // as a stop gap, we'll prevent memory usage over a max amount. |
| memory_usage_ -= entry->data_builder->GetNonsharedMemoryUsage(); |
| - entry->flags |= EXCEEDED_MEMORY; |
| + entry->exceeded_memory = true; |
| entry->data_builder.reset(new InternalBlobData::Builder()); |
| } |
| -scoped_refptr<BlobDataItem> BlobStorageContext::AllocateBlobItem( |
| - const std::string& uuid, |
| - const DataElement& ipc_data) { |
| - scoped_refptr<BlobDataItem> blob_item; |
| - |
| - uint64 length = ipc_data.length(); |
| - scoped_ptr<DataElement> element(new DataElement()); |
| - switch (ipc_data.type()) { |
| - case DataElement::TYPE_BYTES: |
| - DCHECK(!ipc_data.offset()); |
| - element->SetToBytes(ipc_data.bytes(), length); |
| - blob_item = new BlobDataItem(element.Pass()); |
| - break; |
| - case DataElement::TYPE_FILE: |
| - element->SetToFilePathRange(ipc_data.path(), ipc_data.offset(), length, |
| - ipc_data.expected_modification_time()); |
| - blob_item = new BlobDataItem( |
| - element.Pass(), ShareableFileReference::Get(ipc_data.path())); |
| - break; |
| - case DataElement::TYPE_FILE_FILESYSTEM: |
| - element->SetToFileSystemUrlRange(ipc_data.filesystem_url(), |
| - ipc_data.offset(), length, |
| - ipc_data.expected_modification_time()); |
| - blob_item = new BlobDataItem(element.Pass()); |
| - break; |
| - case DataElement::TYPE_BLOB: |
| - // This is a temporary item that will be deconstructed later. |
| - element->SetToBlobRange(ipc_data.blob_uuid(), ipc_data.offset(), |
| - ipc_data.length()); |
| - blob_item = new BlobDataItem(element.Pass()); |
| - break; |
| - case DataElement::TYPE_DISK_CACHE_ENTRY: // This type can't be sent by IPC. |
| - NOTREACHED(); |
| - break; |
| - default: |
| - NOTREACHED(); |
| - break; |
| - } |
| - |
| - return blob_item; |
| -} |
| - |
| bool BlobStorageContext::AppendAllocatedBlobItem( |
| const std::string& target_blob_uuid, |
| scoped_refptr<BlobDataItem> blob_item, |
| @@ -320,6 +253,7 @@ bool BlobStorageContext::AppendAllocatedBlobItem( |
| // offset or size) are shared between the blobs. Otherwise, the relevant |
| // portion of the item is copied. |
| + DCHECK(blob_item->data_element_ptr()); |
| const DataElement& data_element = blob_item->data_element(); |
| uint64 length = data_element.length(); |
| uint64 offset = data_element.offset(); |
| @@ -329,7 +263,7 @@ bool BlobStorageContext::AppendAllocatedBlobItem( |
| case DataElement::TYPE_BYTES: |
| UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.Bytes", length / 1024); |
| DCHECK(!offset); |
| - if (memory_usage_ + length > kMaxMemoryUsage) { |
| + if (memory_usage_ + length > kBlobStorageMaxMemoryUsage) { |
| exceeded_memory = true; |
| break; |
| } |
| @@ -367,8 +301,8 @@ bool BlobStorageContext::AppendAllocatedBlobItem( |
| scoped_ptr<BlobDataHandle> src = |
| GetBlobDataFromUUID(data_element.blob_uuid()); |
| if (src) { |
| - BlobMapEntry* other_entry = |
| - blob_map_.find(data_element.blob_uuid())->second; |
| + BlobRegistryEntry* other_entry = |
| + registry_.GetEntry(data_element.blob_uuid()); |
| DCHECK(other_entry->data); |
| exceeded_memory = !AppendBlob(target_blob_uuid, *other_entry->data, |
| offset, length, target_blob_builder); |
| @@ -382,7 +316,8 @@ bool BlobStorageContext::AppendAllocatedBlobItem( |
| new ShareableBlobDataItem(target_blob_uuid, blob_item)); |
| break; |
| } |
| - default: |
| + case DataElement::TYPE_BYTES_DESCRIPTION: |
| + case DataElement::TYPE_UNKNOWN: |
| NOTREACHED(); |
| break; |
| } |
| @@ -398,7 +333,7 @@ bool BlobStorageContext::AppendBlob( |
| uint64_t offset, |
| uint64_t length, |
| InternalBlobData::Builder* target_blob_builder) { |
| - DCHECK(length > 0); |
| + DCHECK_GT(length, 0ull); |
| const std::vector<scoped_refptr<ShareableBlobDataItem>>& items = blob.items(); |
| auto iter = items.begin(); |
| @@ -435,7 +370,7 @@ bool BlobStorageContext::AppendBlob( |
| case DataElement::TYPE_BYTES: { |
| UMA_HISTOGRAM_COUNTS("Storage.BlobItemSize.BlobSlice.Bytes", |
| new_length / 1024); |
| - if (memory_usage_ + new_length > kMaxMemoryUsage) { |
| + if (memory_usage_ + new_length > kBlobStorageMaxMemoryUsage) { |
| return false; |
| } |
| DCHECK(!item.offset()); |
| @@ -479,7 +414,9 @@ bool BlobStorageContext::AppendBlob( |
| item.disk_cache_entry(), |
| item.disk_cache_stream_index()))); |
| } break; |
| - default: |
| + case DataElement::TYPE_BYTES_DESCRIPTION: |
| + case DataElement::TYPE_BLOB: |
| + case DataElement::TYPE_UNKNOWN: |
| CHECK(false) << "Illegal blob item type: " << item.type(); |
| } |
| length -= new_length; |
| @@ -488,19 +425,55 @@ bool BlobStorageContext::AppendBlob( |
| return true; |
| } |
| -bool BlobStorageContext::IsInUse(const std::string& uuid) { |
| - return blob_map_.find(uuid) != blob_map_.end(); |
| +void BlobStorageContext::RegisterBlobUUID(const std::string& uuid) { |
| + DCHECK(!registry_.GetEntry(uuid) && !uuid.empty()); |
| + registry_.CreateEntry(uuid); |
| } |
| -bool BlobStorageContext::IsBeingBuilt(const std::string& uuid) { |
| - BlobMap::iterator found = blob_map_.find(uuid); |
| - if (found == blob_map_.end()) |
| +bool BlobStorageContext::MaybeStartAsyncBlobTransfer(const std::string& uuid) { |
| + BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| + if (!entry) |
| return false; |
| - return found->second->IsBeingBuilt(); |
| + return entry->TestAndSetState(BlobState::RESERVED, |
| + BlobState::ASYNC_TRANSPORTATION); |
| +} |
| + |
| +void BlobStorageContext::FinishAsyncBlobTransfer( |
| + base::Closure done, |
| + base::Callback<void(storage::IPCBlobCreationCancelCode)> cancel, |
| + const storage::BlobDataBuilder& builder) { |
| + BlobRegistryEntry* entry = registry_.GetEntry(builder.uuid()); |
| + if (!entry || entry->state != BlobState::ASYNC_TRANSPORTATION) { |
| + LOG(ERROR) << "Invalid state while building blob."; |
| + cancel.Run(IPCBlobCreationCancelCode::UNKNOWN); |
| + return; |
| + } |
| + BuildAndStoreBlob(builder); |
| + done.Run(); |
| +} |
| + |
| +void BlobStorageContext::CancelAsyncBlobTransfer( |
| + const std::string& uuid, |
| + base::Callback<void(storage::IPCBlobCreationCancelCode)> cancel, |
| + storage::IPCBlobCreationCancelCode code) { |
| + CleanupCanceledAsyncBlobTransfer(uuid); |
| + cancel.Run(code); |
| } |
| -bool BlobStorageContext::IsUrlRegistered(const GURL& blob_url) { |
| - return public_blob_urls_.find(blob_url) != public_blob_urls_.end(); |
| +bool BlobStorageContext::CleanupCanceledAsyncBlobTransfer( |
| + const std::string& uuid) { |
| + BlobRegistryEntry* entry = registry_.GetEntry(uuid); |
| + if (!entry || (entry->state != BlobState::ASYNC_TRANSPORTATION && |
| + entry->state != BlobState::RESERVED)) { |
| + LOG(ERROR) << "Invalid blob for canceling construction: " << uuid; |
| + return false; |
| + } |
| + for (const auto& callback : entry->construction_complete_callbacks) { |
| + base::MessageLoop::current()->PostTask(FROM_HERE, |
| + base::Bind(callback, false)); |
| + } |
| + registry_.DeleteEntry(uuid); |
| + return true; |
| } |
| } // namespace storage |