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 186