file_system_usage_cache.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  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. #include "storage/browser/file_system/file_system_usage_cache.h"
  5. #include <stddef.h>
  6. #include <stdint.h>
  7. #include <memory>
  8. #include <utility>
  9. #include "base/bind.h"
  10. #include "base/containers/contains.h"
  11. #include "base/files/file_util.h"
  12. #include "base/pickle.h"
  13. #include "base/time/time.h"
  14. #include "base/trace_event/trace_event.h"
  15. namespace storage {
  16. namespace {
  17. constexpr base::TimeDelta kCloseDelay = base::Seconds(5);
  18. const size_t kMaxHandleCacheSize = 2;
  19. } // namespace
  20. FileSystemUsageCache::FileSystemUsageCache(bool is_incognito)
  21. : is_incognito_(is_incognito) {
  22. DETACH_FROM_SEQUENCE(sequence_checker_);
  23. }
  24. FileSystemUsageCache::~FileSystemUsageCache() {
  25. CloseCacheFiles();
  26. }
  27. const base::FilePath::CharType FileSystemUsageCache::kUsageFileName[] =
  28. FILE_PATH_LITERAL(".usage");
  29. const char FileSystemUsageCache::kUsageFileHeader[] = "FSU5";
  30. const size_t FileSystemUsageCache::kUsageFileHeaderSize = 4;
  31. // Pickle::{Read,Write}Bool treat bool as int
  32. const int FileSystemUsageCache::kUsageFileSize =
  33. sizeof(base::Pickle::Header) + FileSystemUsageCache::kUsageFileHeaderSize +
  34. sizeof(int) + sizeof(int32_t) + sizeof(int64_t); // NOLINT
  35. bool FileSystemUsageCache::GetUsage(const base::FilePath& usage_file_path,
  36. int64_t* usage_out) {
  37. TRACE_EVENT0("FileSystem", "UsageCache::GetUsage");
  38. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  39. DCHECK(usage_out);
  40. bool is_valid = true;
  41. uint32_t dirty = 0;
  42. int64_t usage = 0;
  43. if (!Read(usage_file_path, &is_valid, &dirty, &usage))
  44. return false;
  45. *usage_out = usage;
  46. return true;
  47. }
  48. bool FileSystemUsageCache::GetDirty(const base::FilePath& usage_file_path,
  49. uint32_t* dirty_out) {
  50. TRACE_EVENT0("FileSystem", "UsageCache::GetDirty");
  51. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  52. DCHECK(dirty_out);
  53. bool is_valid = true;
  54. uint32_t dirty = 0;
  55. int64_t usage = 0;
  56. if (!Read(usage_file_path, &is_valid, &dirty, &usage))
  57. return false;
  58. *dirty_out = dirty;
  59. return true;
  60. }
  61. bool FileSystemUsageCache::IncrementDirty(
  62. const base::FilePath& usage_file_path) {
  63. TRACE_EVENT0("FileSystem", "UsageCache::IncrementDirty");
  64. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  65. bool is_valid = true;
  66. uint32_t dirty = 0;
  67. int64_t usage = 0;
  68. bool new_handle = !HasCacheFileHandle(usage_file_path);
  69. if (!Read(usage_file_path, &is_valid, &dirty, &usage))
  70. return false;
  71. bool success = Write(usage_file_path, is_valid, dirty + 1, usage);
  72. if (success && dirty == 0 && new_handle)
  73. FlushFile(usage_file_path);
  74. return success;
  75. }
  76. bool FileSystemUsageCache::DecrementDirty(
  77. const base::FilePath& usage_file_path) {
  78. TRACE_EVENT0("FileSystem", "UsageCache::DecrementDirty");
  79. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  80. bool is_valid = true;
  81. uint32_t dirty = 0;
  82. int64_t usage = 0;
  83. if (!Read(usage_file_path, &is_valid, &dirty, &usage) || dirty == 0)
  84. return false;
  85. return Write(usage_file_path, is_valid, dirty - 1, usage);
  86. }
  87. bool FileSystemUsageCache::Invalidate(const base::FilePath& usage_file_path) {
  88. TRACE_EVENT0("FileSystem", "UsageCache::Invalidate");
  89. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  90. bool is_valid = true;
  91. uint32_t dirty = 0;
  92. int64_t usage = 0;
  93. if (!Read(usage_file_path, &is_valid, &dirty, &usage))
  94. return false;
  95. return Write(usage_file_path, false, dirty, usage);
  96. }
  97. bool FileSystemUsageCache::IsValid(const base::FilePath& usage_file_path) {
  98. TRACE_EVENT0("FileSystem", "UsageCache::IsValid");
  99. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  100. bool is_valid = true;
  101. uint32_t dirty = 0;
  102. int64_t usage = 0;
  103. if (!Read(usage_file_path, &is_valid, &dirty, &usage))
  104. return false;
  105. return is_valid;
  106. }
  107. bool FileSystemUsageCache::AtomicUpdateUsageByDelta(
  108. const base::FilePath& usage_file_path,
  109. int64_t delta) {
  110. TRACE_EVENT0("FileSystem", "UsageCache::AtomicUpdateUsageByDelta");
  111. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  112. bool is_valid = true;
  113. uint32_t dirty = 0;
  114. int64_t usage = 0;
  115. if (!Read(usage_file_path, &is_valid, &dirty, &usage))
  116. return false;
  117. return Write(usage_file_path, is_valid, dirty, usage + delta);
  118. }
  119. bool FileSystemUsageCache::UpdateUsage(const base::FilePath& usage_file_path,
  120. int64_t fs_usage) {
  121. TRACE_EVENT0("FileSystem", "UsageCache::UpdateUsage");
  122. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  123. return Write(usage_file_path, true, 0, fs_usage);
  124. }
  125. bool FileSystemUsageCache::Exists(const base::FilePath& usage_file_path) {
  126. TRACE_EVENT0("FileSystem", "UsageCache::Exists");
  127. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  128. if (is_incognito_)
  129. return base::Contains(incognito_usages_, usage_file_path);
  130. return base::PathExists(usage_file_path);
  131. }
  132. bool FileSystemUsageCache::Delete(const base::FilePath& usage_file_path) {
  133. TRACE_EVENT0("FileSystem", "UsageCache::Delete");
  134. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  135. CloseCacheFiles();
  136. if (is_incognito_) {
  137. if (!base::Contains(incognito_usages_, usage_file_path))
  138. return false;
  139. incognito_usages_.erase(incognito_usages_.find(usage_file_path));
  140. return true;
  141. }
  142. return base::DeleteFile(usage_file_path);
  143. }
  144. void FileSystemUsageCache::CloseCacheFiles() {
  145. TRACE_EVENT0("FileSystem", "UsageCache::CloseCacheFiles");
  146. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  147. cache_files_.clear();
  148. timer_.Stop();
  149. }
  150. bool FileSystemUsageCache::Read(const base::FilePath& usage_file_path,
  151. bool* is_valid,
  152. uint32_t* dirty_out,
  153. int64_t* usage_out) {
  154. TRACE_EVENT0("FileSystem", "UsageCache::Read");
  155. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  156. DCHECK(is_valid);
  157. DCHECK(dirty_out);
  158. DCHECK(usage_out);
  159. char buffer[kUsageFileSize];
  160. const char* header;
  161. if (usage_file_path.empty() ||
  162. !ReadBytes(usage_file_path, buffer, kUsageFileSize))
  163. return false;
  164. base::Pickle read_pickle(buffer, kUsageFileSize);
  165. base::PickleIterator iter(read_pickle);
  166. uint32_t dirty = 0;
  167. int64_t usage = 0;
  168. if (!iter.ReadBytes(&header, kUsageFileHeaderSize) ||
  169. !iter.ReadBool(is_valid) || !iter.ReadUInt32(&dirty) ||
  170. !iter.ReadInt64(&usage))
  171. return false;
  172. if (header[0] != kUsageFileHeader[0] || header[1] != kUsageFileHeader[1] ||
  173. header[2] != kUsageFileHeader[2] || header[3] != kUsageFileHeader[3])
  174. return false;
  175. *dirty_out = dirty;
  176. *usage_out = usage;
  177. return true;
  178. }
  179. bool FileSystemUsageCache::Write(const base::FilePath& usage_file_path,
  180. bool is_valid,
  181. int32_t dirty,
  182. int64_t usage) {
  183. TRACE_EVENT0("FileSystem", "UsageCache::Write");
  184. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  185. base::Pickle write_pickle;
  186. write_pickle.WriteBytes(kUsageFileHeader, kUsageFileHeaderSize);
  187. write_pickle.WriteBool(is_valid);
  188. write_pickle.WriteUInt32(dirty);
  189. write_pickle.WriteInt64(usage);
  190. if (!WriteBytes(usage_file_path,
  191. static_cast<const char*>(write_pickle.data()),
  192. write_pickle.size())) {
  193. Delete(usage_file_path);
  194. return false;
  195. }
  196. return true;
  197. }
  198. base::File* FileSystemUsageCache::GetFile(const base::FilePath& file_path) {
  199. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  200. if (is_incognito_) {
  201. NOTREACHED();
  202. return nullptr;
  203. }
  204. if (cache_files_.size() >= kMaxHandleCacheSize)
  205. CloseCacheFiles();
  206. ScheduleCloseTimer();
  207. auto& entry = cache_files_[file_path];
  208. if (entry)
  209. return entry.get();
  210. // Because there are no null entries in cache_files_, the [] inserted a blank
  211. // pointer, so let's populate the cache.
  212. entry = std::make_unique<base::File>(file_path, base::File::FLAG_OPEN_ALWAYS |
  213. base::File::FLAG_READ |
  214. base::File::FLAG_WRITE);
  215. if (!entry->IsValid()) {
  216. cache_files_.erase(file_path);
  217. return nullptr;
  218. }
  219. return entry.get();
  220. }
  221. bool FileSystemUsageCache::ReadBytes(const base::FilePath& file_path,
  222. char* buffer,
  223. int64_t buffer_size) {
  224. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  225. if (is_incognito_) {
  226. if (!base::Contains(incognito_usages_, file_path))
  227. return false;
  228. memcpy(buffer, incognito_usages_[file_path].data(), buffer_size);
  229. return true;
  230. }
  231. base::File* file = GetFile(file_path);
  232. if (!file)
  233. return false;
  234. return file->Read(0, buffer, buffer_size) == buffer_size;
  235. }
  236. bool FileSystemUsageCache::WriteBytes(const base::FilePath& file_path,
  237. const char* buffer,
  238. int64_t buffer_size) {
  239. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  240. if (is_incognito_) {
  241. if (!base::Contains(incognito_usages_, file_path))
  242. incognito_usages_[file_path] = std::vector<uint8_t>(buffer_size);
  243. memcpy(incognito_usages_[file_path].data(), buffer, buffer_size);
  244. return true;
  245. }
  246. base::File* file = GetFile(file_path);
  247. if (!file)
  248. return false;
  249. return file->Write(0, buffer, buffer_size) == buffer_size;
  250. }
  251. bool FileSystemUsageCache::FlushFile(const base::FilePath& file_path) {
  252. TRACE_EVENT0("FileSystem", "UsageCache::FlushFile");
  253. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  254. if (is_incognito_)
  255. return base::Contains(incognito_usages_, file_path);
  256. base::File* file = GetFile(file_path);
  257. if (!file)
  258. return false;
  259. return file->Flush();
  260. }
  261. void FileSystemUsageCache::ScheduleCloseTimer() {
  262. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  263. // This will restart the timer if it is already running.
  264. timer_.Start(FROM_HERE, kCloseDelay, this,
  265. &FileSystemUsageCache::CloseCacheFiles);
  266. }
  267. bool FileSystemUsageCache::HasCacheFileHandle(const base::FilePath& file_path) {
  268. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  269. DCHECK_LE(cache_files_.size(), kMaxHandleCacheSize);
  270. return base::Contains(cache_files_, file_path);
  271. }
  272. } // namespace storage