io_posix_test.cc 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. // Copyright (c) 2020-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. #include "test_util/testharness.h"
  6. #ifdef ROCKSDB_LIB_IO_POSIX
  7. #include "env/io_posix.h"
  8. namespace ROCKSDB_NAMESPACE {
  9. #ifdef OS_LINUX
  10. class LogicalBlockSizeCacheTest : public testing::Test {};
  11. // Tests the caching behavior.
  12. TEST_F(LogicalBlockSizeCacheTest, Cache) {
  13. int ncall = 0;
  14. auto get_fd_block_size = [&](int fd) {
  15. ncall++;
  16. return fd;
  17. };
  18. std::map<std::string, int> dir_fds{
  19. {"/", 0},
  20. {"/db", 1},
  21. {"/db1", 2},
  22. {"/db2", 3},
  23. };
  24. auto get_dir_block_size = [&](const std::string& dir, size_t* size) {
  25. ncall++;
  26. *size = dir_fds[dir];
  27. return Status::OK();
  28. };
  29. LogicalBlockSizeCache cache(get_fd_block_size, get_dir_block_size);
  30. ASSERT_EQ(0, ncall);
  31. ASSERT_EQ(0, cache.Size());
  32. ASSERT_EQ(6, cache.GetLogicalBlockSize("/sst", 6));
  33. ASSERT_EQ(1, ncall);
  34. ASSERT_EQ(7, cache.GetLogicalBlockSize("/db/sst1", 7));
  35. ASSERT_EQ(2, ncall);
  36. ASSERT_EQ(8, cache.GetLogicalBlockSize("/db/sst2", 8));
  37. ASSERT_EQ(3, ncall);
  38. ASSERT_OK(cache.RefAndCacheLogicalBlockSize({"/", "/db1/", "/db2"}));
  39. ASSERT_EQ(3, cache.Size());
  40. ASSERT_TRUE(cache.Contains("/"));
  41. ASSERT_TRUE(cache.Contains("/db1"));
  42. ASSERT_TRUE(cache.Contains("/db2"));
  43. ASSERT_EQ(6, ncall);
  44. // Block size for / is cached.
  45. ASSERT_EQ(0, cache.GetLogicalBlockSize("/sst", 6));
  46. ASSERT_EQ(6, ncall);
  47. // No cached size for /db.
  48. ASSERT_EQ(7, cache.GetLogicalBlockSize("/db/sst1", 7));
  49. ASSERT_EQ(7, ncall);
  50. ASSERT_EQ(8, cache.GetLogicalBlockSize("/db/sst2", 8));
  51. ASSERT_EQ(8, ncall);
  52. // Block size for /db1 is cached.
  53. ASSERT_EQ(2, cache.GetLogicalBlockSize("/db1/sst1", 4));
  54. ASSERT_EQ(8, ncall);
  55. ASSERT_EQ(2, cache.GetLogicalBlockSize("/db1/sst2", 5));
  56. ASSERT_EQ(8, ncall);
  57. // Block size for /db2 is cached.
  58. ASSERT_EQ(3, cache.GetLogicalBlockSize("/db2/sst1", 6));
  59. ASSERT_EQ(8, ncall);
  60. ASSERT_EQ(3, cache.GetLogicalBlockSize("/db2/sst2", 7));
  61. ASSERT_EQ(8, ncall);
  62. ASSERT_OK(cache.RefAndCacheLogicalBlockSize({"/db"}));
  63. ASSERT_EQ(4, cache.Size());
  64. ASSERT_TRUE(cache.Contains("/"));
  65. ASSERT_TRUE(cache.Contains("/db1"));
  66. ASSERT_TRUE(cache.Contains("/db2"));
  67. ASSERT_TRUE(cache.Contains("/db"));
  68. ASSERT_EQ(9, ncall);
  69. // Block size for /db is cached.
  70. ASSERT_EQ(1, cache.GetLogicalBlockSize("/db/sst1", 7));
  71. ASSERT_EQ(9, ncall);
  72. ASSERT_EQ(1, cache.GetLogicalBlockSize("/db/sst2", 8));
  73. ASSERT_EQ(9, ncall);
  74. }
  75. // Tests the reference counting behavior.
  76. TEST_F(LogicalBlockSizeCacheTest, Ref) {
  77. int ncall = 0;
  78. auto get_fd_block_size = [&](int fd) {
  79. ncall++;
  80. return fd;
  81. };
  82. std::map<std::string, int> dir_fds{
  83. {"/db", 0},
  84. };
  85. auto get_dir_block_size = [&](const std::string& dir, size_t* size) {
  86. ncall++;
  87. *size = dir_fds[dir];
  88. return Status::OK();
  89. };
  90. LogicalBlockSizeCache cache(get_fd_block_size, get_dir_block_size);
  91. ASSERT_EQ(0, ncall);
  92. ASSERT_EQ(1, cache.GetLogicalBlockSize("/db/sst0", 1));
  93. ASSERT_EQ(1, ncall);
  94. ASSERT_OK(cache.RefAndCacheLogicalBlockSize({"/db"}));
  95. ASSERT_EQ(2, ncall);
  96. ASSERT_EQ(1, cache.GetRefCount("/db"));
  97. // Block size for /db is cached. Ref count = 1.
  98. ASSERT_EQ(0, cache.GetLogicalBlockSize("/db/sst1", 1));
  99. ASSERT_EQ(2, ncall);
  100. // Ref count = 2, but won't recompute the cached buffer size.
  101. ASSERT_OK(cache.RefAndCacheLogicalBlockSize({"/db"}));
  102. ASSERT_EQ(2, cache.GetRefCount("/db"));
  103. ASSERT_EQ(2, ncall);
  104. // Ref count = 1.
  105. cache.UnrefAndTryRemoveCachedLogicalBlockSize({"/db"});
  106. ASSERT_EQ(1, cache.GetRefCount("/db"));
  107. // Block size for /db is still cached.
  108. ASSERT_EQ(0, cache.GetLogicalBlockSize("/db/sst2", 1));
  109. ASSERT_EQ(2, ncall);
  110. // Ref count = 0 and cached buffer size for /db is removed.
  111. cache.UnrefAndTryRemoveCachedLogicalBlockSize({"/db"});
  112. ASSERT_EQ(0, cache.Size());
  113. ASSERT_EQ(1, cache.GetLogicalBlockSize("/db/sst0", 1));
  114. ASSERT_EQ(3, ncall);
  115. }
  116. #endif
  117. } // namespace ROCKSDB_NAMESPACE
  118. #endif
  119. int main(int argc, char** argv) {
  120. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  121. ::testing::InitGoogleTest(&argc, argv);
  122. return RUN_ALL_TESTS();
  123. }