| OLD | NEW |
| (Empty) |
| 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 | |
| 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 | |
| 27 LogStore::~LogStore() { | |
| 28 DCHECK(!init_ || closed_); | |
| 29 STLDeleteElements(&open_segments_); | |
| 30 } | |
| 31 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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 | |
| 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()); | |
| 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 | |
| 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 | |
| 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 | |
| 179 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 | |
| OLD | NEW |