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