Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(165)

Side by Side Diff: net/disk_cache/entry_impl.cc

Issue 3167020: Disk cache: Extend the internal buffering performed by each entry... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 10 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2006-2010 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "net/disk_cache/entry_impl.h" 5 #include "net/disk_cache/entry_impl.h"
6 6
7 #include "base/histogram.h" 7 #include "base/histogram.h"
8 #include "base/message_loop.h" 8 #include "base/message_loop.h"
9 #include "base/string_util.h" 9 #include "base/string_util.h"
10 #include "net/base/io_buffer.h" 10 #include "net/base/io_buffer.h"
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
70 DCHECK_GE(offset, 0); 70 DCHECK_GE(offset, 0);
71 DCHECK_GE(valid_len, 0); 71 DCHECK_GE(valid_len, 0);
72 DCHECK(disk_cache::kMaxBlockSize >= offset + valid_len); 72 DCHECK(disk_cache::kMaxBlockSize >= offset + valid_len);
73 if (offset) 73 if (offset)
74 memset(buffer, 0, offset); 74 memset(buffer, 0, offset);
75 int end = disk_cache::kMaxBlockSize - offset - valid_len; 75 int end = disk_cache::kMaxBlockSize - offset - valid_len;
76 if (end) 76 if (end)
77 memset(buffer + offset + valid_len, 0, end); 77 memset(buffer + offset + valid_len, 0, end);
78 } 78 }
79 79
80 const int kMaxBufferSize = 1024 * 1024; // 1 MB.
81
80 } // namespace 82 } // namespace
81 83
82 namespace disk_cache { 84 namespace disk_cache {
83 85
86 // This class handles individual memory buffers that store data before it is
87 // sent to disk. The buffer can start at any offset, but if we try to write to
88 // anywhere in the first 16KB of the file (kMaxBlockSize), we set the offset to
89 // zero. The buffer grows up to a size determined by the backend, to keep the
90 // total memory used under control.
91 class EntryImpl::UserBuffer {
92 public:
93 explicit UserBuffer(BackendImpl* backend)
94 : backend_(backend->GetWeakPtr()), offset_(0), grow_allowed_(true) {
95 buffer_.reserve(kMaxBlockSize);
96 }
97 ~UserBuffer() {
98 if (backend_)
99 backend_->BufferDeleted(capacity() - kMaxBlockSize);
100 }
101
102 // Returns true if we can handle writing |len| bytes to |offset|.
103 bool PreWrite(int offset, int len);
104
105 // Truncates the buffer to |offset| bytes.
106 void Truncate(int offset);
107
108 // Writes |len| bytes from |buf| at the given |offset|.
109 void Write(int offset, net::IOBuffer* buf, int len);
110
111 // Returns true if we can read |len| bytes from |offset|, given that the
112 // actual file has |eof| bytes stored. Note that the number of bytes to read
113 // may be modified by this method even though it returns false: that means we
114 // should do a smaller read from disk.
115 bool PreRead(int eof, int offset, int* len);
116
117 // Read |len| bytes from |buf| at the given |offset|.
118 int Read(int offset, net::IOBuffer* buf, int len);
119
120 // Prepare this buffer for reuse.
121 void Reset();
122
123 char* Data() { return buffer_.size() ? &buffer_[0] : NULL; }
124 int Size() { return static_cast<int>(buffer_.size()); }
125 int Start() { return offset_; }
126 int End() { return offset_ + Size(); }
127
128 private:
129 int capacity() { return static_cast<int>(buffer_.capacity()); }
130 bool GrowBuffer(int required, int limit);
131
132 base::WeakPtr<BackendImpl> backend_;
133 int offset_;
134 std::vector<char> buffer_;
135 bool grow_allowed_;
136 DISALLOW_COPY_AND_ASSIGN(UserBuffer);
137 };
138
139 bool EntryImpl::UserBuffer::PreWrite(int offset, int len) {
140 DCHECK_GE(offset, 0);
141 DCHECK_GE(len, 0);
142 DCHECK_GE(offset + len, 0);
143
144 // We don't want to write before our current start.
145 if (offset < offset_)
146 return false;
147
148 // Lets get the common case out of the way.
149 if (offset + len <= capacity())
150 return true;
151
152 // If we are writing to the first 16K (kMaxBlockSize), we want to keep the
153 // buffer offset_ at 0.
154 if (!Size() && offset > kMaxBlockSize)
155 return GrowBuffer(len, kMaxBufferSize);
156
157 int required = offset - offset_ + len;
158 return GrowBuffer(required, kMaxBufferSize * 6 / 5);
159 }
160
161 void EntryImpl::UserBuffer::Truncate(int offset) {
162 DCHECK_GE(offset, 0);
163 DCHECK_GE(offset, offset_);
164
165 offset -= offset_;
166 if (Size() >= offset)
167 buffer_.resize(offset);
168 }
169
170 void EntryImpl::UserBuffer::Write(int offset, net::IOBuffer* buf, int len) {
171 DCHECK_GE(offset, 0);
172 DCHECK_GE(len, 0);
173 DCHECK_GE(offset + len, 0);
174 DCHECK_GE(offset, offset_);
175
176 if (!Size() && offset > kMaxBlockSize)
177 offset_ = offset;
178
179 offset -= offset_;
180
181 if (offset > Size())
182 buffer_.resize(offset);
183
184 if (!len)
185 return;
186
187 char* buffer = buf->data();
188 int valid_len = Size() - offset;
189 int copy_len = std::min(valid_len, len);
190 if (copy_len) {
191 memcpy(&buffer_[offset], buffer, copy_len);
192 len -= copy_len;
193 buffer += copy_len;
194 }
195 if (!len)
196 return;
197
198 buffer_.insert(buffer_.end(), buffer, buffer + len);
199 }
200
201 bool EntryImpl::UserBuffer::PreRead(int eof, int offset, int* len) {
202 DCHECK_GE(offset, 0);
203 DCHECK_GT(*len, 0);
204
205 if (offset < offset_) {
206 // We are reading before this buffer.
207 if (offset >= eof)
208 return true;
209
210 // If the read overlaps with the buffer, change its length so that there is
211 // no overlap.
212 *len = std::min(*len, offset_ - offset);
213 *len = std::min(*len, eof - offset);
214
215 // We should read from disk.
216 return false;
217 }
218
219 if (!Size())
220 return false;
221
222 // See if we can fulfill the first part of the operation.
223 return (offset - offset_ < Size());
224 }
225
226 int EntryImpl::UserBuffer::Read(int offset, net::IOBuffer* buf, int len) {
227 DCHECK_GE(offset, 0);
228 DCHECK_GT(len, 0);
229 DCHECK(Size() || offset < offset_);
230
231 int clean_bytes = 0;
232 if (offset < offset_) {
233 // We don't have a file so lets fill the first part with 0.
234 clean_bytes = std::min(offset_ - offset, len);
235 memset(buf->data(), 0, clean_bytes);
236 if (len == clean_bytes)
237 return len;
238 offset = offset_;
239 len -= clean_bytes;
240 }
241
242 int start = offset - offset_;
243 int available = Size() - start;
244 DCHECK_GE(start, 0);
245 DCHECK_GE(available, 0);
246 len = std::min(len, available);
247 memcpy(buf->data() + clean_bytes, &buffer_[start], len);
248 return len + clean_bytes;
249 }
250
251 void EntryImpl::UserBuffer::Reset() {
252 if (!grow_allowed_) {
253 if (backend_)
254 backend_->BufferDeleted(capacity() - kMaxBlockSize);
255 grow_allowed_ = true;
256 std::vector<char> tmp;
257 buffer_.swap(tmp);
258 }
259 offset_ = 0;
260 buffer_.clear();
261 }
262
263 bool EntryImpl::UserBuffer::GrowBuffer(int required, int limit) {
264 DCHECK_GE(required, 0);
265 int current_size = capacity();
266 if (required <= current_size)
267 return true;
268
269 if (required > limit)
270 return false;
271
272 if (!backend_)
273 return false;
274
275 int to_add = std::max(required - current_size, kMaxBlockSize * 4);
276 to_add = std::max(current_size, to_add);
277 required = std::min(current_size + to_add, limit);
278
279 grow_allowed_ = backend_->IsAllocAllowed(current_size, required);
280 if (!grow_allowed_)
281 return false;
282
283 buffer_.reserve(required);
284 return true;
285 }
286
287 // ------------------------------------------------------------------------
288
84 EntryImpl::EntryImpl(BackendImpl* backend, Addr address) 289 EntryImpl::EntryImpl(BackendImpl* backend, Addr address)
85 : entry_(NULL, Addr(0)), node_(NULL, Addr(0)) { 290 : entry_(NULL, Addr(0)), node_(NULL, Addr(0)) {
86 entry_.LazyInit(backend->File(address), address); 291 entry_.LazyInit(backend->File(address), address);
87 doomed_ = false; 292 doomed_ = false;
88 backend_ = backend; 293 backend_ = backend;
89 for (int i = 0; i < kNumStreams; i++) { 294 for (int i = 0; i < kNumStreams; i++) {
90 unreported_size_[i] = 0; 295 unreported_size_[i] = 0;
91 } 296 }
92 } 297 }
93 298
94 // When an entry is deleted from the cache, we clean up all the data associated 299 // When an entry is deleted from the cache, we clean up all the data associated
95 // with it for two reasons: to simplify the reuse of the block (we know that any 300 // with it for two reasons: to simplify the reuse of the block (we know that any
96 // unused block is filled with zeros), and to simplify the handling of write / 301 // unused block is filled with zeros), and to simplify the handling of write /
97 // read partial information from an entry (don't have to worry about returning 302 // read partial information from an entry (don't have to worry about returning
98 // data related to a previous cache entry because the range was not fully 303 // data related to a previous cache entry because the range was not fully
99 // written before). 304 // written before).
100 EntryImpl::~EntryImpl() { 305 EntryImpl::~EntryImpl() {
101 // Save the sparse info to disk before deleting this entry. 306 // Save the sparse info to disk before deleting this entry.
102 sparse_.reset(); 307 sparse_.reset();
103 308
104 if (doomed_) { 309 if (doomed_) {
105 DeleteEntryData(true); 310 DeleteEntryData(true);
106 } else { 311 } else {
107 bool ret = true; 312 bool ret = true;
108 for (int index = 0; index < kNumStreams; index++) { 313 for (int index = 0; index < kNumStreams; index++) {
109 if (user_buffers_[index].get()) { 314 if (user_buffers_[index].get()) {
110 if (!(ret = Flush(index, entry_.Data()->data_size[index], false))) 315 if (!(ret = Flush(index)))
111 LOG(ERROR) << "Failed to save user data"; 316 LOG(ERROR) << "Failed to save user data";
112 } else if (unreported_size_[index]) { 317 }
318 if (unreported_size_[index]) {
113 backend_->ModifyStorageSize( 319 backend_->ModifyStorageSize(
114 entry_.Data()->data_size[index] - unreported_size_[index], 320 entry_.Data()->data_size[index] - unreported_size_[index],
115 entry_.Data()->data_size[index]); 321 entry_.Data()->data_size[index]);
116 } 322 }
117 } 323 }
118 324
119 if (!ret) { 325 if (!ret) {
120 // There was a failure writing the actual data. Mark the entry as dirty. 326 // There was a failure writing the actual data. Mark the entry as dirty.
121 int current_id = backend_->GetCurrentEntryId(); 327 int current_id = backend_->GetCurrentEntryId();
122 node_.Data()->dirty = current_id == 1 ? -1 : current_id - 1; 328 node_.Data()->dirty = current_id == 1 ? -1 : current_id - 1;
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
295 TimeTicks start = TimeTicks::Now(); 501 TimeTicks start = TimeTicks::Now();
296 502
297 if (offset + buf_len > entry_size) 503 if (offset + buf_len > entry_size)
298 buf_len = entry_size - offset; 504 buf_len = entry_size - offset;
299 505
300 UpdateRank(false); 506 UpdateRank(false);
301 507
302 backend_->OnEvent(Stats::READ_DATA); 508 backend_->OnEvent(Stats::READ_DATA);
303 backend_->OnRead(buf_len); 509 backend_->OnRead(buf_len);
304 510
305 if (user_buffers_[index].get()) { 511 // We need the current size in disk.
512 int eof = entry_size - unreported_size_[index];
513 if (user_buffers_[index].get() &&
514 user_buffers_[index]->PreRead(eof, offset, &buf_len)) {
306 // Complete the operation locally. 515 // Complete the operation locally.
307 DCHECK(kMaxBlockSize >= offset + buf_len); 516 buf_len = user_buffers_[index]->Read(offset, buf, buf_len);
308 memcpy(buf->data() , user_buffers_[index].get() + offset, buf_len);
309 ReportIOTime(kRead, start); 517 ReportIOTime(kRead, start);
310 return buf_len; 518 return buf_len;
311 } 519 }
312 520
313 Addr address(entry_.Data()->data_addr[index]); 521 Addr address(entry_.Data()->data_addr[index]);
314 DCHECK(address.is_initialized()); 522 DCHECK(address.is_initialized());
315 if (!address.is_initialized()) 523 if (!address.is_initialized())
316 return net::ERR_FAILED; 524 return net::ERR_FAILED;
317 525
318 File* file = GetBackingFile(address, index); 526 File* file = GetBackingFile(address, index);
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
361 if (size <= max_file_size) 569 if (size <= max_file_size)
362 size = kint32max; 570 size = kint32max;
363 backend_->TooMuchStorageRequested(size); 571 backend_->TooMuchStorageRequested(size);
364 return net::ERR_FAILED; 572 return net::ERR_FAILED;
365 } 573 }
366 574
367 TimeTicks start = TimeTicks::Now(); 575 TimeTicks start = TimeTicks::Now();
368 576
369 // Read the size at this point (it may change inside prepare). 577 // Read the size at this point (it may change inside prepare).
370 int entry_size = entry_.Data()->data_size[index]; 578 int entry_size = entry_.Data()->data_size[index];
579 bool extending = entry_size < offset + buf_len;
580 truncate = truncate && entry_size > offset + buf_len;
371 if (!PrepareTarget(index, offset, buf_len, truncate)) 581 if (!PrepareTarget(index, offset, buf_len, truncate))
372 return net::ERR_FAILED; 582 return net::ERR_FAILED;
373 583
374 if (entry_size < offset + buf_len) { 584 if (extending || truncate)
375 unreported_size_[index] += offset + buf_len - entry_size; 585 UpdateSize(index, entry_size, offset + buf_len);
376 entry_.Data()->data_size[index] = offset + buf_len;
377 entry_.set_modified();
378 if (!buf_len)
379 truncate = true; // Force file extension.
380 } else if (truncate) {
381 // If the size was modified inside PrepareTarget, we should not do
382 // anything here.
383 if ((entry_size > offset + buf_len) &&
384 (entry_size == entry_.Data()->data_size[index])) {
385 unreported_size_[index] += offset + buf_len - entry_size;
386 entry_.Data()->data_size[index] = offset + buf_len;
387 entry_.set_modified();
388 } else {
389 // Nothing to truncate.
390 truncate = false;
391 }
392 }
393 586
394 UpdateRank(true); 587 UpdateRank(true);
395 588
396 backend_->OnEvent(Stats::WRITE_DATA); 589 backend_->OnEvent(Stats::WRITE_DATA);
397 backend_->OnWrite(buf_len); 590 backend_->OnWrite(buf_len);
398 591
399 if (user_buffers_[index].get()) { 592 if (user_buffers_[index].get()) {
400 // Complete the operation locally. 593 // Complete the operation locally.
401 if (!buf_len) 594 user_buffers_[index]->Write(offset, buf, buf_len);
402 return 0;
403
404 DCHECK(kMaxBlockSize >= offset + buf_len);
405 memcpy(user_buffers_[index].get() + offset, buf->data(), buf_len);
406 ReportIOTime(kWrite, start); 595 ReportIOTime(kWrite, start);
407 return buf_len; 596 return buf_len;
408 } 597 }
409 598
410 Addr address(entry_.Data()->data_addr[index]); 599 Addr address(entry_.Data()->data_addr[index]);
600 if (truncate && offset + buf_len == 0) {
601 DCHECK(!address.is_initialized());
602 return 0;
603 }
604
411 File* file = GetBackingFile(address, index); 605 File* file = GetBackingFile(address, index);
412 if (!file) 606 if (!file)
413 return net::ERR_FAILED; 607 return net::ERR_FAILED;
414 608
415 size_t file_offset = offset; 609 size_t file_offset = offset;
416 if (address.is_block_file()) { 610 if (address.is_block_file()) {
417 file_offset += address.start_block() * address.BlockSize() + 611 file_offset += address.start_block() * address.BlockSize() +
418 kBlockHeaderSize; 612 kBlockHeaderSize;
419 } else if (truncate) { 613 } else if (truncate || (extending && !buf_len)) {
420 if (!file->SetLength(offset + buf_len)) 614 if (!file->SetLength(offset + buf_len))
421 return net::ERR_FAILED; 615 return net::ERR_FAILED;
422 } 616 }
423 617
424 if (!buf_len) 618 if (!buf_len)
425 return 0; 619 return 0;
426 620
427 SyncCallback* io_callback = NULL; 621 SyncCallback* io_callback = NULL;
428 if (callback) 622 if (callback)
429 io_callback = new SyncCallback(this, buf, callback); 623 io_callback = new SyncCallback(this, buf, callback);
(...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after
786 DCHECK(index >= 0 && index <= kKeyFileIndex); 980 DCHECK(index >= 0 && index <= kKeyFileIndex);
787 if (!files_[index].get()) { 981 if (!files_[index].get()) {
788 // For a key file, use mixed mode IO. 982 // For a key file, use mixed mode IO.
789 scoped_refptr<File> file(new File(kKeyFileIndex == index)); 983 scoped_refptr<File> file(new File(kKeyFileIndex == index));
790 if (file->Init(backend_->GetFileName(address))) 984 if (file->Init(backend_->GetFileName(address)))
791 files_[index].swap(file); 985 files_[index].swap(file);
792 } 986 }
793 return files_[index].get(); 987 return files_[index].get();
794 } 988 }
795 989
990 // We keep a memory buffer for everything that ends up stored on a block file
991 // (because we don't know yet the final data size), and for some of the data
992 // that end up on external files. This function will initialize that memory
993 // buffer and / or the files needed to store the data.
994 //
995 // In general, a buffer may overlap data already stored on disk, and in that
996 // case, the contents of the buffer are the most accurate. It may also extend
997 // the file, but we don't want to read from disk just to keep the buffer up to
998 // date. This means that as soon as there is a chance to get confused about what
999 // is the most recent version of some part of a file, we'll flush the buffer and
1000 // reuse it for the new data. Keep in mind that the normal use pattern is quite
1001 // simple (write sequentially from the beginning), so we optimize for handling
1002 // that case.
796 bool EntryImpl::PrepareTarget(int index, int offset, int buf_len, 1003 bool EntryImpl::PrepareTarget(int index, int offset, int buf_len,
797 bool truncate) { 1004 bool truncate) {
798 Addr address(entry_.Data()->data_addr[index]); 1005 if (truncate)
799 1006 return HandleTruncation(index, offset, buf_len);
800 if (address.is_initialized() || user_buffers_[index].get()) 1007
801 return GrowUserBuffer(index, offset, buf_len, truncate); 1008 Addr address(entry_.Data()->data_addr[index]);
802 1009 if (address.is_initialized()) {
803 if (offset + buf_len > kMaxBlockSize) 1010 if (address.is_block_file() && !MoveToLocalBuffer(index))
804 return CreateDataBlock(index, offset + buf_len); 1011 return false;
805 1012
806 user_buffers_[index].reset(new char[kMaxBlockSize]); 1013 if (!user_buffers_[index].get() && offset < kMaxBlockSize) {
807 1014 // We are about to create a buffer for the first 16KB, make sure that we
808 // Overwrite the parts of the buffer that are not going to be written 1015 // preserve existing data.
809 // by the current operation (and yes, let's assume that nothing is going 1016 if (!CopyToLocalBuffer(index))
810 // to fail, and we'll actually write over the part that we are not cleaning 1017 return false;
811 // here). The point is to avoid writing random stuff to disk later on. 1018 }
812 ClearInvalidData(user_buffers_[index].get(), offset, buf_len); 1019 }
813 1020
814 return true; 1021 if (!user_buffers_[index].get())
1022 user_buffers_[index].reset(new UserBuffer(backend_));
1023
1024 return PrepareBuffer(index, offset, buf_len);
815 } 1025 }
816 1026
817 // We get to this function with some data already stored. If there is a 1027 // We get to this function with some data already stored. If there is a
818 // truncation that results on data stored internally, we'll explicitly 1028 // truncation that results on data stored internally, we'll explicitly
819 // handle the case here. 1029 // handle the case here.
820 bool EntryImpl::GrowUserBuffer(int index, int offset, int buf_len, 1030 bool EntryImpl::HandleTruncation(int index, int offset, int buf_len) {
821 bool truncate) { 1031 Addr address(entry_.Data()->data_addr[index]);
822 Addr address(entry_.Data()->data_addr[index]); 1032
823 1033 int current_size = entry_.Data()->data_size[index];
824 if (offset + buf_len > kMaxBlockSize) { 1034 int new_size = offset + buf_len;
825 // The data has to be stored externally. 1035
826 if (address.is_initialized()) { 1036 if (!new_size) {
827 if (address.is_separate_file()) 1037 // This is by far the most common scenario.
1038 DeleteData(address, index);
1039 backend_->ModifyStorageSize(current_size - unreported_size_[index], 0);
1040 entry_.Data()->data_addr[index] = 0;
1041 entry_.Data()->data_size[index] = 0;
1042 unreported_size_[index] = 0;
1043 entry_.Store();
1044
1045 user_buffers_[index].reset();
1046 return true;
1047 }
1048
1049 // We never postpone truncating a file, if there is one, but we may postpone
1050 // telling the backend about the size reduction.
1051 if (user_buffers_[index].get()) {
1052 DCHECK_GE(current_size, user_buffers_[index]->Start());
1053 if (!address.is_initialized()) {
1054 // There is no overlap between the buffer and disk.
1055 if (new_size > user_buffers_[index]->Start()) {
1056 // Just truncate our buffer.
1057 DCHECK_LT(new_size, user_buffers_[index]->End());
1058 user_buffers_[index]->Truncate(new_size);
828 return true; 1059 return true;
829 if (!MoveToLocalBuffer(index)) 1060 }
830 return false; 1061
831 } 1062 // Just discard our buffer.
832 return Flush(index, offset + buf_len, true); 1063 user_buffers_[index]->Reset();
833 } 1064 return PrepareBuffer(index, offset, buf_len);
834 1065 }
835 if (!address.is_initialized()) { 1066
836 DCHECK(user_buffers_[index].get()); 1067 // There is some overlap or we need to extend the file before the
837 if (truncate) 1068 // truncation.
838 ClearInvalidData(user_buffers_[index].get(), 0, offset + buf_len); 1069 if (offset > user_buffers_[index]->Start())
839 return true; 1070 user_buffers_[index]->Truncate(new_size);
840 } 1071 UpdateSize(index, current_size, new_size);
841 if (address.is_separate_file()) { 1072 if (!Flush(index))
842 if (!truncate) 1073 return false;
843 return true; 1074 user_buffers_[index].reset();
844 return ImportSeparateFile(index, offset, buf_len); 1075 }
845 } 1076
846 1077 // We have data somewhere, and it is not in a buffer.
847 // At this point we are dealing with data stored on disk, inside a block file.
848 if (offset + buf_len <= address.BlockSize() * address.num_blocks())
849 return true;
850
851 // ... and the allocated block has to change.
852 if (!MoveToLocalBuffer(index))
853 return false;
854
855 int clear_start = entry_.Data()->data_size[index];
856 if (truncate)
857 clear_start = std::min(clear_start, offset + buf_len);
858 else if (offset < clear_start)
859 clear_start = std::max(offset + buf_len, clear_start);
860
861 // Clear the end of the buffer.
862 ClearInvalidData(user_buffers_[index].get(), 0, clear_start);
863 return true;
864 }
865
866 bool EntryImpl::MoveToLocalBuffer(int index) {
867 Addr address(entry_.Data()->data_addr[index]);
868 DCHECK(!user_buffers_[index].get()); 1078 DCHECK(!user_buffers_[index].get());
869 DCHECK(address.is_initialized()); 1079 DCHECK(address.is_initialized());
870 scoped_array<char> buffer(new char[kMaxBlockSize]); 1080
1081 if (new_size > kMaxBlockSize)
1082 return true; // Let the operation go directly to disk.
1083
1084 return ImportSeparateFile(index, offset + buf_len);
1085 }
1086
1087 bool EntryImpl::CopyToLocalBuffer(int index) {
1088 Addr address(entry_.Data()->data_addr[index]);
1089 DCHECK(!user_buffers_[index].get());
1090 DCHECK(address.is_initialized());
1091
1092 int len = std::min(entry_.Data()->data_size[index], kMaxBlockSize);
1093 user_buffers_[index].reset(new UserBuffer(backend_));
1094 user_buffers_[index]->Write(len, NULL, 0);
871 1095
872 File* file = GetBackingFile(address, index); 1096 File* file = GetBackingFile(address, index);
873 size_t len = entry_.Data()->data_size[index]; 1097 int offset = 0;
874 size_t offset = 0;
875 1098
876 if (address.is_block_file()) 1099 if (address.is_block_file())
877 offset = address.start_block() * address.BlockSize() + kBlockHeaderSize; 1100 offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
878 1101
879 if (!file || !file->Read(buffer.get(), len, offset, NULL, NULL)) 1102 if (!file ||
880 return false; 1103 !file->Read(user_buffers_[index]->Data(), len, offset, NULL, NULL)) {
881 1104 user_buffers_[index].reset();
1105 return false;
1106 }
1107 return true;
1108 }
1109
1110 bool EntryImpl::MoveToLocalBuffer(int index) {
1111 if (!CopyToLocalBuffer(index))
1112 return false;
1113
1114 Addr address(entry_.Data()->data_addr[index]);
882 DeleteData(address, index); 1115 DeleteData(address, index);
883 entry_.Data()->data_addr[index] = 0; 1116 entry_.Data()->data_addr[index] = 0;
884 entry_.Store(); 1117 entry_.Store();
885 1118
886 // If we lose this entry we'll see it as zero sized. 1119 // If we lose this entry we'll see it as zero sized.
887 backend_->ModifyStorageSize(static_cast<int>(len) - unreported_size_[index], 1120 int len = entry_.Data()->data_size[index];
888 0); 1121 backend_->ModifyStorageSize(len - unreported_size_[index], 0);
889 unreported_size_[index] = static_cast<int>(len); 1122 unreported_size_[index] = len;
890 1123 return true;
891 user_buffers_[index].swap(buffer); 1124 }
892 return true; 1125
893 } 1126 bool EntryImpl::ImportSeparateFile(int index, int new_size) {
894 1127 if (entry_.Data()->data_size[index] > new_size)
895 bool EntryImpl::ImportSeparateFile(int index, int offset, int buf_len) { 1128 UpdateSize(index, entry_.Data()->data_size[index], new_size);
896 if (entry_.Data()->data_size[index] > offset + buf_len) { 1129
897 unreported_size_[index] += offset + buf_len - 1130 return MoveToLocalBuffer(index);
898 entry_.Data()->data_size[index]; 1131 }
899 entry_.Data()->data_size[index] = offset + buf_len; 1132
900 } 1133 bool EntryImpl::PrepareBuffer(int index, int offset, int buf_len) {
901
902 if (!MoveToLocalBuffer(index))
903 return false;
904
905 // Clear the end of the buffer.
906 ClearInvalidData(user_buffers_[index].get(), 0, offset + buf_len);
907 return true;
908 }
909
910 // The common scenario is that this is called from the destructor of the entry,
911 // to write to disk what we have buffered. We don't want to hold the destructor
912 // until the actual IO finishes, so we'll send an asynchronous write that will
913 // free up the memory containing the data. To be consistent, this method always
914 // returns with the buffer freed up (on success).
915 bool EntryImpl::Flush(int index, int size, bool async) {
916 Addr address(entry_.Data()->data_addr[index]);
917 DCHECK(user_buffers_[index].get()); 1134 DCHECK(user_buffers_[index].get());
918 DCHECK(!address.is_initialized()); 1135 if (offset > user_buffers_[index]->End()) {
919 1136 // We are about to extend the buffer (with zeros), so make sure that we are
920 if (!size) 1137 // not overwriting anything.
1138 Addr address(entry_.Data()->data_addr[index]);
1139 if (address.is_initialized() && address.is_separate_file()) {
1140 int eof = entry_.Data()->data_size[index];
1141 if (eof > user_buffers_[index]->Start() && !Flush(index))
1142 return false;
1143 }
1144 }
1145
1146 if (!user_buffers_[index]->PreWrite(offset, buf_len)) {
1147 if (!Flush(index))
1148 return false;
1149
1150 // Lets try again.
1151 if (!user_buffers_[index]->PreWrite(offset, buf_len)) {
1152 // We cannot complete the operation with a buffer.
1153 DCHECK(!user_buffers_[index]->Size());
1154 DCHECK(!user_buffers_[index]->Start());
1155 user_buffers_[index].reset();
1156 }
1157 }
1158 return true;
1159 }
1160
1161 bool EntryImpl::Flush(int index) {
1162 Addr address(entry_.Data()->data_addr[index]);
1163 DCHECK(user_buffers_[index].get());
1164
1165 if (!entry_.Data()->data_size[index]) {
1166 DCHECK(!user_buffers_[index]->Size());
921 return true; 1167 return true;
922 1168 }
923 if (!CreateDataBlock(index, size)) 1169
1170 if (!address.is_initialized() &&
1171 !CreateDataBlock(index, entry_.Data()->data_size[index]))
924 return false; 1172 return false;
925 1173
926 address.set_value(entry_.Data()->data_addr[index]); 1174 address.set_value(entry_.Data()->data_addr[index]);
927 1175
928 File* file = GetBackingFile(address, index); 1176 File* file = GetBackingFile(address, index);
929 size_t len = entry_.Data()->data_size[index]; 1177 int len = user_buffers_[index]->Size();
930 size_t offset = 0; 1178 int offset = user_buffers_[index]->Start();
931 if (address.is_block_file()) 1179 if (address.is_block_file()) {
1180 DCHECK_EQ(len, entry_.Data()->data_size[index]);
1181 DCHECK(!offset);
932 offset = address.start_block() * address.BlockSize() + kBlockHeaderSize; 1182 offset = address.start_block() * address.BlockSize() + kBlockHeaderSize;
933 1183 }
934 // We just told the backend to store len bytes for real.
935 DCHECK(len == static_cast<size_t>(unreported_size_[index]));
936 backend_->ModifyStorageSize(0, static_cast<int>(len));
937 unreported_size_[index] = 0;
938 1184
939 if (!file) 1185 if (!file)
940 return false; 1186 return false;
941 1187
942 // TODO(rvargas): figure out if it's worth to re-enable posting operations. 1188 if (!file->Write(user_buffers_[index]->Data(), len, offset, NULL, NULL))
943 // Right now it is only used from GrowUserBuffer, not the destructor, and 1189 return false;
944 // it is not accounted for from the point of view of the total number of 1190 user_buffers_[index]->Reset();
945 // pending operations of the cache. It is also racing with the actual write 1191
946 // on the GrowUserBuffer path because there is no code to exclude the range 1192 return true;
947 // that is going to be written. 1193 }
948 async = false; 1194
949 if (async) { 1195 void EntryImpl::UpdateSize(int index, int old_size, int new_size) {
950 if (!file->PostWrite(user_buffers_[index].get(), len, offset)) 1196 if (entry_.Data()->data_size[index] == new_size)
951 return false; 1197 return;
952 // The buffer is deleted from the PostWrite operation. 1198
953 ignore_result(user_buffers_[index].release()); 1199 unreported_size_[index] += new_size - old_size;
954 } else { 1200 entry_.Data()->data_size[index] = new_size;
955 if (!file->Write(user_buffers_[index].get(), len, offset, NULL, NULL)) 1201 entry_.set_modified();
956 return false;
957 user_buffers_[index].reset(NULL);
958 }
959
960 return true;
961 } 1202 }
962 1203
963 int EntryImpl::InitSparseData() { 1204 int EntryImpl::InitSparseData() {
964 if (sparse_.get()) 1205 if (sparse_.get())
965 return net::OK; 1206 return net::OK;
966 1207
967 // Use a local variable so that sparse_ never goes from 'valid' to NULL. 1208 // Use a local variable so that sparse_ never goes from 'valid' to NULL.
968 scoped_ptr<SparseControl> sparse(new SparseControl(this)); 1209 scoped_ptr<SparseControl> sparse(new SparseControl(this));
969 int result = sparse->Init(); 1210 int result = sparse->Init();
970 if (net::OK == result) 1211 if (net::OK == result)
971 sparse_.swap(sparse); 1212 sparse_.swap(sparse);
972 1213
973 return result; 1214 return result;
974 } 1215 }
975 1216
976 void EntryImpl::SetEntryFlags(uint32 flags) { 1217 void EntryImpl::SetEntryFlags(uint32 flags) {
977 entry_.Data()->flags |= flags; 1218 entry_.Data()->flags |= flags;
978 entry_.set_modified(); 1219 entry_.set_modified();
979 } 1220 }
980 1221
981 uint32 EntryImpl::GetEntryFlags() { 1222 uint32 EntryImpl::GetEntryFlags() {
982 return entry_.Data()->flags; 1223 return entry_.Data()->flags;
983 } 1224 }
984 1225
985 void EntryImpl::GetData(int index, char** buffer, Addr* address) { 1226 void EntryImpl::GetData(int index, char** buffer, Addr* address) {
986 if (user_buffers_[index].get()) { 1227 if (user_buffers_[index].get() && user_buffers_[index]->Size() &&
1228 !user_buffers_[index]->Start()) {
987 // The data is already in memory, just copy it and we're done. 1229 // The data is already in memory, just copy it and we're done.
988 int data_len = entry_.Data()->data_size[index]; 1230 int data_len = entry_.Data()->data_size[index];
989 DCHECK(data_len <= kMaxBlockSize); 1231 if (data_len <= user_buffers_[index]->Size()) {
990 *buffer = new char[data_len]; 1232 DCHECK(!user_buffers_[index]->Start());
991 memcpy(*buffer, user_buffers_[index].get(), data_len); 1233 *buffer = new char[data_len];
992 return; 1234 memcpy(*buffer, user_buffers_[index]->Data(), data_len);
1235 return;
1236 }
993 } 1237 }
994 1238
995 // Bad news: we'd have to read the info from disk so instead we'll just tell 1239 // Bad news: we'd have to read the info from disk so instead we'll just tell
996 // the caller where to read from. 1240 // the caller where to read from.
997 *buffer = NULL; 1241 *buffer = NULL;
998 address->set_value(entry_.Data()->data_addr[index]); 1242 address->set_value(entry_.Data()->data_addr[index]);
999 if (address->is_initialized()) { 1243 if (address->is_initialized()) {
1000 // Prevent us from deleting the block from the backing store. 1244 // Prevent us from deleting the block from the backing store.
1001 backend_->ModifyStorageSize(entry_.Data()->data_size[index] - 1245 backend_->ModifyStorageSize(entry_.Data()->data_size[index] -
1002 unreported_size_[index], 0); 1246 unreported_size_[index], 0);
(...skipping 11 matching lines...) Expand all
1014 Trace("%s 0x%p 0x%x 0x%x", msg, reinterpret_cast<void*>(this), 1258 Trace("%s 0x%p 0x%x 0x%x", msg, reinterpret_cast<void*>(this),
1015 entry_.address().value(), node_.address().value()); 1259 entry_.address().value(), node_.address().value());
1016 1260
1017 Trace(" data: 0x%x 0x%x 0x%x", entry_.Data()->data_addr[0], 1261 Trace(" data: 0x%x 0x%x 0x%x", entry_.Data()->data_addr[0],
1018 entry_.Data()->data_addr[1], entry_.Data()->long_key); 1262 entry_.Data()->data_addr[1], entry_.Data()->long_key);
1019 1263
1020 Trace(" doomed: %d 0x%x", doomed_, dirty); 1264 Trace(" doomed: %d 0x%x", doomed_, dirty);
1021 } 1265 }
1022 1266
1023 } // namespace disk_cache 1267 } // namespace disk_cache
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698