- add sources.
[platform/framework/web/crosswalk.git] / src / net / disk_cache / flash / log_store.cc
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