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.
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"
13 namespace disk_cache {
15 LogStore::LogStore(const base::FilePath& path, int32 size)
16 : storage_(path, size),
17 num_segments_(size / kFlashSegmentSize),
18 open_segments_(num_segments_),
20 current_entry_id_(-1),
21 current_entry_num_bytes_left_to_write_(0),
24 DCHECK(size % kFlashSegmentSize == 0);
27 LogStore::~LogStore() {
28 DCHECK(!init_ || closed_);
29 STLDeleteElements(&open_segments_);
32 bool LogStore::Init() {
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_));
44 open_segments_[write_index_] = segment.release();
49 bool LogStore::Close() {
50 DCHECK(init_ && !closed_);
51 open_segments_[write_index_]->ReleaseUser();
52 if (!open_segments_[write_index_]->Close())
56 // TODO(agayev): persist metadata to disk.
59 bool LogStore::CreateEntry(int32 size, int32* id) {
60 DCHECK(init_ && !closed_);
61 DCHECK(current_entry_id_ == -1 && size <= disk_cache::kFlashSegmentFreeSpace);
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())
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;
74 write_index_ = GetNextSegmentIndex();
75 scoped_ptr<Segment> segment(new Segment(write_index_, false, &storage_));
80 open_segments_[write_index_] = segment.release();
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_);
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|.
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;
109 bool LogStore::OpenEntry(int32 id) {
110 DCHECK(init_ && !closed_);
111 if (open_entries_.find(id) != open_entries_.end())
114 // Segment is already open.
115 int32 index = id / disk_cache::kFlashSegmentSize;
116 if (open_segments_[index]) {
117 if (!open_segments_[index]->HaveOffset(id))
119 open_segments_[index]->AddUser();
120 open_entries_.insert(id);
124 // Segment is not open.
125 scoped_ptr<Segment> segment(new Segment(index, true, &storage_));
126 if (!segment->Init() || !segment->HaveOffset(id))
130 open_segments_[index] = segment.release();
131 open_entries_.insert(id);
135 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());
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);
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());
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;
157 int32 index = id / disk_cache::kFlashSegmentSize;
158 DCHECK(open_segments_[index]);
159 open_entries_.erase(entry_iter);
161 open_segments_[index]->ReleaseUser();
162 if (open_segments_[index]->HasNoUsers()) {
163 delete open_segments_[index];
164 open_segments_[index] = NULL;
168 int32 LogStore::GetNextSegmentIndex() {
169 DCHECK(init_ && !closed_);
170 int32 next_index = (write_index_ + 1) % num_segments_;
172 while (InUse(next_index)) {
173 next_index = (next_index + 1) % num_segments_;
174 DCHECK_NE(next_index, write_index_);
179 bool LogStore::InUse(int32 index) const {
180 DCHECK(init_ && !closed_);
181 DCHECK(index >= 0 && index < num_segments_);
182 return open_segments_[index] != NULL;
185 } // namespace disk_cache