- add sources.
[platform/framework/web/crosswalk.git] / src / net / disk_cache / mem_entry_impl.cc
1 // Copyright (c) 2012 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.
4
5 #include "net/disk_cache/mem_entry_impl.h"
6
7 #include "base/bind.h"
8 #include "base/logging.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/values.h"
11 #include "net/base/io_buffer.h"
12 #include "net/base/net_errors.h"
13 #include "net/disk_cache/mem_backend_impl.h"
14 #include "net/disk_cache/net_log_parameters.h"
15
16 using base::Time;
17
18 namespace {
19
20 const int kSparseData = 1;
21
22 // Maximum size of a sparse entry is 2 to the power of this number.
23 const int kMaxSparseEntryBits = 12;
24
25 // Sparse entry has maximum size of 4KB.
26 const int kMaxSparseEntrySize = 1 << kMaxSparseEntryBits;
27
28 // Convert global offset to child index.
29 inline int ToChildIndex(int64 offset) {
30   return static_cast<int>(offset >> kMaxSparseEntryBits);
31 }
32
33 // Convert global offset to offset in child entry.
34 inline int ToChildOffset(int64 offset) {
35   return static_cast<int>(offset & (kMaxSparseEntrySize - 1));
36 }
37
38 // Returns a name for a child entry given the base_name of the parent and the
39 // child_id.  This name is only used for logging purposes.
40 // If the entry is called entry_name, child entries will be named something
41 // like Range_entry_name:YYY where YYY is the number of the particular child.
42 std::string GenerateChildName(const std::string& base_name, int child_id) {
43   return base::StringPrintf("Range_%s:%i", base_name.c_str(), child_id);
44 }
45
46 // Returns NetLog parameters for the creation of a child MemEntryImpl.  Separate
47 // function needed because child entries don't suppport GetKey().
48 base::Value* NetLogChildEntryCreationCallback(
49     const disk_cache::MemEntryImpl* parent,
50     int child_id,
51     net::NetLog::LogLevel /* log_level */) {
52   base::DictionaryValue* dict = new base::DictionaryValue();
53   dict->SetString("key", GenerateChildName(parent->GetKey(), child_id));
54   dict->SetBoolean("created", true);
55   return dict;
56 }
57
58 }  // namespace
59
60 namespace disk_cache {
61
62 MemEntryImpl::MemEntryImpl(MemBackendImpl* backend) {
63   doomed_ = false;
64   backend_ = backend;
65   ref_count_ = 0;
66   parent_ = NULL;
67   child_id_ = 0;
68   child_first_pos_ = 0;
69   next_ = NULL;
70   prev_ = NULL;
71   for (int i = 0; i < NUM_STREAMS; i++)
72     data_size_[i] = 0;
73 }
74
75 // ------------------------------------------------------------------------
76
77 bool MemEntryImpl::CreateEntry(const std::string& key, net::NetLog* net_log) {
78   key_ = key;
79   Time current = Time::Now();
80   last_modified_ = current;
81   last_used_ = current;
82
83   net_log_ = net::BoundNetLog::Make(net_log,
84                                     net::NetLog::SOURCE_MEMORY_CACHE_ENTRY);
85   // Must be called after |key_| is set, so GetKey() works.
86   net_log_.BeginEvent(
87       net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL,
88       CreateNetLogEntryCreationCallback(this, true));
89
90   Open();
91   backend_->ModifyStorageSize(0, static_cast<int32>(key.size()));
92   return true;
93 }
94
95 void MemEntryImpl::InternalDoom() {
96   net_log_.AddEvent(net::NetLog::TYPE_ENTRY_DOOM);
97   doomed_ = true;
98   if (!ref_count_) {
99     if (type() == kParentEntry) {
100       // If this is a parent entry, we need to doom all the child entries.
101       if (children_.get()) {
102         EntryMap children;
103         children.swap(*children_);
104         for (EntryMap::iterator i = children.begin();
105              i != children.end(); ++i) {
106           // Since a pointer to this object is also saved in the map, avoid
107           // dooming it.
108           if (i->second != this)
109             i->second->Doom();
110         }
111         DCHECK(children_->empty());
112       }
113     } else {
114       // If this is a child entry, detach it from the parent.
115       parent_->DetachChild(child_id_);
116     }
117     delete this;
118   }
119 }
120
121 void MemEntryImpl::Open() {
122   // Only a parent entry can be opened.
123   // TODO(hclam): make sure it's correct to not apply the concept of ref
124   // counting to child entry.
125   DCHECK(type() == kParentEntry);
126   ref_count_++;
127   DCHECK_GE(ref_count_, 0);
128   DCHECK(!doomed_);
129 }
130
131 bool MemEntryImpl::InUse() {
132   if (type() == kParentEntry) {
133     return ref_count_ > 0;
134   } else {
135     // A child entry is always not in use. The consequence is that a child entry
136     // can always be evicted while the associated parent entry is currently in
137     // used (i.e. opened).
138     return false;
139   }
140 }
141
142 // ------------------------------------------------------------------------
143
144 void MemEntryImpl::Doom() {
145   if (doomed_)
146     return;
147   if (type() == kParentEntry) {
148     // Perform internal doom from the backend if this is a parent entry.
149     backend_->InternalDoomEntry(this);
150   } else {
151     // Manually detach from the backend and perform internal doom.
152     backend_->RemoveFromRankingList(this);
153     InternalDoom();
154   }
155 }
156
157 void MemEntryImpl::Close() {
158   // Only a parent entry can be closed.
159   DCHECK(type() == kParentEntry);
160   ref_count_--;
161   DCHECK_GE(ref_count_, 0);
162   if (!ref_count_ && doomed_)
163     InternalDoom();
164 }
165
166 std::string MemEntryImpl::GetKey() const {
167   // A child entry doesn't have key so this method should not be called.
168   DCHECK(type() == kParentEntry);
169   return key_;
170 }
171
172 Time MemEntryImpl::GetLastUsed() const {
173   return last_used_;
174 }
175
176 Time MemEntryImpl::GetLastModified() const {
177   return last_modified_;
178 }
179
180 int32 MemEntryImpl::GetDataSize(int index) const {
181   if (index < 0 || index >= NUM_STREAMS)
182     return 0;
183   return data_size_[index];
184 }
185
186 int MemEntryImpl::ReadData(int index, int offset, IOBuffer* buf, int buf_len,
187                            const CompletionCallback& callback) {
188   if (net_log_.IsLoggingAllEvents()) {
189     net_log_.BeginEvent(
190         net::NetLog::TYPE_ENTRY_READ_DATA,
191         CreateNetLogReadWriteDataCallback(index, offset, buf_len, false));
192   }
193
194   int result = InternalReadData(index, offset, buf, buf_len);
195
196   if (net_log_.IsLoggingAllEvents()) {
197     net_log_.EndEvent(
198         net::NetLog::TYPE_ENTRY_READ_DATA,
199         CreateNetLogReadWriteCompleteCallback(result));
200   }
201   return result;
202 }
203
204 int MemEntryImpl::WriteData(int index, int offset, IOBuffer* buf, int buf_len,
205                             const CompletionCallback& callback, bool truncate) {
206   if (net_log_.IsLoggingAllEvents()) {
207     net_log_.BeginEvent(
208         net::NetLog::TYPE_ENTRY_WRITE_DATA,
209         CreateNetLogReadWriteDataCallback(index, offset, buf_len, truncate));
210   }
211
212   int result = InternalWriteData(index, offset, buf, buf_len, truncate);
213
214   if (net_log_.IsLoggingAllEvents()) {
215     net_log_.EndEvent(
216         net::NetLog::TYPE_ENTRY_WRITE_DATA,
217         CreateNetLogReadWriteCompleteCallback(result));
218   }
219   return result;
220 }
221
222 int MemEntryImpl::ReadSparseData(int64 offset, IOBuffer* buf, int buf_len,
223                                  const CompletionCallback& callback) {
224   if (net_log_.IsLoggingAllEvents()) {
225     net_log_.BeginEvent(
226         net::NetLog::TYPE_SPARSE_READ,
227         CreateNetLogSparseOperationCallback(offset, buf_len));
228   }
229   int result = InternalReadSparseData(offset, buf, buf_len);
230   if (net_log_.IsLoggingAllEvents())
231     net_log_.EndEvent(net::NetLog::TYPE_SPARSE_READ);
232   return result;
233 }
234
235 int MemEntryImpl::WriteSparseData(int64 offset, IOBuffer* buf, int buf_len,
236                                   const CompletionCallback& callback) {
237   if (net_log_.IsLoggingAllEvents()) {
238     net_log_.BeginEvent(
239         net::NetLog::TYPE_SPARSE_WRITE,
240         CreateNetLogSparseOperationCallback(offset, buf_len));
241   }
242   int result = InternalWriteSparseData(offset, buf, buf_len);
243   if (net_log_.IsLoggingAllEvents())
244     net_log_.EndEvent(net::NetLog::TYPE_SPARSE_WRITE);
245   return result;
246 }
247
248 int MemEntryImpl::GetAvailableRange(int64 offset, int len, int64* start,
249                                     const CompletionCallback& callback) {
250   if (net_log_.IsLoggingAllEvents()) {
251     net_log_.BeginEvent(
252         net::NetLog::TYPE_SPARSE_GET_RANGE,
253         CreateNetLogSparseOperationCallback(offset, len));
254   }
255   int result = GetAvailableRange(offset, len, start);
256   if (net_log_.IsLoggingAllEvents()) {
257     net_log_.EndEvent(
258         net::NetLog::TYPE_SPARSE_GET_RANGE,
259         CreateNetLogGetAvailableRangeResultCallback(*start, result));
260   }
261   return result;
262 }
263
264 bool MemEntryImpl::CouldBeSparse() const {
265   DCHECK_EQ(kParentEntry, type());
266   return (children_.get() != NULL);
267 }
268
269 int MemEntryImpl::ReadyForSparseIO(const CompletionCallback& callback) {
270   return net::OK;
271 }
272
273 // ------------------------------------------------------------------------
274
275 MemEntryImpl::~MemEntryImpl() {
276   for (int i = 0; i < NUM_STREAMS; i++)
277     backend_->ModifyStorageSize(data_size_[i], 0);
278   backend_->ModifyStorageSize(static_cast<int32>(key_.size()), 0);
279   net_log_.EndEvent(net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL);
280 }
281
282 int MemEntryImpl::InternalReadData(int index, int offset, IOBuffer* buf,
283                                    int buf_len) {
284   DCHECK(type() == kParentEntry || index == kSparseData);
285
286   if (index < 0 || index >= NUM_STREAMS)
287     return net::ERR_INVALID_ARGUMENT;
288
289   int entry_size = GetDataSize(index);
290   if (offset >= entry_size || offset < 0 || !buf_len)
291     return 0;
292
293   if (buf_len < 0)
294     return net::ERR_INVALID_ARGUMENT;
295
296   if (offset + buf_len > entry_size)
297     buf_len = entry_size - offset;
298
299   UpdateRank(false);
300
301   memcpy(buf->data(), &(data_[index])[offset], buf_len);
302   return buf_len;
303 }
304
305 int MemEntryImpl::InternalWriteData(int index, int offset, IOBuffer* buf,
306                                     int buf_len, bool truncate) {
307   DCHECK(type() == kParentEntry || index == kSparseData);
308
309   if (index < 0 || index >= NUM_STREAMS)
310     return net::ERR_INVALID_ARGUMENT;
311
312   if (offset < 0 || buf_len < 0)
313     return net::ERR_INVALID_ARGUMENT;
314
315   int max_file_size = backend_->MaxFileSize();
316
317   // offset of buf_len could be negative numbers.
318   if (offset > max_file_size || buf_len > max_file_size ||
319       offset + buf_len > max_file_size) {
320     return net::ERR_FAILED;
321   }
322
323   // Read the size at this point.
324   int entry_size = GetDataSize(index);
325
326   PrepareTarget(index, offset, buf_len);
327
328   if (entry_size < offset + buf_len) {
329     backend_->ModifyStorageSize(entry_size, offset + buf_len);
330     data_size_[index] = offset + buf_len;
331   } else if (truncate) {
332     if (entry_size > offset + buf_len) {
333       backend_->ModifyStorageSize(entry_size, offset + buf_len);
334       data_size_[index] = offset + buf_len;
335     }
336   }
337
338   UpdateRank(true);
339
340   if (!buf_len)
341     return 0;
342
343   memcpy(&(data_[index])[offset], buf->data(), buf_len);
344   return buf_len;
345 }
346
347 int MemEntryImpl::InternalReadSparseData(int64 offset, IOBuffer* buf,
348                                          int buf_len) {
349   DCHECK(type() == kParentEntry);
350
351   if (!InitSparseInfo())
352     return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
353
354   if (offset < 0 || buf_len < 0)
355     return net::ERR_INVALID_ARGUMENT;
356
357   // We will keep using this buffer and adjust the offset in this buffer.
358   scoped_refptr<net::DrainableIOBuffer> io_buf(
359       new net::DrainableIOBuffer(buf, buf_len));
360
361   // Iterate until we have read enough.
362   while (io_buf->BytesRemaining()) {
363     MemEntryImpl* child = OpenChild(offset + io_buf->BytesConsumed(), false);
364
365     // No child present for that offset.
366     if (!child)
367       break;
368
369     // We then need to prepare the child offset and len.
370     int child_offset = ToChildOffset(offset + io_buf->BytesConsumed());
371
372     // If we are trying to read from a position that the child entry has no data
373     // we should stop.
374     if (child_offset < child->child_first_pos_)
375       break;
376     if (net_log_.IsLoggingAllEvents()) {
377       net_log_.BeginEvent(
378           net::NetLog::TYPE_SPARSE_READ_CHILD_DATA,
379           CreateNetLogSparseReadWriteCallback(child->net_log().source(),
380                                               io_buf->BytesRemaining()));
381     }
382     int ret = child->ReadData(kSparseData, child_offset, io_buf.get(),
383                               io_buf->BytesRemaining(), CompletionCallback());
384     if (net_log_.IsLoggingAllEvents()) {
385       net_log_.EndEventWithNetErrorCode(
386           net::NetLog::TYPE_SPARSE_READ_CHILD_DATA, ret);
387     }
388
389     // If we encounter an error in one entry, return immediately.
390     if (ret < 0)
391       return ret;
392     else if (ret == 0)
393       break;
394
395     // Increment the counter by number of bytes read in the child entry.
396     io_buf->DidConsume(ret);
397   }
398
399   UpdateRank(false);
400
401   return io_buf->BytesConsumed();
402 }
403
404 int MemEntryImpl::InternalWriteSparseData(int64 offset, IOBuffer* buf,
405                                           int buf_len) {
406   DCHECK(type() == kParentEntry);
407
408   if (!InitSparseInfo())
409     return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
410
411   if (offset < 0 || buf_len < 0)
412     return net::ERR_INVALID_ARGUMENT;
413
414   scoped_refptr<net::DrainableIOBuffer> io_buf(
415       new net::DrainableIOBuffer(buf, buf_len));
416
417   // This loop walks through child entries continuously starting from |offset|
418   // and writes blocks of data (of maximum size kMaxSparseEntrySize) into each
419   // child entry until all |buf_len| bytes are written. The write operation can
420   // start in the middle of an entry.
421   while (io_buf->BytesRemaining()) {
422     MemEntryImpl* child = OpenChild(offset + io_buf->BytesConsumed(), true);
423     int child_offset = ToChildOffset(offset + io_buf->BytesConsumed());
424
425     // Find the right amount to write, this evaluates the remaining bytes to
426     // write and remaining capacity of this child entry.
427     int write_len = std::min(static_cast<int>(io_buf->BytesRemaining()),
428                              kMaxSparseEntrySize - child_offset);
429
430     // Keep a record of the last byte position (exclusive) in the child.
431     int data_size = child->GetDataSize(kSparseData);
432
433     if (net_log_.IsLoggingAllEvents()) {
434       net_log_.BeginEvent(
435           net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA,
436           CreateNetLogSparseReadWriteCallback(child->net_log().source(),
437                                               write_len));
438     }
439
440     // Always writes to the child entry. This operation may overwrite data
441     // previously written.
442     // TODO(hclam): if there is data in the entry and this write is not
443     // continuous we may want to discard this write.
444     int ret = child->WriteData(kSparseData, child_offset, io_buf.get(),
445                                write_len, CompletionCallback(), true);
446     if (net_log_.IsLoggingAllEvents()) {
447       net_log_.EndEventWithNetErrorCode(
448           net::NetLog::TYPE_SPARSE_WRITE_CHILD_DATA, ret);
449     }
450     if (ret < 0)
451       return ret;
452     else if (ret == 0)
453       break;
454
455     // Keep a record of the first byte position in the child if the write was
456     // not aligned nor continuous. This is to enable witting to the middle
457     // of an entry and still keep track of data off the aligned edge.
458     if (data_size != child_offset)
459       child->child_first_pos_ = child_offset;
460
461     // Adjust the offset in the IO buffer.
462     io_buf->DidConsume(ret);
463   }
464
465   UpdateRank(true);
466
467   return io_buf->BytesConsumed();
468 }
469
470 int MemEntryImpl::GetAvailableRange(int64 offset, int len, int64* start) {
471   DCHECK(type() == kParentEntry);
472   DCHECK(start);
473
474   if (!InitSparseInfo())
475     return net::ERR_CACHE_OPERATION_NOT_SUPPORTED;
476
477   if (offset < 0 || len < 0 || !start)
478     return net::ERR_INVALID_ARGUMENT;
479
480   MemEntryImpl* current_child = NULL;
481
482   // Find the first child and record the number of empty bytes.
483   int empty = FindNextChild(offset, len, &current_child);
484   if (current_child) {
485     *start = offset + empty;
486     len -= empty;
487
488     // Counts the number of continuous bytes.
489     int continuous = 0;
490
491     // This loop scan for continuous bytes.
492     while (len && current_child) {
493       // Number of bytes available in this child.
494       int data_size = current_child->GetDataSize(kSparseData) -
495                       ToChildOffset(*start + continuous);
496       if (data_size > len)
497         data_size = len;
498
499       // We have found more continuous bytes so increment the count. Also
500       // decrement the length we should scan.
501       continuous += data_size;
502       len -= data_size;
503
504       // If the next child is discontinuous, break the loop.
505       if (FindNextChild(*start + continuous, len, &current_child))
506         break;
507     }
508     return continuous;
509   }
510   *start = offset;
511   return 0;
512 }
513
514 void MemEntryImpl::PrepareTarget(int index, int offset, int buf_len) {
515   int entry_size = GetDataSize(index);
516
517   if (entry_size >= offset + buf_len)
518     return;  // Not growing the stored data.
519
520   if (static_cast<int>(data_[index].size()) < offset + buf_len)
521     data_[index].resize(offset + buf_len);
522
523   if (offset <= entry_size)
524     return;  // There is no "hole" on the stored data.
525
526   // Cleanup the hole not written by the user. The point is to avoid returning
527   // random stuff later on.
528   memset(&(data_[index])[entry_size], 0, offset - entry_size);
529 }
530
531 void MemEntryImpl::UpdateRank(bool modified) {
532   Time current = Time::Now();
533   last_used_ = current;
534
535   if (modified)
536     last_modified_ = current;
537
538   if (!doomed_)
539     backend_->UpdateRank(this);
540 }
541
542 bool MemEntryImpl::InitSparseInfo() {
543   DCHECK(type() == kParentEntry);
544
545   if (!children_.get()) {
546     // If we already have some data in sparse stream but we are being
547     // initialized as a sparse entry, we should fail.
548     if (GetDataSize(kSparseData))
549       return false;
550     children_.reset(new EntryMap());
551
552     // The parent entry stores data for the first block, so save this object to
553     // index 0.
554     (*children_)[0] = this;
555   }
556   return true;
557 }
558
559 bool MemEntryImpl::InitChildEntry(MemEntryImpl* parent, int child_id,
560                                   net::NetLog* net_log) {
561   DCHECK(!parent_);
562   DCHECK(!child_id_);
563
564   net_log_ = net::BoundNetLog::Make(net_log,
565                                     net::NetLog::SOURCE_MEMORY_CACHE_ENTRY);
566   net_log_.BeginEvent(
567       net::NetLog::TYPE_DISK_CACHE_MEM_ENTRY_IMPL,
568       base::Bind(&NetLogChildEntryCreationCallback, parent, child_id_));
569
570   parent_ = parent;
571   child_id_ = child_id;
572   Time current = Time::Now();
573   last_modified_ = current;
574   last_used_ = current;
575   // Insert this to the backend's ranking list.
576   backend_->InsertIntoRankingList(this);
577   return true;
578 }
579
580 MemEntryImpl* MemEntryImpl::OpenChild(int64 offset, bool create) {
581   DCHECK(type() == kParentEntry);
582   int index = ToChildIndex(offset);
583   EntryMap::iterator i = children_->find(index);
584   if (i != children_->end()) {
585     return i->second;
586   } else if (create) {
587     MemEntryImpl* child = new MemEntryImpl(backend_);
588     child->InitChildEntry(this, index, net_log_.net_log());
589     (*children_)[index] = child;
590     return child;
591   }
592   return NULL;
593 }
594
595 int MemEntryImpl::FindNextChild(int64 offset, int len, MemEntryImpl** child) {
596   DCHECK(child);
597   *child = NULL;
598   int scanned_len = 0;
599
600   // This loop tries to find the first existing child.
601   while (scanned_len < len) {
602     // This points to the current offset in the child.
603     int current_child_offset = ToChildOffset(offset + scanned_len);
604     MemEntryImpl* current_child = OpenChild(offset + scanned_len, false);
605     if (current_child) {
606       int child_first_pos = current_child->child_first_pos_;
607
608       // This points to the first byte that we should be reading from, we need
609       // to take care of the filled region and the current offset in the child.
610       int first_pos =  std::max(current_child_offset, child_first_pos);
611
612       // If the first byte position we should read from doesn't exceed the
613       // filled region, we have found the first child.
614       if (first_pos < current_child->GetDataSize(kSparseData)) {
615          *child = current_child;
616
617          // We need to advance the scanned length.
618          scanned_len += first_pos - current_child_offset;
619          break;
620       }
621     }
622     scanned_len += kMaxSparseEntrySize - current_child_offset;
623   }
624   return scanned_len;
625 }
626
627 void MemEntryImpl::DetachChild(int child_id) {
628   children_->erase(child_id);
629 }
630
631 }  // namespace disk_cache