Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / storage / browser / fileapi / file_system_usage_cache.cc
blobf1d3ece46011eb3489a079add1058896a40bfc57
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_util.h"
11 #include "base/pickle.h"
12 #include "base/stl_util.h"
13 #include "base/trace_event/trace_event.h"
14 #include "storage/browser/fileapi/timed_task_helper.h"
16 namespace storage {
18 namespace {
19 const int64 kCloseDelaySeconds = 5;
20 const size_t kMaxHandleCacheSize = 2;
21 } // namespace
23 FileSystemUsageCache::FileSystemUsageCache(
24 base::SequencedTaskRunner* task_runner)
25 : task_runner_(task_runner),
26 weak_factory_(this) {
29 FileSystemUsageCache::~FileSystemUsageCache() {
30 task_runner_ = NULL;
31 CloseCacheFiles();
34 const base::FilePath::CharType FileSystemUsageCache::kUsageFileName[] =
35 FILE_PATH_LITERAL(".usage");
36 const char FileSystemUsageCache::kUsageFileHeader[] = "FSU5";
37 const int FileSystemUsageCache::kUsageFileHeaderSize = 4;
39 // Pickle::{Read,Write}Bool treat bool as int
40 const int FileSystemUsageCache::kUsageFileSize =
41 sizeof(base::Pickle::Header) + FileSystemUsageCache::kUsageFileHeaderSize +
42 sizeof(int) + sizeof(int32) + sizeof(int64); // NOLINT
44 bool FileSystemUsageCache::GetUsage(const base::FilePath& usage_file_path,
45 int64* usage_out) {
46 TRACE_EVENT0("FileSystem", "UsageCache::GetUsage");
47 DCHECK(CalledOnValidThread());
48 DCHECK(usage_out);
49 bool is_valid = true;
50 uint32 dirty = 0;
51 int64 usage = 0;
52 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
53 return false;
54 *usage_out = usage;
55 return true;
58 bool FileSystemUsageCache::GetDirty(const base::FilePath& usage_file_path,
59 uint32* dirty_out) {
60 TRACE_EVENT0("FileSystem", "UsageCache::GetDirty");
61 DCHECK(CalledOnValidThread());
62 DCHECK(dirty_out);
63 bool is_valid = true;
64 uint32 dirty = 0;
65 int64 usage = 0;
66 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
67 return false;
68 *dirty_out = dirty;
69 return true;
72 bool FileSystemUsageCache::IncrementDirty(
73 const base::FilePath& usage_file_path) {
74 TRACE_EVENT0("FileSystem", "UsageCache::IncrementDirty");
75 DCHECK(CalledOnValidThread());
76 bool is_valid = true;
77 uint32 dirty = 0;
78 int64 usage = 0;
79 bool new_handle = !HasCacheFileHandle(usage_file_path);
80 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
81 return false;
83 bool success = Write(usage_file_path, is_valid, dirty + 1, usage);
84 if (success && dirty == 0 && new_handle)
85 FlushFile(usage_file_path);
86 return success;
89 bool FileSystemUsageCache::DecrementDirty(
90 const base::FilePath& usage_file_path) {
91 TRACE_EVENT0("FileSystem", "UsageCache::DecrementDirty");
92 DCHECK(CalledOnValidThread());
93 bool is_valid = true;
94 uint32 dirty = 0;
95 int64 usage = 0;
96 if (!Read(usage_file_path, &is_valid, &dirty, &usage) || dirty == 0)
97 return false;
99 return Write(usage_file_path, is_valid, dirty - 1, usage);
102 bool FileSystemUsageCache::Invalidate(const base::FilePath& usage_file_path) {
103 TRACE_EVENT0("FileSystem", "UsageCache::Invalidate");
104 DCHECK(CalledOnValidThread());
105 bool is_valid = true;
106 uint32 dirty = 0;
107 int64 usage = 0;
108 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
109 return false;
111 return Write(usage_file_path, false, dirty, usage);
114 bool FileSystemUsageCache::IsValid(const base::FilePath& usage_file_path) {
115 TRACE_EVENT0("FileSystem", "UsageCache::IsValid");
116 DCHECK(CalledOnValidThread());
117 bool is_valid = true;
118 uint32 dirty = 0;
119 int64 usage = 0;
120 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
121 return false;
122 return is_valid;
125 bool FileSystemUsageCache::AtomicUpdateUsageByDelta(
126 const base::FilePath& usage_file_path, int64 delta) {
127 TRACE_EVENT0("FileSystem", "UsageCache::AtomicUpdateUsageByDelta");
128 DCHECK(CalledOnValidThread());
129 bool is_valid = true;
130 uint32 dirty = 0;
131 int64 usage = 0;;
132 if (!Read(usage_file_path, &is_valid, &dirty, &usage))
133 return false;
134 return Write(usage_file_path, is_valid, dirty, usage + delta);
137 bool FileSystemUsageCache::UpdateUsage(const base::FilePath& usage_file_path,
138 int64 fs_usage) {
139 TRACE_EVENT0("FileSystem", "UsageCache::UpdateUsage");
140 DCHECK(CalledOnValidThread());
141 return Write(usage_file_path, true, 0, fs_usage);
144 bool FileSystemUsageCache::Exists(const base::FilePath& usage_file_path) {
145 TRACE_EVENT0("FileSystem", "UsageCache::Exists");
146 DCHECK(CalledOnValidThread());
147 return base::PathExists(usage_file_path);
150 bool FileSystemUsageCache::Delete(const base::FilePath& usage_file_path) {
151 TRACE_EVENT0("FileSystem", "UsageCache::Delete");
152 DCHECK(CalledOnValidThread());
153 CloseCacheFiles();
154 return base::DeleteFile(usage_file_path, true);
157 void FileSystemUsageCache::CloseCacheFiles() {
158 TRACE_EVENT0("FileSystem", "UsageCache::CloseCacheFiles");
159 DCHECK(CalledOnValidThread());
160 STLDeleteValues(&cache_files_);
161 timer_.reset();
164 bool FileSystemUsageCache::Read(const base::FilePath& usage_file_path,
165 bool* is_valid,
166 uint32* dirty_out,
167 int64* usage_out) {
168 TRACE_EVENT0("FileSystem", "UsageCache::Read");
169 DCHECK(CalledOnValidThread());
170 DCHECK(is_valid);
171 DCHECK(dirty_out);
172 DCHECK(usage_out);
173 char buffer[kUsageFileSize];
174 const char *header;
175 if (usage_file_path.empty() ||
176 !ReadBytes(usage_file_path, buffer, kUsageFileSize))
177 return false;
178 base::Pickle read_pickle(buffer, kUsageFileSize);
179 base::PickleIterator iter(read_pickle);
180 uint32 dirty = 0;
181 int64 usage = 0;
183 if (!iter.ReadBytes(&header, kUsageFileHeaderSize) ||
184 !iter.ReadBool(is_valid) ||
185 !iter.ReadUInt32(&dirty) ||
186 !iter.ReadInt64(&usage))
187 return false;
189 if (header[0] != kUsageFileHeader[0] ||
190 header[1] != kUsageFileHeader[1] ||
191 header[2] != kUsageFileHeader[2] ||
192 header[3] != kUsageFileHeader[3])
193 return false;
195 *dirty_out = dirty;
196 *usage_out = usage;
197 return true;
200 bool FileSystemUsageCache::Write(const base::FilePath& usage_file_path,
201 bool is_valid,
202 int32 dirty,
203 int64 usage) {
204 TRACE_EVENT0("FileSystem", "UsageCache::Write");
205 DCHECK(CalledOnValidThread());
206 base::Pickle write_pickle;
207 write_pickle.WriteBytes(kUsageFileHeader, kUsageFileHeaderSize);
208 write_pickle.WriteBool(is_valid);
209 write_pickle.WriteUInt32(dirty);
210 write_pickle.WriteInt64(usage);
212 if (!WriteBytes(usage_file_path,
213 static_cast<const char*>(write_pickle.data()),
214 write_pickle.size())) {
215 Delete(usage_file_path);
216 return false;
218 return true;
221 base::File* FileSystemUsageCache::GetFile(const base::FilePath& file_path) {
222 DCHECK(CalledOnValidThread());
223 if (cache_files_.size() >= kMaxHandleCacheSize)
224 CloseCacheFiles();
225 ScheduleCloseTimer();
227 base::File* new_file = NULL;
228 std::pair<CacheFiles::iterator, bool> inserted =
229 cache_files_.insert(std::make_pair(file_path, new_file));
230 if (!inserted.second)
231 return inserted.first->second;
233 new_file = new base::File(file_path,
234 base::File::FLAG_OPEN_ALWAYS |
235 base::File::FLAG_READ |
236 base::File::FLAG_WRITE);
237 if (!new_file->IsValid()) {
238 cache_files_.erase(inserted.first);
239 delete new_file;
240 return NULL;
243 inserted.first->second = new_file;
244 return new_file;
247 bool FileSystemUsageCache::ReadBytes(const base::FilePath& file_path,
248 char* buffer,
249 int64 buffer_size) {
250 DCHECK(CalledOnValidThread());
251 base::File* file = GetFile(file_path);
252 if (!file)
253 return false;
254 return file->Read(0, buffer, buffer_size) == buffer_size;
257 bool FileSystemUsageCache::WriteBytes(const base::FilePath& file_path,
258 const char* buffer,
259 int64 buffer_size) {
260 DCHECK(CalledOnValidThread());
261 base::File* file = GetFile(file_path);
262 if (!file)
263 return false;
264 return file->Write(0, buffer, buffer_size) == buffer_size;
267 bool FileSystemUsageCache::FlushFile(const base::FilePath& file_path) {
268 TRACE_EVENT0("FileSystem", "UsageCache::FlushFile");
269 DCHECK(CalledOnValidThread());
270 base::File* file = GetFile(file_path);
271 if (!file)
272 return false;
273 return file->Flush();
276 void FileSystemUsageCache::ScheduleCloseTimer() {
277 DCHECK(CalledOnValidThread());
278 if (!timer_)
279 timer_.reset(new TimedTaskHelper(task_runner_.get()));
281 if (timer_->IsRunning()) {
282 timer_->Reset();
283 return;
286 timer_->Start(FROM_HERE,
287 base::TimeDelta::FromSeconds(kCloseDelaySeconds),
288 base::Bind(&FileSystemUsageCache::CloseCacheFiles,
289 weak_factory_.GetWeakPtr()));
292 bool FileSystemUsageCache::CalledOnValidThread() {
293 return !task_runner_.get() || task_runner_->RunsTasksOnCurrentThread();
296 bool FileSystemUsageCache::HasCacheFileHandle(const base::FilePath& file_path) {
297 DCHECK(CalledOnValidThread());
298 DCHECK_LE(cache_files_.size(), kMaxHandleCacheSize);
299 return ContainsKey(cache_files_, file_path);
302 } // namespace storage