• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "base/logging.h"
6 #include "base/memory/scoped_ptr.h"
7 #include "base/stl_util.h"
8 #include "net/disk_cache/flash/format.h"
9 #include "net/disk_cache/flash/log_store.h"
10 #include "net/disk_cache/flash/segment.h"
11 #include "net/disk_cache/flash/storage.h"
12 
13 namespace disk_cache {
14 
LogStore(const base::FilePath & path,int32 size)15 LogStore::LogStore(const base::FilePath& path, int32 size)
16     : storage_(path, size),
17       num_segments_(size / kFlashSegmentSize),
18       open_segments_(num_segments_),
19       write_index_(0),
20       current_entry_id_(-1),
21       current_entry_num_bytes_left_to_write_(0),
22       init_(false),
23       closed_(false) {
24   DCHECK(size % kFlashSegmentSize == 0);
25 }
26 
~LogStore()27 LogStore::~LogStore() {
28   DCHECK(!init_ || closed_);
29   STLDeleteElements(&open_segments_);
30 }
31 
Init()32 bool LogStore::Init() {
33   DCHECK(!init_);
34   if (!storage_.Init())
35     return false;
36 
37   // TODO(agayev): Once we start persisting segment metadata to disk, we will
38   // start from where we left off during the last shutdown.
39   scoped_ptr<Segment> segment(new Segment(write_index_, false, &storage_));
40   if (!segment->Init())
41     return false;
42 
43   segment->AddUser();
44   open_segments_[write_index_] = segment.release();
45   init_ = true;
46   return true;
47 }
48 
Close()49 bool LogStore::Close() {
50   DCHECK(init_ && !closed_);
51   open_segments_[write_index_]->ReleaseUser();
52   if (!open_segments_[write_index_]->Close())
53     return false;
54   closed_ = true;
55   return true;
56   // TODO(agayev): persist metadata to disk.
57 }
58 
CreateEntry(int32 size,int32 * id)59 bool LogStore::CreateEntry(int32 size, int32* id) {
60   DCHECK(init_ && !closed_);
61   DCHECK(current_entry_id_ == -1 && size <= disk_cache::kFlashSegmentFreeSpace);
62 
63   // TODO(agayev): Avoid large entries from leaving the segments almost empty.
64   if (!open_segments_[write_index_]->CanHold(size)) {
65     if (!open_segments_[write_index_]->Close())
66       return false;
67 
68     open_segments_[write_index_]->ReleaseUser();
69     if (open_segments_[write_index_]->HasNoUsers()) {
70       delete open_segments_[write_index_];
71       open_segments_[write_index_] = NULL;
72     }
73 
74     write_index_ = GetNextSegmentIndex();
75     scoped_ptr<Segment> segment(new Segment(write_index_, false, &storage_));
76     if (!segment->Init())
77       return false;
78 
79     segment->AddUser();
80     open_segments_[write_index_] = segment.release();
81   }
82 
83   *id = open_segments_[write_index_]->write_offset();
84   open_segments_[write_index_]->StoreOffset(*id);
85   current_entry_id_ = *id;
86   current_entry_num_bytes_left_to_write_ = size;
87   open_entries_.insert(current_entry_id_);
88   return true;
89 }
90 
DeleteEntry(int32 id,int32 size)91 void LogStore::DeleteEntry(int32 id, int32 size) {
92   DCHECK(init_ && !closed_);
93   DCHECK(open_entries_.find(id) == open_entries_.end());
94   // TODO(agayev): Increment the number of dead bytes in the segment metadata
95   // for the segment identified by |index|.
96 }
97 
WriteData(const void * buffer,int32 size)98 bool LogStore::WriteData(const void* buffer, int32 size) {
99   DCHECK(init_ && !closed_);
100   DCHECK(current_entry_id_ != -1 &&
101          size <= current_entry_num_bytes_left_to_write_);
102   if (open_segments_[write_index_]->WriteData(buffer, size)) {
103     current_entry_num_bytes_left_to_write_ -= size;
104     return true;
105   }
106   return false;
107 }
108 
OpenEntry(int32 id)109 bool LogStore::OpenEntry(int32 id) {
110   DCHECK(init_ && !closed_);
111   if (open_entries_.find(id) != open_entries_.end())
112     return false;
113 
114   // Segment is already open.
115   int32 index = id / disk_cache::kFlashSegmentSize;
116   if (open_segments_[index]) {
117     if (!open_segments_[index]->HaveOffset(id))
118       return false;
119     open_segments_[index]->AddUser();
120     open_entries_.insert(id);
121     return true;
122   }
123 
124   // Segment is not open.
125   scoped_ptr<Segment> segment(new Segment(index, true, &storage_));
126   if (!segment->Init() || !segment->HaveOffset(id))
127     return false;
128 
129   segment->AddUser();
130   open_segments_[index] = segment.release();
131   open_entries_.insert(id);
132   return true;
133 }
134 
ReadData(int32 id,void * buffer,int32 size,int32 offset) const135 bool LogStore::ReadData(int32 id, void* buffer, int32 size,
136                                   int32 offset) const {
137   DCHECK(init_ && !closed_);
138   DCHECK(open_entries_.find(id) != open_entries_.end());
139 
140   int32 index = id / disk_cache::kFlashSegmentSize;
141   DCHECK(open_segments_[index] && open_segments_[index]->HaveOffset(id));
142   return open_segments_[index]->ReadData(buffer, size, id + offset);
143 }
144 
CloseEntry(int32 id)145 void LogStore::CloseEntry(int32 id) {
146   DCHECK(init_ && !closed_);
147   std::set<int32>::iterator entry_iter = open_entries_.find(id);
148   DCHECK(entry_iter != open_entries_.end());
149 
150   if (current_entry_id_ != -1) {
151     DCHECK(id == current_entry_id_ && !current_entry_num_bytes_left_to_write_);
152     open_entries_.erase(entry_iter);
153     current_entry_id_ = -1;
154     return;
155   }
156 
157   int32 index = id / disk_cache::kFlashSegmentSize;
158   DCHECK(open_segments_[index]);
159   open_entries_.erase(entry_iter);
160 
161   open_segments_[index]->ReleaseUser();
162   if (open_segments_[index]->HasNoUsers()) {
163     delete open_segments_[index];
164     open_segments_[index] = NULL;
165   }
166 }
167 
GetNextSegmentIndex()168 int32 LogStore::GetNextSegmentIndex() {
169   DCHECK(init_ && !closed_);
170   int32 next_index = (write_index_ + 1) % num_segments_;
171 
172   while (InUse(next_index)) {
173     next_index = (next_index + 1) % num_segments_;
174     DCHECK_NE(next_index, write_index_);
175   }
176   return next_index;
177 }
178 
InUse(int32 index) const179 bool LogStore::InUse(int32 index) const {
180   DCHECK(init_ && !closed_);
181   DCHECK(index >= 0 && index < num_segments_);
182   return open_segments_[index] != NULL;
183 }
184 
185 }  // namespace disk_cache
186