1// Copyright (c) 2011 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#ifndef NET_DISK_CACHE_MEM_ENTRY_IMPL_H_
6#define NET_DISK_CACHE_MEM_ENTRY_IMPL_H_
7#pragma once
8
9#include "base/hash_tables.h"
10#include "base/memory/scoped_ptr.h"
11#include "net/base/net_log.h"
12#include "net/disk_cache/disk_cache.h"
13#include "testing/gtest/include/gtest/gtest_prod.h"
14
15namespace disk_cache {
16
17class MemBackendImpl;
18
19// This class implements the Entry interface for the memory-only cache. An
20// object of this class represents a single entry on the cache. We use two
21// types of entries, parent and child to support sparse caching.
22//
23// A parent entry is non-sparse until a sparse method is invoked (i.e.
24// ReadSparseData, WriteSparseData, GetAvailableRange) when sparse information
25// is initialized. It then manages a list of child entries and delegates the
26// sparse API calls to the child entries. It creates and deletes child entries
27// and updates the list when needed.
28//
29// A child entry is used to carry partial cache content, non-sparse methods like
30// ReadData and WriteData cannot be applied to them. The lifetime of a child
31// entry is managed by the parent entry that created it except that the entry
32// can be evicted independently. A child entry does not have a key and it is not
33// registered in the backend's entry map. It is registered in the backend's
34// ranking list to enable eviction of a partial content.
35//
36// A sparse entry has a fixed maximum size and can be partially filled. There
37// can only be one continous filled region in a sparse entry, as illustrated by
38// the following example:
39// | xxx ooooo |
40// x = unfilled region
41// o = filled region
42// It is guranteed that there is at most one unfilled region and one filled
43// region, and the unfilled region (if there is one) is always before the filled
44// region. The book keeping for filled region in a sparse entry is done by using
45// the variable |child_first_pos_| (inclusive).
46
47class MemEntryImpl : public Entry {
48 public:
49  enum EntryType {
50    kParentEntry,
51    kChildEntry,
52  };
53
54  explicit MemEntryImpl(MemBackendImpl* backend);
55
56  // Performs the initialization of a EntryImpl that will be added to the
57  // cache.
58  bool CreateEntry(const std::string& key, net::NetLog* net_log);
59
60  // Permanently destroys this entry.
61  void InternalDoom();
62
63  void Open();
64  bool InUse();
65
66  MemEntryImpl* next() const {
67    return next_;
68  }
69
70  MemEntryImpl* prev() const {
71    return prev_;
72  }
73
74  void set_next(MemEntryImpl* next) {
75    next_ = next;
76  }
77
78  void set_prev(MemEntryImpl* prev) {
79    prev_ = prev;
80  }
81
82  EntryType type() const {
83    return parent_ ? kChildEntry : kParentEntry;
84  }
85
86  std::string& key() {
87    return key_;
88  }
89
90  net::BoundNetLog& net_log() {
91    return net_log_;
92  }
93
94  // Entry interface.
95  virtual void Doom();
96  virtual void Close();
97  virtual std::string GetKey() const;
98  virtual base::Time GetLastUsed() const;
99  virtual base::Time GetLastModified() const;
100  virtual int32 GetDataSize(int index) const;
101  virtual int ReadData(int index, int offset, net::IOBuffer* buf, int buf_len,
102                       net::CompletionCallback* completion_callback);
103  virtual int WriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
104                        net::CompletionCallback* completion_callback,
105                        bool truncate);
106  virtual int ReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
107                             net::CompletionCallback* completion_callback);
108  virtual int WriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len,
109                              net::CompletionCallback* completion_callback);
110  virtual int GetAvailableRange(int64 offset, int len, int64* start,
111                                CompletionCallback* callback);
112  virtual bool CouldBeSparse() const;
113  virtual void CancelSparseIO() {}
114  virtual int ReadyForSparseIO(net::CompletionCallback* completion_callback);
115
116 private:
117  typedef base::hash_map<int, MemEntryImpl*> EntryMap;
118
119  enum {
120    NUM_STREAMS = 3
121  };
122
123  ~MemEntryImpl();
124
125  // Do all the work for corresponding public functions.  Implemented as
126  // separate functions to make logging of results simpler.
127  int InternalReadData(int index, int offset, net::IOBuffer* buf, int buf_len);
128  int InternalWriteData(int index, int offset, net::IOBuffer* buf, int buf_len,
129                        bool truncate);
130  int InternalReadSparseData(int64 offset, net::IOBuffer* buf, int buf_len);
131  int InternalWriteSparseData(int64 offset, net::IOBuffer* buf, int buf_len);
132
133  // Old Entry interface.
134  int GetAvailableRange(int64 offset, int len, int64* start);
135
136  // Grows and cleans up the data buffer.
137  void PrepareTarget(int index, int offset, int buf_len);
138
139  // Updates ranking information.
140  void UpdateRank(bool modified);
141
142  // Initializes the children map and sparse info. This method is only called
143  // on a parent entry.
144  bool InitSparseInfo();
145
146  // Performs the initialization of a MemEntryImpl as a child entry.
147  // |parent| is the pointer to the parent entry. |child_id| is the ID of
148  // the new child.
149  bool InitChildEntry(MemEntryImpl* parent, int child_id, net::NetLog* net_log);
150
151  // Returns an entry responsible for |offset|. The returned entry can be a
152  // child entry or this entry itself if |offset| points to the first range.
153  // If such entry does not exist and |create| is true, a new child entry is
154  // created.
155  MemEntryImpl* OpenChild(int64 offset, bool create);
156
157  // Finds the first child located within the range [|offset|, |offset + len|).
158  // Returns the number of bytes ahead of |offset| to reach the first available
159  // bytes in the entry. The first child found is output to |child|.
160  int FindNextChild(int64 offset, int len, MemEntryImpl** child);
161
162  // Removes child indexed by |child_id| from the children map.
163  void DetachChild(int child_id);
164
165  std::string key_;
166  std::vector<char> data_[NUM_STREAMS];  // User data.
167  int32 data_size_[NUM_STREAMS];
168  int ref_count_;
169
170  int child_id_;              // The ID of a child entry.
171  int child_first_pos_;       // The position of the first byte in a child
172                              // entry.
173  MemEntryImpl* next_;        // Pointers for the LRU list.
174  MemEntryImpl* prev_;
175  MemEntryImpl* parent_;      // Pointer to the parent entry.
176  scoped_ptr<EntryMap> children_;
177
178  base::Time last_modified_;  // LRU information.
179  base::Time last_used_;
180  MemBackendImpl* backend_;   // Back pointer to the cache.
181  bool doomed_;               // True if this entry was removed from the cache.
182
183  net::BoundNetLog net_log_;
184
185  DISALLOW_COPY_AND_ASSIGN(MemEntryImpl);
186};
187
188}  // namespace disk_cache
189
190#endif  // NET_DISK_CACHE_MEM_ENTRY_IMPL_H_
191