We started redesigning GpuMemoryBuffer interface to handle multiple buffers [0].
[chromium-blink-merge.git] / storage / browser / fileapi / file_system_usage_cache.cc
blobc6baa7ae1174cc92bd86c2d17e8395116d004271
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 "storage/browser/fileapi/file_system_usage_cache.h"
7 #include <utility>
9 #include "base/bind.h"
10 #include "base/files/file_path.h"
11 #include "base/files/file_util.h"
12 #include "base/pickle.h"
13 #include "base/stl_util.h"
14 #include "base/trace_event/trace_event.h"
15 #include "storage/browser/fileapi/timed_task_helper.h"
17 namespace storage {
19 namespace {
20 const int64 kCloseDelaySeconds = 5;
21 const size_t kMaxHandleCacheSize = 2;
22 } // namespace
24 FileSystemUsageCache::FileSystemUsageCache(
25 base::SequencedTaskRunner* task_runner)
26 : task_runner_(task_runner),
27 weak_factory_(this) {
30 FileSystemUsageCache::~FileSystemUsageCache() {
31 task_runner_ = NULL;
32 CloseCacheFiles();
35 const base::FilePath::CharType FileSystemUsageCache::kUsageFileName[] =
36 FILE_PATH_LITERAL(".usage");
37 const char FileSystemUsageCache::kUsageFileHeader[] = "FSU5";
38 const int FileSystemUsageCache::kUsageFileHeaderSize = 4;
40 // Pickle::{Read,Write}Bool treat bool as int
41 const int FileSystemUsageCache::kUsageFileSize =
42 sizeof(Pickle::Header) +
43 FileSystemUsageCache::kUsageFileHeaderSize +
44 sizeof(int) + sizeof(int32) + sizeof(int64); // NOLINT
46 bool FileSystemUsageCache::GetUsage(const base::FilePath& usage_file_path,
47 int64* usage_out) {
48 TRACE_EVENT0("FileSystem", "UsageCache::GetUsage");
49 DCHECK(CalledOnValidThread());
50 DCHECK(usage_out);
51 bool is_valid = true;
52 uint32 dirty = 0;
53 int64 usage = 0;
54 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
55 return false;
56 *usage_out = usage;
57 return true;
60 bool FileSystemUsageCache::GetDirty(const base::FilePath& usage_file_path,
61 uint32* dirty_out) {
62 TRACE_EVENT0("FileSystem", "UsageCache::GetDirty");
63 DCHECK(CalledOnValidThread());
64 DCHECK(dirty_out);
65 bool is_valid = true;
66 uint32 dirty = 0;
67 int64 usage = 0;
68 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
69 return false;
70 *dirty_out = dirty;
71 return true;
74 bool FileSystemUsageCache::IncrementDirty(
75 const base::FilePath& usage_file_path) {
76 TRACE_EVENT0("FileSystem", "UsageCache::IncrementDirty");
77 DCHECK(CalledOnValidThread());
78 bool is_valid = true;
79 uint32 dirty = 0;
80 int64 usage = 0;
81 bool new_handle = !HasCacheFileHandle(usage_file_path);
82 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
83 return false;
85 bool success = Write(usage_file_path, is_valid, dirty + 1, usage);
86 if (success && dirty == 0 && new_handle)
87 FlushFile(usage_file_path);
88 return success;
91 bool FileSystemUsageCache::DecrementDirty(
92 const base::FilePath& usage_file_path) {
93 TRACE_EVENT0("FileSystem", "UsageCache::DecrementDirty");
94 DCHECK(CalledOnValidThread());
95 bool is_valid = true;
96 uint32 dirty = 0;
97 int64 usage = 0;
98 if (!Read(usage_file_path, &is_valid, &dirty, &usage) || dirty == 0)
99 return false;
101 return Write(usage_file_path, is_valid, dirty - 1, usage);
104 bool FileSystemUsageCache::Invalidate(const base::FilePath& usage_file_path) {
105 TRACE_EVENT0("FileSystem", "UsageCache::Invalidate");
106 DCHECK(CalledOnValidThread());
107 bool is_valid = true;
108 uint32 dirty = 0;
109 int64 usage = 0;
110 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
111 return false;
113 return Write(usage_file_path, false, dirty, usage);
116 bool FileSystemUsageCache::IsValid(const base::FilePath& usage_file_path) {
117 TRACE_EVENT0("FileSystem", "UsageCache::IsValid");
118 DCHECK(CalledOnValidThread());
119 bool is_valid = true;
120 uint32 dirty = 0;
121 int64 usage = 0;
122 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
123 return false;
124 return is_valid;
127 bool FileSystemUsageCache::AtomicUpdateUsageByDelta(
128 const base::FilePath& usage_file_path, int64 delta) {
129 TRACE_EVENT0("FileSystem", "UsageCache::AtomicUpdateUsageByDelta");
130 DCHECK(CalledOnValidThread());
131 bool is_valid = true;
132 uint32 dirty = 0;
133 int64 usage = 0;;
134 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
135 return false;
136 return Write(usage_file_path, is_valid, dirty, usage + delta);
139 bool FileSystemUsageCache::UpdateUsage(const base::FilePath& usage_file_path,
140 int64 fs_usage) {
141 TRACE_EVENT0("FileSystem", "UsageCache::UpdateUsage");
142 DCHECK(CalledOnValidThread());
143 return Write(usage_file_path, true, 0, fs_usage);
146 bool FileSystemUsageCache::Exists(const base::FilePath& usage_file_path) {
147 TRACE_EVENT0("FileSystem", "UsageCache::Exists");
148 DCHECK(CalledOnValidThread());
149 return base::PathExists(usage_file_path);
152 bool FileSystemUsageCache::Delete(const base::FilePath& usage_file_path) {
153 TRACE_EVENT0("FileSystem", "UsageCache::Delete");
154 DCHECK(CalledOnValidThread());
155 CloseCacheFiles();
156 return base::DeleteFile(usage_file_path, true);
159 void FileSystemUsageCache::CloseCacheFiles() {
160 TRACE_EVENT0("FileSystem", "UsageCache::CloseCacheFiles");
161 DCHECK(CalledOnValidThread());
162 STLDeleteValues(&cache_files_);
163 timer_.reset();
166 bool FileSystemUsageCache::Read(const base::FilePath& usage_file_path,
167 bool* is_valid,
168 uint32* dirty_out,
169 int64* usage_out) {
170 TRACE_EVENT0("FileSystem", "UsageCache::Read");
171 DCHECK(CalledOnValidThread());
172 DCHECK(is_valid);
173 DCHECK(dirty_out);
174 DCHECK(usage_out);
175 char buffer[kUsageFileSize];
176 const char *header;
177 if (usage_file_path.empty() ||
178 !ReadBytes(usage_file_path, buffer, kUsageFileSize))
179 return false;
180 Pickle read_pickle(buffer, kUsageFileSize);
181 PickleIterator iter(read_pickle);
182 uint32 dirty = 0;
183 int64 usage = 0;
185 if (!iter.ReadBytes(&header, kUsageFileHeaderSize) ||
186 !iter.ReadBool(is_valid) ||
187 !iter.ReadUInt32(&dirty) ||
188 !iter.ReadInt64(&usage))
189 return false;
191 if (header[0] != kUsageFileHeader[0] ||
192 header[1] != kUsageFileHeader[1] ||
193 header[2] != kUsageFileHeader[2] ||
194 header[3] != kUsageFileHeader[3])
195 return false;
197 *dirty_out = dirty;
198 *usage_out = usage;
199 return true;
202 bool FileSystemUsageCache::Write(const base::FilePath& usage_file_path,
203 bool is_valid,
204 int32 dirty,
205 int64 usage) {
206 TRACE_EVENT0("FileSystem", "UsageCache::Write");
207 DCHECK(CalledOnValidThread());
208 Pickle write_pickle;
209 write_pickle.WriteBytes(kUsageFileHeader, kUsageFileHeaderSize);
210 write_pickle.WriteBool(is_valid);
211 write_pickle.WriteUInt32(dirty);
212 write_pickle.WriteInt64(usage);
214 if (!WriteBytes(usage_file_path,
215 static_cast<const char*>(write_pickle.data()),
216 write_pickle.size())) {
217 Delete(usage_file_path);
218 return false;
220 return true;
223 base::File* FileSystemUsageCache::GetFile(const base::FilePath& file_path) {
224 DCHECK(CalledOnValidThread());
225 if (cache_files_.size() >= kMaxHandleCacheSize)
226 CloseCacheFiles();
227 ScheduleCloseTimer();
229 base::File* new_file = NULL;
230 std::pair<CacheFiles::iterator, bool> inserted =
231 cache_files_.insert(std::make_pair(file_path, new_file));
232 if (!inserted.second)
233 return inserted.first->second;
235 new_file = new base::File(file_path,
236 base::File::FLAG_OPEN_ALWAYS |
237 base::File::FLAG_READ |
238 base::File::FLAG_WRITE);
239 if (!new_file->IsValid()) {
240 cache_files_.erase(inserted.first);
241 delete new_file;
242 return NULL;
245 inserted.first->second = new_file;
246 return new_file;
249 bool FileSystemUsageCache::ReadBytes(const base::FilePath& file_path,
250 char* buffer,
251 int64 buffer_size) {
252 DCHECK(CalledOnValidThread());
253 base::File* file = GetFile(file_path);
254 if (!file)
255 return false;
256 return file->Read(0, buffer, buffer_size) == buffer_size;
259 bool FileSystemUsageCache::WriteBytes(const base::FilePath& file_path,
260 const char* buffer,
261 int64 buffer_size) {
262 DCHECK(CalledOnValidThread());
263 base::File* file = GetFile(file_path);
264 if (!file)
265 return false;
266 return file->Write(0, buffer, buffer_size) == buffer_size;
269 bool FileSystemUsageCache::FlushFile(const base::FilePath& file_path) {
270 TRACE_EVENT0("FileSystem", "UsageCache::FlushFile");
271 DCHECK(CalledOnValidThread());
272 base::File* file = GetFile(file_path);
273 if (!file)
274 return false;
275 return file->Flush();
278 void FileSystemUsageCache::ScheduleCloseTimer() {
279 DCHECK(CalledOnValidThread());
280 if (!timer_)
281 timer_.reset(new TimedTaskHelper(task_runner_.get()));
283 if (timer_->IsRunning()) {
284 timer_->Reset();
285 return;
288 timer_->Start(FROM_HERE,
289 base::TimeDelta::FromSeconds(kCloseDelaySeconds),
290 base::Bind(&FileSystemUsageCache::CloseCacheFiles,
291 weak_factory_.GetWeakPtr()));
294 bool FileSystemUsageCache::CalledOnValidThread() {
295 return !task_runner_.get() || task_runner_->RunsTasksOnCurrentThread();
298 bool FileSystemUsageCache::HasCacheFileHandle(const base::FilePath& file_path) {
299 DCHECK(CalledOnValidThread());
300 DCHECK_LE(cache_files_.size(), kMaxHandleCacheSize);
301 return ContainsKey(cache_files_, file_path);
304 } // namespace storage