simple_file_tracker_unittest.cc 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. // Copyright (c) 2017 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 <memory>
  5. #include <string>
  6. #include "base/files/file.h"
  7. #include "base/files/file_path.h"
  8. #include "base/files/file_util.h"
  9. #include "base/strings/string_number_conversions.h"
  10. #include "base/strings/string_piece.h"
  11. #include "base/strings/string_util.h"
  12. #include "base/test/metrics/histogram_tester.h"
  13. #include "net/base/cache_type.h"
  14. #include "net/disk_cache/disk_cache.h"
  15. #include "net/disk_cache/disk_cache_test_base.h"
  16. #include "net/disk_cache/simple/simple_file_tracker.h"
  17. #include "net/disk_cache/simple/simple_histogram_enums.h"
  18. #include "net/disk_cache/simple/simple_synchronous_entry.h"
  19. #include "testing/gtest/include/gtest/gtest.h"
  20. namespace disk_cache {
  21. class SimpleFileTrackerTest : public DiskCacheTest {
  22. public:
  23. void DeleteSyncEntry(SimpleSynchronousEntry* entry) { delete entry; }
  24. // We limit open files to 4 for the fixture, as this is large enough
  25. // that simple tests don't have to worry about naming files normally,
  26. // but small enough to test with easily.
  27. static const int kFileLimit = 4;
  28. protected:
  29. SimpleFileTrackerTest() : file_tracker_(kFileLimit) {}
  30. // A bit of messiness since we rely on friendship of the fixture to be able to
  31. // create/delete SimpleSynchronousEntry objects.
  32. class SyncEntryDeleter {
  33. public:
  34. explicit SyncEntryDeleter(SimpleFileTrackerTest* fixture)
  35. : fixture_(fixture) {}
  36. void operator()(SimpleSynchronousEntry* entry) {
  37. fixture_->DeleteSyncEntry(entry);
  38. }
  39. private:
  40. SimpleFileTrackerTest* fixture_;
  41. };
  42. using SyncEntryPointer =
  43. std::unique_ptr<SimpleSynchronousEntry, SyncEntryDeleter>;
  44. SyncEntryPointer MakeSyncEntry(uint64_t hash) {
  45. return SyncEntryPointer(
  46. new SimpleSynchronousEntry(
  47. net::DISK_CACHE, cache_path_, "dummy", hash, &file_tracker_,
  48. base::MakeRefCounted<disk_cache::TrivialFileOperationsFactory>()
  49. ->CreateUnbound(),
  50. /*stream_0_size=*/-1),
  51. SyncEntryDeleter(this));
  52. }
  53. void UpdateEntryFileKey(SimpleSynchronousEntry* sync_entry,
  54. SimpleFileTracker::EntryFileKey file_key) {
  55. sync_entry->entry_file_key_ = file_key;
  56. }
  57. SimpleFileTracker file_tracker_;
  58. };
  59. TEST_F(SimpleFileTrackerTest, Basic) {
  60. SyncEntryPointer entry = MakeSyncEntry(1);
  61. TrivialFileOperations ops;
  62. // Just transfer some files to the tracker, and then do some I/O on getting
  63. // them back.
  64. base::FilePath path_0 = cache_path_.AppendASCII("file_0");
  65. base::FilePath path_1 = cache_path_.AppendASCII("file_1");
  66. std::unique_ptr<base::File> file_0 = std::make_unique<base::File>(
  67. path_0, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  68. std::unique_ptr<base::File> file_1 = std::make_unique<base::File>(
  69. path_1, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  70. ASSERT_TRUE(file_0->IsValid());
  71. ASSERT_TRUE(file_1->IsValid());
  72. file_tracker_.Register(entry.get(), SimpleFileTracker::SubFile::FILE_0,
  73. std::move(file_0));
  74. file_tracker_.Register(entry.get(), SimpleFileTracker::SubFile::FILE_1,
  75. std::move(file_1));
  76. base::StringPiece msg_0 = "Hello";
  77. base::StringPiece msg_1 = "Worldish Place";
  78. {
  79. SimpleFileTracker::FileHandle borrow_0 = file_tracker_.Acquire(
  80. &ops, entry.get(), SimpleFileTracker::SubFile::FILE_0);
  81. SimpleFileTracker::FileHandle borrow_1 = file_tracker_.Acquire(
  82. &ops, entry.get(), SimpleFileTracker::SubFile::FILE_1);
  83. EXPECT_EQ(static_cast<int>(msg_0.size()),
  84. borrow_0->Write(0, msg_0.data(), msg_0.size()));
  85. EXPECT_EQ(static_cast<int>(msg_1.size()),
  86. borrow_1->Write(0, msg_1.data(), msg_1.size()));
  87. // For stream 0 do release/close, for stream 1 do close/release --- where
  88. // release happens when borrow_{0,1} go out of scope
  89. file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_1);
  90. }
  91. file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_0);
  92. // Verify contents.
  93. std::string verify_0, verify_1;
  94. EXPECT_TRUE(ReadFileToString(path_0, &verify_0));
  95. EXPECT_TRUE(ReadFileToString(path_1, &verify_1));
  96. EXPECT_EQ(msg_0, verify_0);
  97. EXPECT_EQ(msg_1, verify_1);
  98. EXPECT_TRUE(file_tracker_.IsEmptyForTesting());
  99. }
  100. TEST_F(SimpleFileTrackerTest, Collision) {
  101. // Two entries with same key.
  102. SyncEntryPointer entry = MakeSyncEntry(1);
  103. SyncEntryPointer entry2 = MakeSyncEntry(1);
  104. TrivialFileOperations ops;
  105. base::FilePath path = cache_path_.AppendASCII("file");
  106. base::FilePath path2 = cache_path_.AppendASCII("file2");
  107. std::unique_ptr<base::File> file = std::make_unique<base::File>(
  108. path, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  109. std::unique_ptr<base::File> file2 = std::make_unique<base::File>(
  110. path2, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  111. ASSERT_TRUE(file->IsValid());
  112. ASSERT_TRUE(file2->IsValid());
  113. file_tracker_.Register(entry.get(), SimpleFileTracker::SubFile::FILE_0,
  114. std::move(file));
  115. file_tracker_.Register(entry2.get(), SimpleFileTracker::SubFile::FILE_0,
  116. std::move(file2));
  117. base::StringPiece msg = "Alpha";
  118. base::StringPiece msg2 = "Beta";
  119. {
  120. SimpleFileTracker::FileHandle borrow = file_tracker_.Acquire(
  121. &ops, entry.get(), SimpleFileTracker::SubFile::FILE_0);
  122. SimpleFileTracker::FileHandle borrow2 = file_tracker_.Acquire(
  123. &ops, entry2.get(), SimpleFileTracker::SubFile::FILE_0);
  124. EXPECT_EQ(static_cast<int>(msg.size()),
  125. borrow->Write(0, msg.data(), msg.size()));
  126. EXPECT_EQ(static_cast<int>(msg2.size()),
  127. borrow2->Write(0, msg2.data(), msg2.size()));
  128. }
  129. file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_0);
  130. file_tracker_.Close(entry2.get(), SimpleFileTracker::SubFile::FILE_0);
  131. // Verify contents.
  132. std::string verify, verify2;
  133. EXPECT_TRUE(ReadFileToString(path, &verify));
  134. EXPECT_TRUE(ReadFileToString(path2, &verify2));
  135. EXPECT_EQ(msg, verify);
  136. EXPECT_EQ(msg2, verify2);
  137. EXPECT_TRUE(file_tracker_.IsEmptyForTesting());
  138. }
  139. TEST_F(SimpleFileTrackerTest, Reopen) {
  140. // We may sometimes go Register -> Close -> Register, with info still
  141. // alive.
  142. SyncEntryPointer entry = MakeSyncEntry(1);
  143. base::FilePath path_0 = cache_path_.AppendASCII("file_0");
  144. base::FilePath path_1 = cache_path_.AppendASCII("file_1");
  145. std::unique_ptr<base::File> file_0 = std::make_unique<base::File>(
  146. path_0, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  147. std::unique_ptr<base::File> file_1 = std::make_unique<base::File>(
  148. path_1, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  149. ASSERT_TRUE(file_0->IsValid());
  150. ASSERT_TRUE(file_1->IsValid());
  151. file_tracker_.Register(entry.get(), SimpleFileTracker::SubFile::FILE_0,
  152. std::move(file_0));
  153. file_tracker_.Register(entry.get(), SimpleFileTracker::SubFile::FILE_1,
  154. std::move(file_1));
  155. file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_1);
  156. std::unique_ptr<base::File> file_1b = std::make_unique<base::File>(
  157. path_1, base::File::FLAG_OPEN | base::File::FLAG_WRITE);
  158. ASSERT_TRUE(file_1b->IsValid());
  159. file_tracker_.Register(entry.get(), SimpleFileTracker::SubFile::FILE_1,
  160. std::move(file_1b));
  161. file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_0);
  162. file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_1);
  163. EXPECT_TRUE(file_tracker_.IsEmptyForTesting());
  164. }
  165. TEST_F(SimpleFileTrackerTest, PointerStability) {
  166. // Make sure the FileHandle lent out doesn't get screwed up as we update
  167. // the state (and potentially move the underlying base::File object around).
  168. const int kEntries = 8;
  169. SyncEntryPointer entries[kEntries] = {
  170. MakeSyncEntry(1), MakeSyncEntry(1), MakeSyncEntry(1), MakeSyncEntry(1),
  171. MakeSyncEntry(1), MakeSyncEntry(1), MakeSyncEntry(1), MakeSyncEntry(1),
  172. };
  173. TrivialFileOperations ops;
  174. std::unique_ptr<base::File> file_0 = std::make_unique<base::File>(
  175. cache_path_.AppendASCII("0"),
  176. base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  177. ASSERT_TRUE(file_0->IsValid());
  178. file_tracker_.Register(entries[0].get(), SimpleFileTracker::SubFile::FILE_0,
  179. std::move(file_0));
  180. base::StringPiece msg = "Message to write";
  181. {
  182. SimpleFileTracker::FileHandle borrow = file_tracker_.Acquire(
  183. &ops, entries[0].get(), SimpleFileTracker::SubFile::FILE_0);
  184. for (int i = 1; i < kEntries; ++i) {
  185. std::unique_ptr<base::File> file_n = std::make_unique<base::File>(
  186. cache_path_.AppendASCII(base::NumberToString(i)),
  187. base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  188. ASSERT_TRUE(file_n->IsValid());
  189. file_tracker_.Register(entries[i].get(),
  190. SimpleFileTracker::SubFile::FILE_0,
  191. std::move(file_n));
  192. }
  193. EXPECT_EQ(static_cast<int>(msg.size()),
  194. borrow->Write(0, msg.data(), msg.size()));
  195. }
  196. for (const auto& entry : entries)
  197. file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_0);
  198. // Verify the file.
  199. std::string verify;
  200. EXPECT_TRUE(ReadFileToString(cache_path_.AppendASCII("0"), &verify));
  201. EXPECT_EQ(msg, verify);
  202. EXPECT_TRUE(file_tracker_.IsEmptyForTesting());
  203. }
  204. TEST_F(SimpleFileTrackerTest, Doom) {
  205. SyncEntryPointer entry1 = MakeSyncEntry(1);
  206. base::FilePath path1 = cache_path_.AppendASCII("file1");
  207. std::unique_ptr<base::File> file1 = std::make_unique<base::File>(
  208. path1, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  209. ASSERT_TRUE(file1->IsValid());
  210. file_tracker_.Register(entry1.get(), SimpleFileTracker::SubFile::FILE_0,
  211. std::move(file1));
  212. SimpleFileTracker::EntryFileKey key1 = entry1->entry_file_key();
  213. file_tracker_.Doom(entry1.get(), &key1);
  214. EXPECT_NE(0u, key1.doom_generation);
  215. // Other entry with same key.
  216. SyncEntryPointer entry2 = MakeSyncEntry(1);
  217. base::FilePath path2 = cache_path_.AppendASCII("file2");
  218. std::unique_ptr<base::File> file2 = std::make_unique<base::File>(
  219. path2, base::File::FLAG_CREATE | base::File::FLAG_WRITE);
  220. ASSERT_TRUE(file2->IsValid());
  221. file_tracker_.Register(entry2.get(), SimpleFileTracker::SubFile::FILE_0,
  222. std::move(file2));
  223. SimpleFileTracker::EntryFileKey key2 = entry2->entry_file_key();
  224. file_tracker_.Doom(entry2.get(), &key2);
  225. EXPECT_NE(0u, key2.doom_generation);
  226. EXPECT_NE(key1.doom_generation, key2.doom_generation);
  227. file_tracker_.Close(entry1.get(), SimpleFileTracker::SubFile::FILE_0);
  228. file_tracker_.Close(entry2.get(), SimpleFileTracker::SubFile::FILE_0);
  229. }
  230. TEST_F(SimpleFileTrackerTest, OverLimit) {
  231. base::HistogramTester histogram_tester;
  232. const int kEntries = 10; // want more than FD limit in fixture.
  233. std::vector<SyncEntryPointer> entries;
  234. std::vector<base::FilePath> names;
  235. TrivialFileOperations ops;
  236. for (int i = 0; i < kEntries; ++i) {
  237. SyncEntryPointer entry = MakeSyncEntry(i);
  238. base::FilePath name =
  239. entry->GetFilenameForSubfile(SimpleFileTracker::SubFile::FILE_0);
  240. std::unique_ptr<base::File> file = std::make_unique<base::File>(
  241. name, base::File::FLAG_CREATE | base::File::FLAG_WRITE |
  242. base::File::FLAG_READ);
  243. ASSERT_TRUE(file->IsValid());
  244. file_tracker_.Register(entry.get(), SimpleFileTracker::SubFile::FILE_0,
  245. std::move(file));
  246. entries.push_back(std::move(entry));
  247. names.push_back(name);
  248. }
  249. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  250. disk_cache::FD_LIMIT_CLOSE_FILE,
  251. kEntries - kFileLimit);
  252. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  253. disk_cache::FD_LIMIT_REOPEN_FILE, 0);
  254. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  255. disk_cache::FD_LIMIT_FAIL_REOPEN_FILE, 0);
  256. // Grab the last one; we will hold it open till the end of the test. It's
  257. // still open, so no change in stats after.
  258. SimpleFileTracker::FileHandle borrow_last = file_tracker_.Acquire(
  259. &ops, entries[kEntries - 1].get(), SimpleFileTracker::SubFile::FILE_0);
  260. EXPECT_EQ(1, borrow_last->Write(0, "L", 1));
  261. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  262. disk_cache::FD_LIMIT_CLOSE_FILE,
  263. kEntries - kFileLimit);
  264. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  265. disk_cache::FD_LIMIT_REOPEN_FILE, 0);
  266. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  267. disk_cache::FD_LIMIT_FAIL_REOPEN_FILE, 0);
  268. // Delete file for [2], to cause error on its re-open.
  269. EXPECT_TRUE(base::DeleteFile(names[2])) << names[2];
  270. // Reacquire all the other files.
  271. for (int i = 0; i < kEntries - 1; ++i) {
  272. SimpleFileTracker::FileHandle borrow = file_tracker_.Acquire(
  273. &ops, entries[i].get(), SimpleFileTracker::SubFile::FILE_0);
  274. if (i != 2) {
  275. EXPECT_TRUE(borrow.IsOK());
  276. char c = static_cast<char>(i);
  277. EXPECT_EQ(1, borrow->Write(0, &c, 1));
  278. } else {
  279. EXPECT_FALSE(borrow.IsOK());
  280. }
  281. }
  282. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  283. disk_cache::FD_LIMIT_CLOSE_FILE,
  284. kEntries - kFileLimit + kEntries - 2);
  285. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  286. disk_cache::FD_LIMIT_REOPEN_FILE,
  287. kEntries - 2);
  288. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  289. disk_cache::FD_LIMIT_FAIL_REOPEN_FILE, 1);
  290. // Doom file for [1].
  291. SimpleFileTracker::EntryFileKey key = entries[1]->entry_file_key();
  292. file_tracker_.Doom(entries[1].get(), &key);
  293. base::FilePath old_path = names[1];
  294. UpdateEntryFileKey(entries[1].get(), key);
  295. base::FilePath new_path =
  296. entries[1]->GetFilenameForSubfile(SimpleFileTracker::SubFile::FILE_0);
  297. EXPECT_TRUE(base::StartsWith(new_path.BaseName().MaybeAsASCII(), "todelete_",
  298. base::CompareCase::SENSITIVE));
  299. EXPECT_TRUE(base::Move(old_path, new_path));
  300. // Now re-acquire everything again; this time reading.
  301. for (int i = 0; i < kEntries - 1; ++i) {
  302. SimpleFileTracker::FileHandle borrow = file_tracker_.Acquire(
  303. &ops, entries[i].get(), SimpleFileTracker::SubFile::FILE_0);
  304. char read;
  305. char expected = static_cast<char>(i);
  306. if (i != 2) {
  307. EXPECT_TRUE(borrow.IsOK());
  308. EXPECT_EQ(1, borrow->Read(0, &read, 1));
  309. EXPECT_EQ(expected, read);
  310. } else {
  311. EXPECT_FALSE(borrow.IsOK());
  312. }
  313. }
  314. histogram_tester.ExpectBucketCount(
  315. "SimpleCache.FileDescriptorLimiterAction",
  316. disk_cache::FD_LIMIT_CLOSE_FILE,
  317. kEntries - kFileLimit + 2 * (kEntries - 2));
  318. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  319. disk_cache::FD_LIMIT_REOPEN_FILE,
  320. 2 * (kEntries - 2));
  321. histogram_tester.ExpectBucketCount("SimpleCache.FileDescriptorLimiterAction",
  322. disk_cache::FD_LIMIT_FAIL_REOPEN_FILE, 2);
  323. // Read from the last one, too. Should still be fine.
  324. char read;
  325. EXPECT_EQ(1, borrow_last->Read(0, &read, 1));
  326. EXPECT_EQ('L', read);
  327. for (const auto& entry : entries)
  328. file_tracker_.Close(entry.get(), SimpleFileTracker::SubFile::FILE_0);
  329. }
  330. } // namespace disk_cache