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