cache_util.cc 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  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 "net/disk_cache/cache_util.h"
  5. #include <limits>
  6. #include "base/bind.h"
  7. #include "base/files/file_enumerator.h"
  8. #include "base/files/file_path.h"
  9. #include "base/files/file_util.h"
  10. #include "base/files/safe_base_name.h"
  11. #include "base/location.h"
  12. #include "base/metrics/field_trial_params.h"
  13. #include "base/numerics/clamped_math.h"
  14. #include "base/numerics/ostream_operators.h"
  15. #include "base/strings/string_util.h"
  16. #include "base/strings/stringprintf.h"
  17. #include "base/strings/utf_string_conversions.h"
  18. #include "base/task/bind_post_task.h"
  19. #include "base/task/thread_pool.h"
  20. #include "base/threading/sequenced_task_runner_handle.h"
  21. #include "base/threading/thread_restrictions.h"
  22. #include "build/build_config.h"
  23. namespace {
  24. const int kMaxOldFolders = 100;
  25. // Returns a fully qualified name from path and name, using a given name prefix
  26. // and index number. For instance, if the arguments are "/foo", "bar" and 5, it
  27. // will return "/foo/old_bar_005".
  28. base::FilePath GetPrefixedName(const base::FilePath& path,
  29. const base::SafeBaseName& basename,
  30. int index) {
  31. const base::FilePath::StringType filename =
  32. base::StringPrintf(FILE_PATH_LITERAL("old_%" PRFilePath "_%03d"),
  33. basename.path().value().c_str(), index);
  34. return path.Append(filename);
  35. }
  36. base::FilePath GetTempCacheName(const base::FilePath& dirname,
  37. const base::SafeBaseName& basename) {
  38. // We'll attempt to have up to kMaxOldFolders folders for deletion.
  39. for (int i = 0; i < kMaxOldFolders; i++) {
  40. base::FilePath to_delete = GetPrefixedName(dirname, basename, i);
  41. if (!base::PathExists(to_delete))
  42. return to_delete;
  43. }
  44. return base::FilePath();
  45. }
  46. void CleanupTemporaryDirectories(const base::FilePath& path) {
  47. const base::FilePath dirname = path.DirName();
  48. const absl::optional<base::SafeBaseName> basename =
  49. base::SafeBaseName::Create(path);
  50. if (!basename.has_value()) {
  51. return;
  52. }
  53. for (int i = 0; i < kMaxOldFolders; i++) {
  54. base::FilePath to_delete = GetPrefixedName(dirname, *basename, i);
  55. disk_cache::DeleteCache(to_delete, /*remove_folder=*/true);
  56. }
  57. }
  58. bool MoveDirectoryToTemporaryDirectory(const base::FilePath& path) {
  59. const base::FilePath dirname = path.DirName();
  60. const absl::optional<base::SafeBaseName> basename =
  61. base::SafeBaseName::Create(path);
  62. if (!basename.has_value()) {
  63. return false;
  64. }
  65. const base::FilePath destination = GetTempCacheName(dirname, *basename);
  66. if (destination.empty()) {
  67. return false;
  68. }
  69. return disk_cache::MoveCache(path, destination);
  70. }
  71. // In order to process a potentially large number of files, we'll rename the
  72. // cache directory to old_ + original_name + number, (located on the same parent
  73. // directory), and use a worker thread to delete all the files on all the stale
  74. // cache directories. The whole process can still fail if we are not able to
  75. // rename the cache directory (for instance due to a sharing violation), and in
  76. // that case a cache for this profile (on the desired path) cannot be created.
  77. bool CleanupDirectoryInternal(const base::FilePath& path) {
  78. const base::FilePath path_to_pass = path.StripTrailingSeparators();
  79. bool result = MoveDirectoryToTemporaryDirectory(path_to_pass);
  80. base::ThreadPool::PostTask(
  81. FROM_HERE,
  82. {base::MayBlock(), base::TaskPriority::BEST_EFFORT,
  83. base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
  84. base::BindOnce(&CleanupTemporaryDirectories, path_to_pass));
  85. return result;
  86. }
  87. int64_t PreferredCacheSizeInternal(int64_t available) {
  88. using disk_cache::kDefaultCacheSize;
  89. // Return 80% of the available space if there is not enough space to use
  90. // kDefaultCacheSize.
  91. if (available < kDefaultCacheSize * 10 / 8)
  92. return available * 8 / 10;
  93. // Return kDefaultCacheSize if it uses 10% to 80% of the available space.
  94. if (available < kDefaultCacheSize * 10)
  95. return kDefaultCacheSize;
  96. // Return 10% of the available space if the target size
  97. // (2.5 * kDefaultCacheSize) is more than 10%.
  98. if (available < static_cast<int64_t>(kDefaultCacheSize) * 25)
  99. return available / 10;
  100. // Return the target size (2.5 * kDefaultCacheSize) if it uses 10% to 1%
  101. // of the available space.
  102. if (available < static_cast<int64_t>(kDefaultCacheSize) * 250)
  103. return kDefaultCacheSize * 5 / 2;
  104. // Return 1% of the available space.
  105. return available / 100;
  106. }
  107. } // namespace
  108. namespace disk_cache {
  109. const int kDefaultCacheSize = 80 * 1024 * 1024;
  110. const base::Feature kChangeDiskCacheSizeExperiment{
  111. "ChangeDiskCacheSize", base::FEATURE_DISABLED_BY_DEFAULT};
  112. void DeleteCache(const base::FilePath& path, bool remove_folder) {
  113. if (remove_folder) {
  114. if (!base::DeletePathRecursively(path))
  115. LOG(WARNING) << "Unable to delete cache folder.";
  116. return;
  117. }
  118. base::FileEnumerator iter(
  119. path,
  120. /* recursive */ false,
  121. base::FileEnumerator::FILES | base::FileEnumerator::DIRECTORIES);
  122. for (base::FilePath file = iter.Next(); !file.value().empty();
  123. file = iter.Next()) {
  124. if (!base::DeletePathRecursively(file)) {
  125. LOG(WARNING) << "Unable to delete cache.";
  126. return;
  127. }
  128. }
  129. }
  130. void CleanupDirectory(const base::FilePath& path,
  131. base::OnceCallback<void(bool)> callback) {
  132. auto task_runner = base::ThreadPool::CreateSequencedTaskRunner(
  133. {base::MayBlock(), base::TaskPriority::USER_BLOCKING,
  134. base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN});
  135. task_runner->PostTaskAndReplyWithResult(
  136. FROM_HERE, base::BindOnce(CleanupDirectoryInternal, path),
  137. std::move(callback));
  138. }
  139. bool CleanupDirectorySync(const base::FilePath& path) {
  140. base::ScopedAllowBlocking allow_blocking;
  141. return CleanupDirectoryInternal(path);
  142. }
  143. // Returns the preferred maximum number of bytes for the cache given the
  144. // number of available bytes.
  145. int PreferredCacheSize(int64_t available, net::CacheType type) {
  146. // Percent of cache size to use, relative to the default size. "100" means to
  147. // use 100% of the default size.
  148. int percent_relative_size = 100;
  149. if (base::FeatureList::IsEnabled(
  150. disk_cache::kChangeDiskCacheSizeExperiment) &&
  151. type == net::DISK_CACHE) {
  152. percent_relative_size = base::GetFieldTrialParamByFeatureAsInt(
  153. disk_cache::kChangeDiskCacheSizeExperiment, "percent_relative_size",
  154. 100 /* default value */);
  155. }
  156. // Cap scaling, as a safety check, to avoid overflow.
  157. if (percent_relative_size > 400)
  158. percent_relative_size = 400;
  159. else if (percent_relative_size < 100)
  160. percent_relative_size = 100;
  161. base::ClampedNumeric<int64_t> scaled_default_disk_cache_size =
  162. (base::ClampedNumeric<int64_t>(disk_cache::kDefaultCacheSize) *
  163. percent_relative_size) /
  164. 100;
  165. base::ClampedNumeric<int64_t> preferred_cache_size =
  166. scaled_default_disk_cache_size;
  167. // If available disk space is known, use it to compute a better value for
  168. // preferred_cache_size.
  169. if (available >= 0) {
  170. preferred_cache_size = PreferredCacheSizeInternal(available);
  171. // If the preferred cache size is less than 20% of the available space,
  172. // scale for the field trial, capping the scaled value at 20% of the
  173. // available space.
  174. if (preferred_cache_size < available / 5) {
  175. const base::ClampedNumeric<int64_t> clamped_available(available);
  176. preferred_cache_size =
  177. std::min((preferred_cache_size * percent_relative_size) / 100,
  178. clamped_available / 5);
  179. }
  180. }
  181. // Limit cache size to somewhat less than kint32max to avoid potential
  182. // integer overflows in cache backend implementations.
  183. //
  184. // Note: the 4x limit is of course far below that; historically it came
  185. // from the blockfile backend with the following explanation:
  186. // "Let's not use more than the default size while we tune-up the performance
  187. // of bigger caches. "
  188. base::ClampedNumeric<int64_t> size_limit = scaled_default_disk_cache_size * 4;
  189. // Native code entries can be large, so we would like a larger cache.
  190. // Make the size limit 50% larger in that case.
  191. if (type == net::GENERATED_NATIVE_CODE_CACHE) {
  192. size_limit = (size_limit / 2) * 3;
  193. } else if (type == net::GENERATED_WEBUI_BYTE_CODE_CACHE) {
  194. size_limit = std::min(
  195. size_limit, base::ClampedNumeric<int64_t>(kMaxWebUICodeCacheSize));
  196. }
  197. DCHECK_LT(size_limit, std::numeric_limits<int32_t>::max());
  198. return static_cast<int32_t>(std::min(preferred_cache_size, size_limit));
  199. }
  200. } // namespace disk_cache