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