1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "content/child/blob_storage/blob_consolidation.h"
9 using storage::DataElement
;
10 using blink::WebThreadSafeData
;
14 using ReadStatus
= BlobConsolidation::ReadStatus
;
16 BlobConsolidation::ConsolidatedItem::ConsolidatedItem()
17 : type(DataElement::TYPE_UNKNOWN
),
20 expected_modification_time(0) {
23 BlobConsolidation::ConsolidatedItem::~ConsolidatedItem() {
26 BlobConsolidation::ConsolidatedItem::ConsolidatedItem(DataElement::Type type
,
32 expected_modification_time(0) {
35 BlobConsolidation::BlobConsolidation() : total_memory_(0) {
38 BlobConsolidation::~BlobConsolidation() {
41 void BlobConsolidation::AddDataItem(const WebThreadSafeData
& data
) {
44 if (consolidated_items_
.empty() ||
45 consolidated_items_
.back().type
!= DataElement::TYPE_BYTES
) {
46 consolidated_items_
.push_back(
47 ConsolidatedItem(DataElement::TYPE_BYTES
, 0, 0));
49 ConsolidatedItem
& item
= consolidated_items_
.back();
50 if (!item
.data
.empty()) {
51 item
.offsets
.push_back(static_cast<size_t>(item
.length
));
53 item
.length
+= data
.size();
54 total_memory_
+= data
.size();
55 item
.data
.push_back(data
);
58 void BlobConsolidation::AddFileItem(const base::FilePath
& path
,
61 double expected_modification_time
) {
64 consolidated_items_
.push_back(
65 ConsolidatedItem(DataElement::TYPE_FILE
, offset
, length
));
66 ConsolidatedItem
& item
= consolidated_items_
.back();
68 item
.expected_modification_time
= expected_modification_time
;
71 void BlobConsolidation::AddBlobItem(const std::string
& uuid
,
76 consolidated_items_
.push_back(
77 ConsolidatedItem(DataElement::TYPE_BLOB
, offset
, length
));
78 ConsolidatedItem
& item
= consolidated_items_
.back();
79 item
.blob_uuid
= uuid
;
82 void BlobConsolidation::AddFileSystemItem(const GURL
& url
,
85 double expected_modification_time
) {
88 consolidated_items_
.push_back(
89 ConsolidatedItem(DataElement::TYPE_FILE_FILESYSTEM
, offset
, length
));
90 ConsolidatedItem
& item
= consolidated_items_
.back();
91 item
.filesystem_url
= url
;
92 item
.expected_modification_time
= expected_modification_time
;
95 ReadStatus
BlobConsolidation::ReadMemory(size_t consolidated_item_index
,
96 size_t consolidated_offset
,
97 size_t consolidated_size
,
100 if (consolidated_item_index
>= consolidated_items_
.size())
101 return ReadStatus::ERROR_OUT_OF_BOUNDS
;
103 const ConsolidatedItem
& item
= consolidated_items_
[consolidated_item_index
];
104 if (item
.type
!= DataElement::TYPE_BYTES
)
105 return ReadStatus::ERROR_WRONG_TYPE
;
107 if (consolidated_size
+ consolidated_offset
> item
.length
) {
108 LOG(ERROR
) << "Invalid consolidated size " << consolidated_size
109 << " and offset " << consolidated_offset
<< " vs item length of "
111 return ReadStatus::ERROR_OUT_OF_BOUNDS
;
114 // We do a binary search to find the correct data to start with in the data
115 // elements. This is slightly customized due to our unique storage and
118 size_t offset_from_mid
= consolidated_offset
;
119 size_t num_items
= item
.data
.size();
120 if (!item
.offsets
.empty()) {
122 size_t high
= num_items
- 1;
124 mid
= (high
+ low
) / 2;
125 // Note: we don't include the implicit '0' for the first item in offsets.
126 size_t item_offset
= (mid
== 0 ? 0 : item
.offsets
[mid
- 1]);
127 offset_from_mid
= consolidated_offset
- item_offset
;
128 size_t next_item_offset
= (mid
+ 1 == num_items
? 0 : item
.offsets
[mid
]);
129 if (item_offset
== consolidated_offset
) {
130 // found exact match.
132 } else if (item_offset
> consolidated_offset
) {
134 } else if (mid
+ 1 == num_items
||
135 next_item_offset
> consolidated_offset
) {
136 // We are at the last item, or the next offset is greater than the one
137 // we want, so the current item wins.
145 DCHECK_LT(offset_from_mid
, item
.data
[mid
].size());
146 // Read starting from 'mid' and 'offset_from_mid'.
147 for (size_t memory_read
= 0;
148 mid
< num_items
&& memory_read
< consolidated_size
; mid
++) {
149 size_t read_size
= std::min(item
.data
[mid
].size() - offset_from_mid
,
150 consolidated_size
- memory_read
);
151 memcpy(static_cast<char*>(memory_out
) + memory_read
,
152 item
.data
[mid
].data() + offset_from_mid
, read_size
);
154 memory_read
+= read_size
;
156 return ReadStatus::OK
;
159 } // namespace content