db_properties_test.cc 63 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711
  1. // Copyright (c) 2011-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. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. #include <stdio.h>
  10. #include <algorithm>
  11. #include <string>
  12. #include "db/db_test_util.h"
  13. #include "port/stack_trace.h"
  14. #include "rocksdb/listener.h"
  15. #include "rocksdb/options.h"
  16. #include "rocksdb/perf_context.h"
  17. #include "rocksdb/perf_level.h"
  18. #include "rocksdb/table.h"
  19. #include "util/random.h"
  20. #include "util/string_util.h"
  21. namespace ROCKSDB_NAMESPACE {
  22. class DBPropertiesTest : public DBTestBase {
  23. public:
  24. DBPropertiesTest() : DBTestBase("/db_properties_test") {}
  25. };
  26. #ifndef ROCKSDB_LITE
  27. TEST_F(DBPropertiesTest, Empty) {
  28. do {
  29. Options options;
  30. options.env = env_;
  31. options.write_buffer_size = 100000; // Small write buffer
  32. options.allow_concurrent_memtable_write = false;
  33. options = CurrentOptions(options);
  34. CreateAndReopenWithCF({"pikachu"}, options);
  35. std::string num;
  36. ASSERT_TRUE(dbfull()->GetProperty(
  37. handles_[1], "rocksdb.num-entries-active-mem-table", &num));
  38. ASSERT_EQ("0", num);
  39. ASSERT_OK(Put(1, "foo", "v1"));
  40. ASSERT_EQ("v1", Get(1, "foo"));
  41. ASSERT_TRUE(dbfull()->GetProperty(
  42. handles_[1], "rocksdb.num-entries-active-mem-table", &num));
  43. ASSERT_EQ("1", num);
  44. // Block sync calls
  45. env_->delay_sstable_sync_.store(true, std::memory_order_release);
  46. Put(1, "k1", std::string(100000, 'x')); // Fill memtable
  47. ASSERT_TRUE(dbfull()->GetProperty(
  48. handles_[1], "rocksdb.num-entries-active-mem-table", &num));
  49. ASSERT_EQ("2", num);
  50. Put(1, "k2", std::string(100000, 'y')); // Trigger compaction
  51. ASSERT_TRUE(dbfull()->GetProperty(
  52. handles_[1], "rocksdb.num-entries-active-mem-table", &num));
  53. ASSERT_EQ("1", num);
  54. ASSERT_EQ("v1", Get(1, "foo"));
  55. // Release sync calls
  56. env_->delay_sstable_sync_.store(false, std::memory_order_release);
  57. ASSERT_OK(db_->DisableFileDeletions());
  58. ASSERT_TRUE(
  59. dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
  60. ASSERT_EQ("0", num);
  61. ASSERT_OK(db_->DisableFileDeletions());
  62. ASSERT_TRUE(
  63. dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
  64. ASSERT_EQ("0", num);
  65. ASSERT_OK(db_->DisableFileDeletions());
  66. ASSERT_TRUE(
  67. dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
  68. ASSERT_EQ("0", num);
  69. ASSERT_OK(db_->EnableFileDeletions(false));
  70. ASSERT_TRUE(
  71. dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
  72. ASSERT_EQ("0", num);
  73. ASSERT_OK(db_->EnableFileDeletions());
  74. ASSERT_TRUE(
  75. dbfull()->GetProperty("rocksdb.is-file-deletions-enabled", &num));
  76. ASSERT_EQ("1", num);
  77. } while (ChangeOptions());
  78. }
  79. TEST_F(DBPropertiesTest, CurrentVersionNumber) {
  80. uint64_t v1, v2, v3;
  81. ASSERT_TRUE(
  82. dbfull()->GetIntProperty("rocksdb.current-super-version-number", &v1));
  83. Put("12345678", "");
  84. ASSERT_TRUE(
  85. dbfull()->GetIntProperty("rocksdb.current-super-version-number", &v2));
  86. Flush();
  87. ASSERT_TRUE(
  88. dbfull()->GetIntProperty("rocksdb.current-super-version-number", &v3));
  89. ASSERT_EQ(v1, v2);
  90. ASSERT_GT(v3, v2);
  91. }
  92. TEST_F(DBPropertiesTest, GetAggregatedIntPropertyTest) {
  93. const int kKeySize = 100;
  94. const int kValueSize = 500;
  95. const int kKeyNum = 100;
  96. Options options;
  97. options.env = env_;
  98. options.create_if_missing = true;
  99. options.write_buffer_size = (kKeySize + kValueSize) * kKeyNum / 10;
  100. // Make them never flush
  101. options.min_write_buffer_number_to_merge = 1000;
  102. options.max_write_buffer_number = 1000;
  103. options = CurrentOptions(options);
  104. CreateAndReopenWithCF({"one", "two", "three", "four"}, options);
  105. Random rnd(301);
  106. for (auto* handle : handles_) {
  107. for (int i = 0; i < kKeyNum; ++i) {
  108. db_->Put(WriteOptions(), handle, RandomString(&rnd, kKeySize),
  109. RandomString(&rnd, kValueSize));
  110. }
  111. }
  112. uint64_t manual_sum = 0;
  113. uint64_t api_sum = 0;
  114. uint64_t value = 0;
  115. for (auto* handle : handles_) {
  116. ASSERT_TRUE(
  117. db_->GetIntProperty(handle, DB::Properties::kSizeAllMemTables, &value));
  118. manual_sum += value;
  119. }
  120. ASSERT_TRUE(db_->GetAggregatedIntProperty(DB::Properties::kSizeAllMemTables,
  121. &api_sum));
  122. ASSERT_GT(manual_sum, 0);
  123. ASSERT_EQ(manual_sum, api_sum);
  124. ASSERT_FALSE(db_->GetAggregatedIntProperty(DB::Properties::kDBStats, &value));
  125. uint64_t before_flush_trm;
  126. uint64_t after_flush_trm;
  127. for (auto* handle : handles_) {
  128. ASSERT_TRUE(db_->GetAggregatedIntProperty(
  129. DB::Properties::kEstimateTableReadersMem, &before_flush_trm));
  130. // Issue flush and expect larger memory usage of table readers.
  131. db_->Flush(FlushOptions(), handle);
  132. ASSERT_TRUE(db_->GetAggregatedIntProperty(
  133. DB::Properties::kEstimateTableReadersMem, &after_flush_trm));
  134. ASSERT_GT(after_flush_trm, before_flush_trm);
  135. }
  136. }
  137. namespace {
  138. void ResetTableProperties(TableProperties* tp) {
  139. tp->data_size = 0;
  140. tp->index_size = 0;
  141. tp->filter_size = 0;
  142. tp->raw_key_size = 0;
  143. tp->raw_value_size = 0;
  144. tp->num_data_blocks = 0;
  145. tp->num_entries = 0;
  146. tp->num_deletions = 0;
  147. tp->num_merge_operands = 0;
  148. tp->num_range_deletions = 0;
  149. }
  150. void ParseTablePropertiesString(std::string tp_string, TableProperties* tp) {
  151. double dummy_double;
  152. std::replace(tp_string.begin(), tp_string.end(), ';', ' ');
  153. std::replace(tp_string.begin(), tp_string.end(), '=', ' ');
  154. ResetTableProperties(tp);
  155. sscanf(tp_string.c_str(),
  156. "# data blocks %" SCNu64 " # entries %" SCNu64 " # deletions %" SCNu64
  157. " # merge operands %" SCNu64 " # range deletions %" SCNu64
  158. " raw key size %" SCNu64
  159. " raw average key size %lf "
  160. " raw value size %" SCNu64
  161. " raw average value size %lf "
  162. " data block size %" SCNu64 " index block size (user-key? %" SCNu64
  163. ", delta-value? %" SCNu64 ") %" SCNu64 " filter block size %" SCNu64,
  164. &tp->num_data_blocks, &tp->num_entries, &tp->num_deletions,
  165. &tp->num_merge_operands, &tp->num_range_deletions, &tp->raw_key_size,
  166. &dummy_double, &tp->raw_value_size, &dummy_double, &tp->data_size,
  167. &tp->index_key_is_user_key, &tp->index_value_is_delta_encoded,
  168. &tp->index_size, &tp->filter_size);
  169. }
  170. void VerifySimilar(uint64_t a, uint64_t b, double bias) {
  171. ASSERT_EQ(a == 0U, b == 0U);
  172. if (a == 0) {
  173. return;
  174. }
  175. double dbl_a = static_cast<double>(a);
  176. double dbl_b = static_cast<double>(b);
  177. if (dbl_a > dbl_b) {
  178. ASSERT_LT(static_cast<double>(dbl_a - dbl_b) / (dbl_a + dbl_b), bias);
  179. } else {
  180. ASSERT_LT(static_cast<double>(dbl_b - dbl_a) / (dbl_a + dbl_b), bias);
  181. }
  182. }
  183. void VerifyTableProperties(
  184. const TableProperties& base_tp, const TableProperties& new_tp,
  185. double filter_size_bias = CACHE_LINE_SIZE >= 256 ? 0.15 : 0.1,
  186. double index_size_bias = 0.1, double data_size_bias = 0.1,
  187. double num_data_blocks_bias = 0.05) {
  188. VerifySimilar(base_tp.data_size, new_tp.data_size, data_size_bias);
  189. VerifySimilar(base_tp.index_size, new_tp.index_size, index_size_bias);
  190. VerifySimilar(base_tp.filter_size, new_tp.filter_size, filter_size_bias);
  191. VerifySimilar(base_tp.num_data_blocks, new_tp.num_data_blocks,
  192. num_data_blocks_bias);
  193. ASSERT_EQ(base_tp.raw_key_size, new_tp.raw_key_size);
  194. ASSERT_EQ(base_tp.raw_value_size, new_tp.raw_value_size);
  195. ASSERT_EQ(base_tp.num_entries, new_tp.num_entries);
  196. ASSERT_EQ(base_tp.num_deletions, new_tp.num_deletions);
  197. ASSERT_EQ(base_tp.num_range_deletions, new_tp.num_range_deletions);
  198. // Merge operands may become Puts, so we only have an upper bound the exact
  199. // number of merge operands.
  200. ASSERT_GE(base_tp.num_merge_operands, new_tp.num_merge_operands);
  201. }
  202. void GetExpectedTableProperties(
  203. TableProperties* expected_tp, const int kKeySize, const int kValueSize,
  204. const int kPutsPerTable, const int kDeletionsPerTable,
  205. const int kMergeOperandsPerTable, const int kRangeDeletionsPerTable,
  206. const int kTableCount, const int kBloomBitsPerKey, const size_t kBlockSize,
  207. const bool index_key_is_user_key, const bool value_delta_encoding) {
  208. const int kKeysPerTable =
  209. kPutsPerTable + kDeletionsPerTable + kMergeOperandsPerTable;
  210. const int kPutCount = kTableCount * kPutsPerTable;
  211. const int kDeletionCount = kTableCount * kDeletionsPerTable;
  212. const int kMergeCount = kTableCount * kMergeOperandsPerTable;
  213. const int kRangeDeletionCount = kTableCount * kRangeDeletionsPerTable;
  214. const int kKeyCount = kPutCount + kDeletionCount + kMergeCount + kRangeDeletionCount;
  215. const int kAvgSuccessorSize = kKeySize / 5;
  216. const int kEncodingSavePerKey = kKeySize / 4;
  217. expected_tp->raw_key_size = kKeyCount * (kKeySize + 8);
  218. expected_tp->raw_value_size =
  219. (kPutCount + kMergeCount + kRangeDeletionCount) * kValueSize;
  220. expected_tp->num_entries = kKeyCount;
  221. expected_tp->num_deletions = kDeletionCount + kRangeDeletionCount;
  222. expected_tp->num_merge_operands = kMergeCount;
  223. expected_tp->num_range_deletions = kRangeDeletionCount;
  224. expected_tp->num_data_blocks =
  225. kTableCount * (kKeysPerTable * (kKeySize - kEncodingSavePerKey + kValueSize)) /
  226. kBlockSize;
  227. expected_tp->data_size =
  228. kTableCount * (kKeysPerTable * (kKeySize + 8 + kValueSize));
  229. expected_tp->index_size =
  230. expected_tp->num_data_blocks *
  231. (kAvgSuccessorSize + (index_key_is_user_key ? 0 : 8) -
  232. // discount 1 byte as value size is not encoded in value delta encoding
  233. (value_delta_encoding ? 1 : 0));
  234. expected_tp->filter_size =
  235. kTableCount * ((kKeysPerTable * kBloomBitsPerKey + 7) / 8 +
  236. /*average-ish overhead*/ CACHE_LINE_SIZE / 2);
  237. }
  238. } // anonymous namespace
  239. TEST_F(DBPropertiesTest, ValidatePropertyInfo) {
  240. for (const auto& ppt_name_and_info : InternalStats::ppt_name_to_info) {
  241. // If C++ gets a std::string_literal, this would be better to check at
  242. // compile-time using static_assert.
  243. ASSERT_TRUE(ppt_name_and_info.first.empty() ||
  244. !isdigit(ppt_name_and_info.first.back()));
  245. int count = 0;
  246. count += (ppt_name_and_info.second.handle_string == nullptr) ? 0 : 1;
  247. count += (ppt_name_and_info.second.handle_int == nullptr) ? 0 : 1;
  248. count += (ppt_name_and_info.second.handle_string_dbimpl == nullptr) ? 0 : 1;
  249. ASSERT_TRUE(count == 1);
  250. }
  251. }
  252. TEST_F(DBPropertiesTest, ValidateSampleNumber) {
  253. // When "max_open_files" is -1, we read all the files for
  254. // "rocksdb.estimate-num-keys" computation, which is the ground truth.
  255. // Otherwise, we sample 20 newest files to make an estimation.
  256. // Formula: lastest_20_files_active_key_ratio * total_files
  257. Options options = CurrentOptions();
  258. options.disable_auto_compactions = true;
  259. options.level0_stop_writes_trigger = 1000;
  260. DestroyAndReopen(options);
  261. int key = 0;
  262. for (int files = 20; files >= 10; files -= 10) {
  263. for (int i = 0; i < files; i++) {
  264. int rows = files / 10;
  265. for (int j = 0; j < rows; j++) {
  266. db_->Put(WriteOptions(), std::to_string(++key), "foo");
  267. }
  268. db_->Flush(FlushOptions());
  269. }
  270. }
  271. std::string num;
  272. Reopen(options);
  273. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num));
  274. ASSERT_EQ("45", num);
  275. options.max_open_files = -1;
  276. Reopen(options);
  277. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num));
  278. ASSERT_EQ("50", num);
  279. }
  280. TEST_F(DBPropertiesTest, AggregatedTableProperties) {
  281. for (int kTableCount = 40; kTableCount <= 100; kTableCount += 30) {
  282. const int kDeletionsPerTable = 5;
  283. const int kMergeOperandsPerTable = 15;
  284. const int kRangeDeletionsPerTable = 5;
  285. const int kPutsPerTable = 100;
  286. const int kKeySize = 80;
  287. const int kValueSize = 200;
  288. const int kBloomBitsPerKey = 20;
  289. Options options = CurrentOptions();
  290. options.level0_file_num_compaction_trigger = 8;
  291. options.compression = kNoCompression;
  292. options.create_if_missing = true;
  293. options.preserve_deletes = true;
  294. options.merge_operator.reset(new TestPutOperator());
  295. BlockBasedTableOptions table_options;
  296. table_options.filter_policy.reset(
  297. NewBloomFilterPolicy(kBloomBitsPerKey, false));
  298. table_options.block_size = 1024;
  299. options.table_factory.reset(new BlockBasedTableFactory(table_options));
  300. DestroyAndReopen(options);
  301. // Hold open a snapshot to prevent range tombstones from being compacted
  302. // away.
  303. ManagedSnapshot snapshot(db_);
  304. Random rnd(5632);
  305. for (int table = 1; table <= kTableCount; ++table) {
  306. for (int i = 0; i < kPutsPerTable; ++i) {
  307. db_->Put(WriteOptions(), RandomString(&rnd, kKeySize),
  308. RandomString(&rnd, kValueSize));
  309. }
  310. for (int i = 0; i < kDeletionsPerTable; i++) {
  311. db_->Delete(WriteOptions(), RandomString(&rnd, kKeySize));
  312. }
  313. for (int i = 0; i < kMergeOperandsPerTable; i++) {
  314. db_->Merge(WriteOptions(), RandomString(&rnd, kKeySize),
  315. RandomString(&rnd, kValueSize));
  316. }
  317. for (int i = 0; i < kRangeDeletionsPerTable; i++) {
  318. std::string start = RandomString(&rnd, kKeySize);
  319. std::string end = start;
  320. end.resize(kValueSize);
  321. db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), start, end);
  322. }
  323. db_->Flush(FlushOptions());
  324. }
  325. std::string property;
  326. db_->GetProperty(DB::Properties::kAggregatedTableProperties, &property);
  327. TableProperties output_tp;
  328. ParseTablePropertiesString(property, &output_tp);
  329. bool index_key_is_user_key = output_tp.index_key_is_user_key > 0;
  330. bool value_is_delta_encoded = output_tp.index_value_is_delta_encoded > 0;
  331. TableProperties expected_tp;
  332. GetExpectedTableProperties(
  333. &expected_tp, kKeySize, kValueSize, kPutsPerTable, kDeletionsPerTable,
  334. kMergeOperandsPerTable, kRangeDeletionsPerTable, kTableCount,
  335. kBloomBitsPerKey, table_options.block_size, index_key_is_user_key,
  336. value_is_delta_encoded);
  337. VerifyTableProperties(expected_tp, output_tp);
  338. }
  339. }
  340. TEST_F(DBPropertiesTest, ReadLatencyHistogramByLevel) {
  341. Options options = CurrentOptions();
  342. options.write_buffer_size = 110 << 10;
  343. options.level0_file_num_compaction_trigger = 6;
  344. options.num_levels = 4;
  345. options.compression = kNoCompression;
  346. options.max_bytes_for_level_base = 4500 << 10;
  347. options.target_file_size_base = 98 << 10;
  348. options.max_write_buffer_number = 2;
  349. options.statistics = ROCKSDB_NAMESPACE::CreateDBStatistics();
  350. options.max_open_files = 11; // Make sure no proloading of table readers
  351. // RocksDB sanitize max open files to at least 20. Modify it back.
  352. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  353. "SanitizeOptions::AfterChangeMaxOpenFiles", [&](void* arg) {
  354. int* max_open_files = static_cast<int*>(arg);
  355. *max_open_files = 11;
  356. });
  357. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  358. BlockBasedTableOptions table_options;
  359. table_options.no_block_cache = true;
  360. CreateAndReopenWithCF({"pikachu"}, options);
  361. int key_index = 0;
  362. Random rnd(301);
  363. for (int num = 0; num < 8; num++) {
  364. Put("foo", "bar");
  365. GenerateNewFile(&rnd, &key_index);
  366. dbfull()->TEST_WaitForCompact();
  367. }
  368. dbfull()->TEST_WaitForCompact();
  369. std::string prop;
  370. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.dbstats", &prop));
  371. // Get() after flushes, See latency histogram tracked.
  372. for (int key = 0; key < key_index; key++) {
  373. Get(Key(key));
  374. }
  375. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.cfstats", &prop));
  376. ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram"));
  377. ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram"));
  378. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  379. // Reopen and issue Get(). See thee latency tracked
  380. ReopenWithColumnFamilies({"default", "pikachu"}, options);
  381. dbfull()->TEST_WaitForCompact();
  382. for (int key = 0; key < key_index; key++) {
  383. Get(Key(key));
  384. }
  385. // Test for getting immutable_db_options_.statistics
  386. ASSERT_TRUE(dbfull()->GetProperty(dbfull()->DefaultColumnFamily(),
  387. "rocksdb.options-statistics", &prop));
  388. ASSERT_NE(std::string::npos, prop.find("rocksdb.block.cache.miss"));
  389. ASSERT_EQ(std::string::npos, prop.find("rocksdb.db.f.micros"));
  390. ASSERT_TRUE(dbfull()->GetProperty(dbfull()->DefaultColumnFamily(),
  391. "rocksdb.cf-file-histogram", &prop));
  392. ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram"));
  393. ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram"));
  394. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  395. // Reopen and issue iterating. See thee latency tracked
  396. ReopenWithColumnFamilies({"default", "pikachu"}, options);
  397. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  398. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.cf-file-histogram", &prop));
  399. ASSERT_EQ(std::string::npos, prop.find("** Level 0 read latency histogram"));
  400. ASSERT_EQ(std::string::npos, prop.find("** Level 1 read latency histogram"));
  401. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  402. {
  403. std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions()));
  404. for (iter->Seek(Key(0)); iter->Valid(); iter->Next()) {
  405. }
  406. }
  407. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.cf-file-histogram", &prop));
  408. ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram"));
  409. ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram"));
  410. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  411. // CF 1 should show no histogram.
  412. ASSERT_TRUE(
  413. dbfull()->GetProperty(handles_[1], "rocksdb.cf-file-histogram", &prop));
  414. ASSERT_EQ(std::string::npos, prop.find("** Level 0 read latency histogram"));
  415. ASSERT_EQ(std::string::npos, prop.find("** Level 1 read latency histogram"));
  416. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  417. // put something and read it back , CF 1 should show histogram.
  418. Put(1, "foo", "bar");
  419. Flush(1);
  420. dbfull()->TEST_WaitForCompact();
  421. ASSERT_EQ("bar", Get(1, "foo"));
  422. ASSERT_TRUE(
  423. dbfull()->GetProperty(handles_[1], "rocksdb.cf-file-histogram", &prop));
  424. ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram"));
  425. ASSERT_EQ(std::string::npos, prop.find("** Level 1 read latency histogram"));
  426. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  427. // options.max_open_files preloads table readers.
  428. options.max_open_files = -1;
  429. ReopenWithColumnFamilies({"default", "pikachu"}, options);
  430. ASSERT_TRUE(dbfull()->GetProperty(dbfull()->DefaultColumnFamily(),
  431. "rocksdb.cf-file-histogram", &prop));
  432. ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram"));
  433. ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram"));
  434. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  435. for (int key = 0; key < key_index; key++) {
  436. Get(Key(key));
  437. }
  438. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.cfstats", &prop));
  439. ASSERT_NE(std::string::npos, prop.find("** Level 0 read latency histogram"));
  440. ASSERT_NE(std::string::npos, prop.find("** Level 1 read latency histogram"));
  441. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  442. // Clear internal stats
  443. dbfull()->ResetStats();
  444. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.cfstats", &prop));
  445. ASSERT_EQ(std::string::npos, prop.find("** Level 0 read latency histogram"));
  446. ASSERT_EQ(std::string::npos, prop.find("** Level 1 read latency histogram"));
  447. ASSERT_EQ(std::string::npos, prop.find("** Level 2 read latency histogram"));
  448. }
  449. TEST_F(DBPropertiesTest, AggregatedTablePropertiesAtLevel) {
  450. const int kTableCount = 100;
  451. const int kDeletionsPerTable = 2;
  452. const int kMergeOperandsPerTable = 2;
  453. const int kRangeDeletionsPerTable = 2;
  454. const int kPutsPerTable = 10;
  455. const int kKeySize = 50;
  456. const int kValueSize = 400;
  457. const int kMaxLevel = 7;
  458. const int kBloomBitsPerKey = 20;
  459. Random rnd(301);
  460. Options options = CurrentOptions();
  461. options.level0_file_num_compaction_trigger = 8;
  462. options.compression = kNoCompression;
  463. options.create_if_missing = true;
  464. options.level0_file_num_compaction_trigger = 2;
  465. options.target_file_size_base = 8192;
  466. options.max_bytes_for_level_base = 10000;
  467. options.max_bytes_for_level_multiplier = 2;
  468. // This ensures there no compaction happening when we call GetProperty().
  469. options.disable_auto_compactions = true;
  470. options.preserve_deletes = true;
  471. options.merge_operator.reset(new TestPutOperator());
  472. BlockBasedTableOptions table_options;
  473. table_options.filter_policy.reset(
  474. NewBloomFilterPolicy(kBloomBitsPerKey, false));
  475. table_options.block_size = 1024;
  476. options.table_factory.reset(new BlockBasedTableFactory(table_options));
  477. DestroyAndReopen(options);
  478. // Hold open a snapshot to prevent range tombstones from being compacted away.
  479. ManagedSnapshot snapshot(db_);
  480. std::string level_tp_strings[kMaxLevel];
  481. std::string tp_string;
  482. TableProperties level_tps[kMaxLevel];
  483. TableProperties tp, sum_tp, expected_tp;
  484. for (int table = 1; table <= kTableCount; ++table) {
  485. for (int i = 0; i < kPutsPerTable; ++i) {
  486. db_->Put(WriteOptions(), RandomString(&rnd, kKeySize),
  487. RandomString(&rnd, kValueSize));
  488. }
  489. for (int i = 0; i < kDeletionsPerTable; i++) {
  490. db_->Delete(WriteOptions(), RandomString(&rnd, kKeySize));
  491. }
  492. for (int i = 0; i < kMergeOperandsPerTable; i++) {
  493. db_->Merge(WriteOptions(), RandomString(&rnd, kKeySize),
  494. RandomString(&rnd, kValueSize));
  495. }
  496. for (int i = 0; i < kRangeDeletionsPerTable; i++) {
  497. std::string start = RandomString(&rnd, kKeySize);
  498. std::string end = start;
  499. end.resize(kValueSize);
  500. db_->DeleteRange(WriteOptions(), db_->DefaultColumnFamily(), start, end);
  501. }
  502. db_->Flush(FlushOptions());
  503. db_->CompactRange(CompactRangeOptions(), nullptr, nullptr);
  504. ResetTableProperties(&sum_tp);
  505. for (int level = 0; level < kMaxLevel; ++level) {
  506. db_->GetProperty(
  507. DB::Properties::kAggregatedTablePropertiesAtLevel + ToString(level),
  508. &level_tp_strings[level]);
  509. ParseTablePropertiesString(level_tp_strings[level], &level_tps[level]);
  510. sum_tp.data_size += level_tps[level].data_size;
  511. sum_tp.index_size += level_tps[level].index_size;
  512. sum_tp.filter_size += level_tps[level].filter_size;
  513. sum_tp.raw_key_size += level_tps[level].raw_key_size;
  514. sum_tp.raw_value_size += level_tps[level].raw_value_size;
  515. sum_tp.num_data_blocks += level_tps[level].num_data_blocks;
  516. sum_tp.num_entries += level_tps[level].num_entries;
  517. sum_tp.num_deletions += level_tps[level].num_deletions;
  518. sum_tp.num_merge_operands += level_tps[level].num_merge_operands;
  519. sum_tp.num_range_deletions += level_tps[level].num_range_deletions;
  520. }
  521. db_->GetProperty(DB::Properties::kAggregatedTableProperties, &tp_string);
  522. ParseTablePropertiesString(tp_string, &tp);
  523. bool index_key_is_user_key = tp.index_key_is_user_key > 0;
  524. bool value_is_delta_encoded = tp.index_value_is_delta_encoded > 0;
  525. ASSERT_EQ(sum_tp.data_size, tp.data_size);
  526. ASSERT_EQ(sum_tp.index_size, tp.index_size);
  527. ASSERT_EQ(sum_tp.filter_size, tp.filter_size);
  528. ASSERT_EQ(sum_tp.raw_key_size, tp.raw_key_size);
  529. ASSERT_EQ(sum_tp.raw_value_size, tp.raw_value_size);
  530. ASSERT_EQ(sum_tp.num_data_blocks, tp.num_data_blocks);
  531. ASSERT_EQ(sum_tp.num_entries, tp.num_entries);
  532. ASSERT_EQ(sum_tp.num_deletions, tp.num_deletions);
  533. ASSERT_EQ(sum_tp.num_merge_operands, tp.num_merge_operands);
  534. ASSERT_EQ(sum_tp.num_range_deletions, tp.num_range_deletions);
  535. if (table > 3) {
  536. GetExpectedTableProperties(
  537. &expected_tp, kKeySize, kValueSize, kPutsPerTable, kDeletionsPerTable,
  538. kMergeOperandsPerTable, kRangeDeletionsPerTable, table,
  539. kBloomBitsPerKey, table_options.block_size, index_key_is_user_key,
  540. value_is_delta_encoded);
  541. // Gives larger bias here as index block size, filter block size,
  542. // and data block size become much harder to estimate in this test.
  543. VerifyTableProperties(expected_tp, tp, 0.5, 0.4, 0.4, 0.25);
  544. }
  545. }
  546. }
  547. TEST_F(DBPropertiesTest, NumImmutableMemTable) {
  548. do {
  549. Options options = CurrentOptions();
  550. WriteOptions writeOpt = WriteOptions();
  551. writeOpt.disableWAL = true;
  552. options.max_write_buffer_number = 4;
  553. options.min_write_buffer_number_to_merge = 3;
  554. options.write_buffer_size = 1000000;
  555. options.max_write_buffer_size_to_maintain =
  556. 5 * static_cast<int64_t>(options.write_buffer_size);
  557. CreateAndReopenWithCF({"pikachu"}, options);
  558. std::string big_value(1000000 * 2, 'x');
  559. std::string num;
  560. uint64_t value;
  561. SetPerfLevel(kEnableTime);
  562. ASSERT_TRUE(GetPerfLevel() == kEnableTime);
  563. ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k1", big_value));
  564. ASSERT_TRUE(dbfull()->GetProperty(handles_[1],
  565. "rocksdb.num-immutable-mem-table", &num));
  566. ASSERT_EQ(num, "0");
  567. ASSERT_TRUE(dbfull()->GetProperty(
  568. handles_[1], DB::Properties::kNumImmutableMemTableFlushed, &num));
  569. ASSERT_EQ(num, "0");
  570. ASSERT_TRUE(dbfull()->GetProperty(
  571. handles_[1], "rocksdb.num-entries-active-mem-table", &num));
  572. ASSERT_EQ(num, "1");
  573. get_perf_context()->Reset();
  574. Get(1, "k1");
  575. ASSERT_EQ(1, static_cast<int>(get_perf_context()->get_from_memtable_count));
  576. ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k2", big_value));
  577. ASSERT_TRUE(dbfull()->GetProperty(handles_[1],
  578. "rocksdb.num-immutable-mem-table", &num));
  579. ASSERT_EQ(num, "1");
  580. ASSERT_TRUE(dbfull()->GetProperty(
  581. handles_[1], "rocksdb.num-entries-active-mem-table", &num));
  582. ASSERT_EQ(num, "1");
  583. ASSERT_TRUE(dbfull()->GetProperty(
  584. handles_[1], "rocksdb.num-entries-imm-mem-tables", &num));
  585. ASSERT_EQ(num, "1");
  586. get_perf_context()->Reset();
  587. Get(1, "k1");
  588. ASSERT_EQ(2, static_cast<int>(get_perf_context()->get_from_memtable_count));
  589. get_perf_context()->Reset();
  590. Get(1, "k2");
  591. ASSERT_EQ(1, static_cast<int>(get_perf_context()->get_from_memtable_count));
  592. ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k3", big_value));
  593. ASSERT_TRUE(dbfull()->GetProperty(
  594. handles_[1], "rocksdb.cur-size-active-mem-table", &num));
  595. ASSERT_TRUE(dbfull()->GetProperty(handles_[1],
  596. "rocksdb.num-immutable-mem-table", &num));
  597. ASSERT_EQ(num, "2");
  598. ASSERT_TRUE(dbfull()->GetProperty(
  599. handles_[1], "rocksdb.num-entries-active-mem-table", &num));
  600. ASSERT_EQ(num, "1");
  601. ASSERT_TRUE(dbfull()->GetProperty(
  602. handles_[1], "rocksdb.num-entries-imm-mem-tables", &num));
  603. ASSERT_EQ(num, "2");
  604. get_perf_context()->Reset();
  605. Get(1, "k2");
  606. ASSERT_EQ(2, static_cast<int>(get_perf_context()->get_from_memtable_count));
  607. get_perf_context()->Reset();
  608. Get(1, "k3");
  609. ASSERT_EQ(1, static_cast<int>(get_perf_context()->get_from_memtable_count));
  610. get_perf_context()->Reset();
  611. Get(1, "k1");
  612. ASSERT_EQ(3, static_cast<int>(get_perf_context()->get_from_memtable_count));
  613. ASSERT_OK(Flush(1));
  614. ASSERT_TRUE(dbfull()->GetProperty(handles_[1],
  615. "rocksdb.num-immutable-mem-table", &num));
  616. ASSERT_EQ(num, "0");
  617. ASSERT_TRUE(dbfull()->GetProperty(
  618. handles_[1], DB::Properties::kNumImmutableMemTableFlushed, &num));
  619. ASSERT_EQ(num, "3");
  620. ASSERT_TRUE(dbfull()->GetIntProperty(
  621. handles_[1], "rocksdb.cur-size-active-mem-table", &value));
  622. // "192" is the size of the metadata of two empty skiplists, this would
  623. // break if we change the default skiplist implementation
  624. ASSERT_GE(value, 192);
  625. uint64_t int_num;
  626. uint64_t base_total_size;
  627. ASSERT_TRUE(dbfull()->GetIntProperty(
  628. handles_[1], "rocksdb.estimate-num-keys", &base_total_size));
  629. ASSERT_OK(dbfull()->Delete(writeOpt, handles_[1], "k2"));
  630. ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k3", ""));
  631. ASSERT_OK(dbfull()->Delete(writeOpt, handles_[1], "k3"));
  632. ASSERT_TRUE(dbfull()->GetIntProperty(
  633. handles_[1], "rocksdb.num-deletes-active-mem-table", &int_num));
  634. ASSERT_EQ(int_num, 2U);
  635. ASSERT_TRUE(dbfull()->GetIntProperty(
  636. handles_[1], "rocksdb.num-entries-active-mem-table", &int_num));
  637. ASSERT_EQ(int_num, 3U);
  638. ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k2", big_value));
  639. ASSERT_OK(dbfull()->Put(writeOpt, handles_[1], "k2", big_value));
  640. ASSERT_TRUE(dbfull()->GetIntProperty(
  641. handles_[1], "rocksdb.num-entries-imm-mem-tables", &int_num));
  642. ASSERT_EQ(int_num, 4U);
  643. ASSERT_TRUE(dbfull()->GetIntProperty(
  644. handles_[1], "rocksdb.num-deletes-imm-mem-tables", &int_num));
  645. ASSERT_EQ(int_num, 2U);
  646. ASSERT_TRUE(dbfull()->GetIntProperty(
  647. handles_[1], "rocksdb.estimate-num-keys", &int_num));
  648. ASSERT_EQ(int_num, base_total_size + 1);
  649. SetPerfLevel(kDisable);
  650. ASSERT_TRUE(GetPerfLevel() == kDisable);
  651. } while (ChangeCompactOptions());
  652. }
  653. // TODO(techdept) : Disabled flaky test #12863555
  654. TEST_F(DBPropertiesTest, DISABLED_GetProperty) {
  655. // Set sizes to both background thread pool to be 1 and block them.
  656. env_->SetBackgroundThreads(1, Env::HIGH);
  657. env_->SetBackgroundThreads(1, Env::LOW);
  658. test::SleepingBackgroundTask sleeping_task_low;
  659. env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, &sleeping_task_low,
  660. Env::Priority::LOW);
  661. test::SleepingBackgroundTask sleeping_task_high;
  662. env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask,
  663. &sleeping_task_high, Env::Priority::HIGH);
  664. Options options = CurrentOptions();
  665. WriteOptions writeOpt = WriteOptions();
  666. writeOpt.disableWAL = true;
  667. options.compaction_style = kCompactionStyleUniversal;
  668. options.level0_file_num_compaction_trigger = 1;
  669. options.compaction_options_universal.size_ratio = 50;
  670. options.max_background_compactions = 1;
  671. options.max_background_flushes = 1;
  672. options.max_write_buffer_number = 10;
  673. options.min_write_buffer_number_to_merge = 1;
  674. options.max_write_buffer_size_to_maintain = 0;
  675. options.write_buffer_size = 1000000;
  676. Reopen(options);
  677. std::string big_value(1000000 * 2, 'x');
  678. std::string num;
  679. uint64_t int_num;
  680. SetPerfLevel(kEnableTime);
  681. ASSERT_TRUE(
  682. dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
  683. ASSERT_EQ(int_num, 0U);
  684. ASSERT_TRUE(
  685. dbfull()->GetIntProperty("rocksdb.estimate-live-data-size", &int_num));
  686. ASSERT_EQ(int_num, 0U);
  687. ASSERT_OK(dbfull()->Put(writeOpt, "k1", big_value));
  688. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.num-immutable-mem-table", &num));
  689. ASSERT_EQ(num, "0");
  690. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.mem-table-flush-pending", &num));
  691. ASSERT_EQ(num, "0");
  692. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.compaction-pending", &num));
  693. ASSERT_EQ(num, "0");
  694. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num));
  695. ASSERT_EQ(num, "1");
  696. get_perf_context()->Reset();
  697. ASSERT_OK(dbfull()->Put(writeOpt, "k2", big_value));
  698. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.num-immutable-mem-table", &num));
  699. ASSERT_EQ(num, "1");
  700. ASSERT_OK(dbfull()->Delete(writeOpt, "k-non-existing"));
  701. ASSERT_OK(dbfull()->Put(writeOpt, "k3", big_value));
  702. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.num-immutable-mem-table", &num));
  703. ASSERT_EQ(num, "2");
  704. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.mem-table-flush-pending", &num));
  705. ASSERT_EQ(num, "1");
  706. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.compaction-pending", &num));
  707. ASSERT_EQ(num, "0");
  708. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num));
  709. ASSERT_EQ(num, "2");
  710. // Verify the same set of properties through GetIntProperty
  711. ASSERT_TRUE(
  712. dbfull()->GetIntProperty("rocksdb.num-immutable-mem-table", &int_num));
  713. ASSERT_EQ(int_num, 2U);
  714. ASSERT_TRUE(
  715. dbfull()->GetIntProperty("rocksdb.mem-table-flush-pending", &int_num));
  716. ASSERT_EQ(int_num, 1U);
  717. ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.compaction-pending", &int_num));
  718. ASSERT_EQ(int_num, 0U);
  719. ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &int_num));
  720. ASSERT_EQ(int_num, 2U);
  721. ASSERT_TRUE(
  722. dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
  723. ASSERT_EQ(int_num, 0U);
  724. sleeping_task_high.WakeUp();
  725. sleeping_task_high.WaitUntilDone();
  726. dbfull()->TEST_WaitForFlushMemTable();
  727. ASSERT_OK(dbfull()->Put(writeOpt, "k4", big_value));
  728. ASSERT_OK(dbfull()->Put(writeOpt, "k5", big_value));
  729. dbfull()->TEST_WaitForFlushMemTable();
  730. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.mem-table-flush-pending", &num));
  731. ASSERT_EQ(num, "0");
  732. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.compaction-pending", &num));
  733. ASSERT_EQ(num, "1");
  734. ASSERT_TRUE(dbfull()->GetProperty("rocksdb.estimate-num-keys", &num));
  735. ASSERT_EQ(num, "4");
  736. ASSERT_TRUE(
  737. dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
  738. ASSERT_GT(int_num, 0U);
  739. sleeping_task_low.WakeUp();
  740. sleeping_task_low.WaitUntilDone();
  741. // Wait for compaction to be done. This is important because otherwise RocksDB
  742. // might schedule a compaction when reopening the database, failing assertion
  743. // (A) as a result.
  744. dbfull()->TEST_WaitForCompact();
  745. options.max_open_files = 10;
  746. Reopen(options);
  747. // After reopening, no table reader is loaded, so no memory for table readers
  748. ASSERT_TRUE(
  749. dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
  750. ASSERT_EQ(int_num, 0U); // (A)
  751. ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &int_num));
  752. ASSERT_GT(int_num, 0U);
  753. // After reading a key, at least one table reader is loaded.
  754. Get("k5");
  755. ASSERT_TRUE(
  756. dbfull()->GetIntProperty("rocksdb.estimate-table-readers-mem", &int_num));
  757. ASSERT_GT(int_num, 0U);
  758. // Test rocksdb.num-live-versions
  759. {
  760. options.level0_file_num_compaction_trigger = 20;
  761. Reopen(options);
  762. ASSERT_TRUE(
  763. dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num));
  764. ASSERT_EQ(int_num, 1U);
  765. // Use an iterator to hold current version
  766. std::unique_ptr<Iterator> iter1(dbfull()->NewIterator(ReadOptions()));
  767. ASSERT_OK(dbfull()->Put(writeOpt, "k6", big_value));
  768. Flush();
  769. ASSERT_TRUE(
  770. dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num));
  771. ASSERT_EQ(int_num, 2U);
  772. // Use an iterator to hold current version
  773. std::unique_ptr<Iterator> iter2(dbfull()->NewIterator(ReadOptions()));
  774. ASSERT_OK(dbfull()->Put(writeOpt, "k7", big_value));
  775. Flush();
  776. ASSERT_TRUE(
  777. dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num));
  778. ASSERT_EQ(int_num, 3U);
  779. iter2.reset();
  780. ASSERT_TRUE(
  781. dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num));
  782. ASSERT_EQ(int_num, 2U);
  783. iter1.reset();
  784. ASSERT_TRUE(
  785. dbfull()->GetIntProperty("rocksdb.num-live-versions", &int_num));
  786. ASSERT_EQ(int_num, 1U);
  787. }
  788. }
  789. TEST_F(DBPropertiesTest, ApproximateMemoryUsage) {
  790. const int kNumRounds = 10;
  791. // TODO(noetzli) kFlushesPerRound does not really correlate with how many
  792. // flushes happen.
  793. const int kFlushesPerRound = 10;
  794. const int kWritesPerFlush = 10;
  795. const int kKeySize = 100;
  796. const int kValueSize = 1000;
  797. Options options;
  798. options.write_buffer_size = 1000; // small write buffer
  799. options.min_write_buffer_number_to_merge = 4;
  800. options.compression = kNoCompression;
  801. options.create_if_missing = true;
  802. options = CurrentOptions(options);
  803. DestroyAndReopen(options);
  804. Random rnd(301);
  805. std::vector<Iterator*> iters;
  806. uint64_t active_mem;
  807. uint64_t unflushed_mem;
  808. uint64_t all_mem;
  809. uint64_t prev_all_mem;
  810. // Phase 0. The verify the initial value of all these properties are the same
  811. // as we have no mem-tables.
  812. dbfull()->GetIntProperty("rocksdb.cur-size-active-mem-table", &active_mem);
  813. dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem);
  814. dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem);
  815. ASSERT_EQ(all_mem, active_mem);
  816. ASSERT_EQ(all_mem, unflushed_mem);
  817. // Phase 1. Simply issue Put() and expect "cur-size-all-mem-tables" equals to
  818. // "size-all-mem-tables"
  819. for (int r = 0; r < kNumRounds; ++r) {
  820. for (int f = 0; f < kFlushesPerRound; ++f) {
  821. for (int w = 0; w < kWritesPerFlush; ++w) {
  822. Put(RandomString(&rnd, kKeySize), RandomString(&rnd, kValueSize));
  823. }
  824. }
  825. // Make sure that there is no flush between getting the two properties.
  826. dbfull()->TEST_WaitForFlushMemTable();
  827. dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem);
  828. dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem);
  829. // in no iterator case, these two number should be the same.
  830. ASSERT_EQ(unflushed_mem, all_mem);
  831. }
  832. prev_all_mem = all_mem;
  833. // Phase 2. Keep issuing Put() but also create new iterators. This time we
  834. // expect "size-all-mem-tables" > "cur-size-all-mem-tables".
  835. for (int r = 0; r < kNumRounds; ++r) {
  836. iters.push_back(db_->NewIterator(ReadOptions()));
  837. for (int f = 0; f < kFlushesPerRound; ++f) {
  838. for (int w = 0; w < kWritesPerFlush; ++w) {
  839. Put(RandomString(&rnd, kKeySize), RandomString(&rnd, kValueSize));
  840. }
  841. }
  842. // Force flush to prevent flush from happening between getting the
  843. // properties or after getting the properties and before the new round.
  844. Flush();
  845. // In the second round, add iterators.
  846. dbfull()->GetIntProperty("rocksdb.cur-size-active-mem-table", &active_mem);
  847. dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem);
  848. dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem);
  849. ASSERT_GT(all_mem, active_mem);
  850. ASSERT_GT(all_mem, unflushed_mem);
  851. ASSERT_GT(all_mem, prev_all_mem);
  852. prev_all_mem = all_mem;
  853. }
  854. // Phase 3. Delete iterators and expect "size-all-mem-tables" shrinks
  855. // whenever we release an iterator.
  856. for (auto* iter : iters) {
  857. delete iter;
  858. dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem);
  859. // Expect the size shrinking
  860. ASSERT_LT(all_mem, prev_all_mem);
  861. prev_all_mem = all_mem;
  862. }
  863. // Expect all these three counters to be the same.
  864. dbfull()->GetIntProperty("rocksdb.cur-size-active-mem-table", &active_mem);
  865. dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem);
  866. dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem);
  867. ASSERT_EQ(active_mem, unflushed_mem);
  868. ASSERT_EQ(unflushed_mem, all_mem);
  869. // Phase 5. Reopen, and expect all these three counters to be the same again.
  870. Reopen(options);
  871. dbfull()->GetIntProperty("rocksdb.cur-size-active-mem-table", &active_mem);
  872. dbfull()->GetIntProperty("rocksdb.cur-size-all-mem-tables", &unflushed_mem);
  873. dbfull()->GetIntProperty("rocksdb.size-all-mem-tables", &all_mem);
  874. ASSERT_EQ(active_mem, unflushed_mem);
  875. ASSERT_EQ(unflushed_mem, all_mem);
  876. }
  877. TEST_F(DBPropertiesTest, EstimatePendingCompBytes) {
  878. // Set sizes to both background thread pool to be 1 and block them.
  879. env_->SetBackgroundThreads(1, Env::HIGH);
  880. env_->SetBackgroundThreads(1, Env::LOW);
  881. test::SleepingBackgroundTask sleeping_task_low;
  882. env_->Schedule(&test::SleepingBackgroundTask::DoSleepTask, &sleeping_task_low,
  883. Env::Priority::LOW);
  884. Options options = CurrentOptions();
  885. WriteOptions writeOpt = WriteOptions();
  886. writeOpt.disableWAL = true;
  887. options.compaction_style = kCompactionStyleLevel;
  888. options.level0_file_num_compaction_trigger = 2;
  889. options.max_background_compactions = 1;
  890. options.max_background_flushes = 1;
  891. options.max_write_buffer_number = 10;
  892. options.min_write_buffer_number_to_merge = 1;
  893. options.max_write_buffer_size_to_maintain = 0;
  894. options.write_buffer_size = 1000000;
  895. Reopen(options);
  896. std::string big_value(1000000 * 2, 'x');
  897. std::string num;
  898. uint64_t int_num;
  899. ASSERT_OK(dbfull()->Put(writeOpt, "k1", big_value));
  900. Flush();
  901. ASSERT_TRUE(dbfull()->GetIntProperty(
  902. "rocksdb.estimate-pending-compaction-bytes", &int_num));
  903. ASSERT_EQ(int_num, 0U);
  904. ASSERT_OK(dbfull()->Put(writeOpt, "k2", big_value));
  905. Flush();
  906. ASSERT_TRUE(dbfull()->GetIntProperty(
  907. "rocksdb.estimate-pending-compaction-bytes", &int_num));
  908. ASSERT_GT(int_num, 0U);
  909. ASSERT_OK(dbfull()->Put(writeOpt, "k3", big_value));
  910. Flush();
  911. ASSERT_TRUE(dbfull()->GetIntProperty(
  912. "rocksdb.estimate-pending-compaction-bytes", &int_num));
  913. ASSERT_GT(int_num, 0U);
  914. sleeping_task_low.WakeUp();
  915. sleeping_task_low.WaitUntilDone();
  916. dbfull()->TEST_WaitForCompact();
  917. ASSERT_TRUE(dbfull()->GetIntProperty(
  918. "rocksdb.estimate-pending-compaction-bytes", &int_num));
  919. ASSERT_EQ(int_num, 0U);
  920. }
  921. TEST_F(DBPropertiesTest, EstimateCompressionRatio) {
  922. if (!Snappy_Supported()) {
  923. return;
  924. }
  925. const int kNumL0Files = 3;
  926. const int kNumEntriesPerFile = 1000;
  927. Options options = CurrentOptions();
  928. options.compression_per_level = {kNoCompression, kSnappyCompression};
  929. options.disable_auto_compactions = true;
  930. options.num_levels = 2;
  931. Reopen(options);
  932. // compression ratio is -1.0 when no open files at level
  933. ASSERT_EQ(CompressionRatioAtLevel(0), -1.0);
  934. const std::string kVal(100, 'a');
  935. for (int i = 0; i < kNumL0Files; ++i) {
  936. for (int j = 0; j < kNumEntriesPerFile; ++j) {
  937. // Put common data ("key") at end to prevent delta encoding from
  938. // compressing the key effectively
  939. std::string key = ToString(i) + ToString(j) + "key";
  940. ASSERT_OK(dbfull()->Put(WriteOptions(), key, kVal));
  941. }
  942. Flush();
  943. }
  944. // no compression at L0, so ratio is less than one
  945. ASSERT_LT(CompressionRatioAtLevel(0), 1.0);
  946. ASSERT_GT(CompressionRatioAtLevel(0), 0.0);
  947. ASSERT_EQ(CompressionRatioAtLevel(1), -1.0);
  948. dbfull()->TEST_CompactRange(0, nullptr, nullptr);
  949. ASSERT_EQ(CompressionRatioAtLevel(0), -1.0);
  950. // Data at L1 should be highly compressed thanks to Snappy and redundant data
  951. // in values (ratio is 12.846 as of 4/19/2016).
  952. ASSERT_GT(CompressionRatioAtLevel(1), 10.0);
  953. }
  954. #endif // ROCKSDB_LITE
  955. class CountingUserTblPropCollector : public TablePropertiesCollector {
  956. public:
  957. const char* Name() const override { return "CountingUserTblPropCollector"; }
  958. Status Finish(UserCollectedProperties* properties) override {
  959. std::string encoded;
  960. PutVarint32(&encoded, count_);
  961. *properties = UserCollectedProperties{
  962. {"CountingUserTblPropCollector", message_}, {"Count", encoded},
  963. };
  964. return Status::OK();
  965. }
  966. Status AddUserKey(const Slice& /*user_key*/, const Slice& /*value*/,
  967. EntryType /*type*/, SequenceNumber /*seq*/,
  968. uint64_t /*file_size*/) override {
  969. ++count_;
  970. return Status::OK();
  971. }
  972. UserCollectedProperties GetReadableProperties() const override {
  973. return UserCollectedProperties{};
  974. }
  975. private:
  976. std::string message_ = "Rocksdb";
  977. uint32_t count_ = 0;
  978. };
  979. class CountingUserTblPropCollectorFactory
  980. : public TablePropertiesCollectorFactory {
  981. public:
  982. explicit CountingUserTblPropCollectorFactory(
  983. uint32_t expected_column_family_id)
  984. : expected_column_family_id_(expected_column_family_id),
  985. num_created_(0) {}
  986. TablePropertiesCollector* CreateTablePropertiesCollector(
  987. TablePropertiesCollectorFactory::Context context) override {
  988. EXPECT_EQ(expected_column_family_id_, context.column_family_id);
  989. num_created_++;
  990. return new CountingUserTblPropCollector();
  991. }
  992. const char* Name() const override {
  993. return "CountingUserTblPropCollectorFactory";
  994. }
  995. void set_expected_column_family_id(uint32_t v) {
  996. expected_column_family_id_ = v;
  997. }
  998. uint32_t expected_column_family_id_;
  999. uint32_t num_created_;
  1000. };
  1001. class CountingDeleteTabPropCollector : public TablePropertiesCollector {
  1002. public:
  1003. const char* Name() const override { return "CountingDeleteTabPropCollector"; }
  1004. Status AddUserKey(const Slice& /*user_key*/, const Slice& /*value*/,
  1005. EntryType type, SequenceNumber /*seq*/,
  1006. uint64_t /*file_size*/) override {
  1007. if (type == kEntryDelete) {
  1008. num_deletes_++;
  1009. }
  1010. return Status::OK();
  1011. }
  1012. bool NeedCompact() const override { return num_deletes_ > 10; }
  1013. UserCollectedProperties GetReadableProperties() const override {
  1014. return UserCollectedProperties{};
  1015. }
  1016. Status Finish(UserCollectedProperties* properties) override {
  1017. *properties =
  1018. UserCollectedProperties{{"num_delete", ToString(num_deletes_)}};
  1019. return Status::OK();
  1020. }
  1021. private:
  1022. uint32_t num_deletes_ = 0;
  1023. };
  1024. class CountingDeleteTabPropCollectorFactory
  1025. : public TablePropertiesCollectorFactory {
  1026. public:
  1027. TablePropertiesCollector* CreateTablePropertiesCollector(
  1028. TablePropertiesCollectorFactory::Context /*context*/) override {
  1029. return new CountingDeleteTabPropCollector();
  1030. }
  1031. const char* Name() const override {
  1032. return "CountingDeleteTabPropCollectorFactory";
  1033. }
  1034. };
  1035. #ifndef ROCKSDB_LITE
  1036. TEST_F(DBPropertiesTest, GetUserDefinedTableProperties) {
  1037. Options options = CurrentOptions();
  1038. options.level0_file_num_compaction_trigger = (1 << 30);
  1039. options.table_properties_collector_factories.resize(1);
  1040. std::shared_ptr<CountingUserTblPropCollectorFactory> collector_factory =
  1041. std::make_shared<CountingUserTblPropCollectorFactory>(0);
  1042. options.table_properties_collector_factories[0] = collector_factory;
  1043. Reopen(options);
  1044. // Create 4 tables
  1045. for (int table = 0; table < 4; ++table) {
  1046. for (int i = 0; i < 10 + table; ++i) {
  1047. db_->Put(WriteOptions(), ToString(table * 100 + i), "val");
  1048. }
  1049. db_->Flush(FlushOptions());
  1050. }
  1051. TablePropertiesCollection props;
  1052. ASSERT_OK(db_->GetPropertiesOfAllTables(&props));
  1053. ASSERT_EQ(4U, props.size());
  1054. uint32_t sum = 0;
  1055. for (const auto& item : props) {
  1056. auto& user_collected = item.second->user_collected_properties;
  1057. ASSERT_TRUE(user_collected.find("CountingUserTblPropCollector") !=
  1058. user_collected.end());
  1059. ASSERT_EQ(user_collected.at("CountingUserTblPropCollector"), "Rocksdb");
  1060. ASSERT_TRUE(user_collected.find("Count") != user_collected.end());
  1061. Slice key(user_collected.at("Count"));
  1062. uint32_t count;
  1063. ASSERT_TRUE(GetVarint32(&key, &count));
  1064. sum += count;
  1065. }
  1066. ASSERT_EQ(10u + 11u + 12u + 13u, sum);
  1067. ASSERT_GT(collector_factory->num_created_, 0U);
  1068. collector_factory->num_created_ = 0;
  1069. dbfull()->TEST_CompactRange(0, nullptr, nullptr);
  1070. ASSERT_GT(collector_factory->num_created_, 0U);
  1071. }
  1072. #endif // ROCKSDB_LITE
  1073. TEST_F(DBPropertiesTest, UserDefinedTablePropertiesContext) {
  1074. Options options = CurrentOptions();
  1075. options.level0_file_num_compaction_trigger = 3;
  1076. options.table_properties_collector_factories.resize(1);
  1077. std::shared_ptr<CountingUserTblPropCollectorFactory> collector_factory =
  1078. std::make_shared<CountingUserTblPropCollectorFactory>(1);
  1079. options.table_properties_collector_factories[0] = collector_factory,
  1080. CreateAndReopenWithCF({"pikachu"}, options);
  1081. // Create 2 files
  1082. for (int table = 0; table < 2; ++table) {
  1083. for (int i = 0; i < 10 + table; ++i) {
  1084. Put(1, ToString(table * 100 + i), "val");
  1085. }
  1086. Flush(1);
  1087. }
  1088. ASSERT_GT(collector_factory->num_created_, 0U);
  1089. collector_factory->num_created_ = 0;
  1090. // Trigger automatic compactions.
  1091. for (int table = 0; table < 3; ++table) {
  1092. for (int i = 0; i < 10 + table; ++i) {
  1093. Put(1, ToString(table * 100 + i), "val");
  1094. }
  1095. Flush(1);
  1096. dbfull()->TEST_WaitForCompact();
  1097. }
  1098. ASSERT_GT(collector_factory->num_created_, 0U);
  1099. collector_factory->num_created_ = 0;
  1100. dbfull()->TEST_CompactRange(0, nullptr, nullptr, handles_[1]);
  1101. ASSERT_GT(collector_factory->num_created_, 0U);
  1102. // Come back to write to default column family
  1103. collector_factory->num_created_ = 0;
  1104. collector_factory->set_expected_column_family_id(0); // default CF
  1105. // Create 4 tables in default column family
  1106. for (int table = 0; table < 2; ++table) {
  1107. for (int i = 0; i < 10 + table; ++i) {
  1108. Put(ToString(table * 100 + i), "val");
  1109. }
  1110. Flush();
  1111. }
  1112. ASSERT_GT(collector_factory->num_created_, 0U);
  1113. collector_factory->num_created_ = 0;
  1114. // Trigger automatic compactions.
  1115. for (int table = 0; table < 3; ++table) {
  1116. for (int i = 0; i < 10 + table; ++i) {
  1117. Put(ToString(table * 100 + i), "val");
  1118. }
  1119. Flush();
  1120. dbfull()->TEST_WaitForCompact();
  1121. }
  1122. ASSERT_GT(collector_factory->num_created_, 0U);
  1123. collector_factory->num_created_ = 0;
  1124. dbfull()->TEST_CompactRange(0, nullptr, nullptr);
  1125. ASSERT_GT(collector_factory->num_created_, 0U);
  1126. }
  1127. #ifndef ROCKSDB_LITE
  1128. TEST_F(DBPropertiesTest, TablePropertiesNeedCompactTest) {
  1129. Random rnd(301);
  1130. Options options;
  1131. options.create_if_missing = true;
  1132. options.write_buffer_size = 4096;
  1133. options.max_write_buffer_number = 8;
  1134. options.level0_file_num_compaction_trigger = 2;
  1135. options.level0_slowdown_writes_trigger = 2;
  1136. options.level0_stop_writes_trigger = 4;
  1137. options.target_file_size_base = 2048;
  1138. options.max_bytes_for_level_base = 10240;
  1139. options.max_bytes_for_level_multiplier = 4;
  1140. options.soft_pending_compaction_bytes_limit = 1024 * 1024;
  1141. options.num_levels = 8;
  1142. options.env = env_;
  1143. std::shared_ptr<TablePropertiesCollectorFactory> collector_factory =
  1144. std::make_shared<CountingDeleteTabPropCollectorFactory>();
  1145. options.table_properties_collector_factories.resize(1);
  1146. options.table_properties_collector_factories[0] = collector_factory;
  1147. DestroyAndReopen(options);
  1148. const int kMaxKey = 1000;
  1149. for (int i = 0; i < kMaxKey; i++) {
  1150. ASSERT_OK(Put(Key(i), RandomString(&rnd, 102)));
  1151. ASSERT_OK(Put(Key(kMaxKey + i), RandomString(&rnd, 102)));
  1152. }
  1153. Flush();
  1154. dbfull()->TEST_WaitForCompact();
  1155. if (NumTableFilesAtLevel(0) == 1) {
  1156. // Clear Level 0 so that when later flush a file with deletions,
  1157. // we don't trigger an organic compaction.
  1158. ASSERT_OK(Put(Key(0), ""));
  1159. ASSERT_OK(Put(Key(kMaxKey * 2), ""));
  1160. Flush();
  1161. dbfull()->TEST_WaitForCompact();
  1162. }
  1163. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  1164. {
  1165. int c = 0;
  1166. std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions()));
  1167. iter->Seek(Key(kMaxKey - 100));
  1168. while (iter->Valid() && iter->key().compare(Key(kMaxKey + 100)) < 0) {
  1169. iter->Next();
  1170. ++c;
  1171. }
  1172. ASSERT_EQ(c, 200);
  1173. }
  1174. Delete(Key(0));
  1175. for (int i = kMaxKey - 100; i < kMaxKey + 100; i++) {
  1176. Delete(Key(i));
  1177. }
  1178. Delete(Key(kMaxKey * 2));
  1179. Flush();
  1180. dbfull()->TEST_WaitForCompact();
  1181. {
  1182. SetPerfLevel(kEnableCount);
  1183. get_perf_context()->Reset();
  1184. int c = 0;
  1185. std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions()));
  1186. iter->Seek(Key(kMaxKey - 100));
  1187. while (iter->Valid() && iter->key().compare(Key(kMaxKey + 100)) < 0) {
  1188. iter->Next();
  1189. }
  1190. ASSERT_EQ(c, 0);
  1191. ASSERT_LT(get_perf_context()->internal_delete_skipped_count, 30u);
  1192. ASSERT_LT(get_perf_context()->internal_key_skipped_count, 30u);
  1193. SetPerfLevel(kDisable);
  1194. }
  1195. }
  1196. TEST_F(DBPropertiesTest, NeedCompactHintPersistentTest) {
  1197. Random rnd(301);
  1198. Options options;
  1199. options.create_if_missing = true;
  1200. options.max_write_buffer_number = 8;
  1201. options.level0_file_num_compaction_trigger = 10;
  1202. options.level0_slowdown_writes_trigger = 10;
  1203. options.level0_stop_writes_trigger = 10;
  1204. options.disable_auto_compactions = true;
  1205. options.env = env_;
  1206. std::shared_ptr<TablePropertiesCollectorFactory> collector_factory =
  1207. std::make_shared<CountingDeleteTabPropCollectorFactory>();
  1208. options.table_properties_collector_factories.resize(1);
  1209. options.table_properties_collector_factories[0] = collector_factory;
  1210. DestroyAndReopen(options);
  1211. const int kMaxKey = 100;
  1212. for (int i = 0; i < kMaxKey; i++) {
  1213. ASSERT_OK(Put(Key(i), ""));
  1214. }
  1215. Flush();
  1216. dbfull()->TEST_WaitForFlushMemTable();
  1217. for (int i = 1; i < kMaxKey - 1; i++) {
  1218. Delete(Key(i));
  1219. }
  1220. Flush();
  1221. dbfull()->TEST_WaitForFlushMemTable();
  1222. ASSERT_EQ(NumTableFilesAtLevel(0), 2);
  1223. // Restart the DB. Although number of files didn't reach
  1224. // options.level0_file_num_compaction_trigger, compaction should
  1225. // still be triggered because of the need-compaction hint.
  1226. options.disable_auto_compactions = false;
  1227. Reopen(options);
  1228. dbfull()->TEST_WaitForCompact();
  1229. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  1230. {
  1231. SetPerfLevel(kEnableCount);
  1232. get_perf_context()->Reset();
  1233. int c = 0;
  1234. std::unique_ptr<Iterator> iter(db_->NewIterator(ReadOptions()));
  1235. for (iter->Seek(Key(0)); iter->Valid(); iter->Next()) {
  1236. c++;
  1237. }
  1238. ASSERT_EQ(c, 2);
  1239. ASSERT_EQ(get_perf_context()->internal_delete_skipped_count, 0);
  1240. // We iterate every key twice. Is it a bug?
  1241. ASSERT_LE(get_perf_context()->internal_key_skipped_count, 2);
  1242. SetPerfLevel(kDisable);
  1243. }
  1244. }
  1245. TEST_F(DBPropertiesTest, EstimateNumKeysUnderflow) {
  1246. Options options;
  1247. Reopen(options);
  1248. Put("foo", "bar");
  1249. Delete("foo");
  1250. Delete("foo");
  1251. uint64_t num_keys = 0;
  1252. ASSERT_TRUE(dbfull()->GetIntProperty("rocksdb.estimate-num-keys", &num_keys));
  1253. ASSERT_EQ(0, num_keys);
  1254. }
  1255. TEST_F(DBPropertiesTest, EstimateOldestKeyTime) {
  1256. std::unique_ptr<MockTimeEnv> mock_env(new MockTimeEnv(Env::Default()));
  1257. uint64_t oldest_key_time = 0;
  1258. Options options;
  1259. options.env = mock_env.get();
  1260. // "rocksdb.estimate-oldest-key-time" only available to fifo compaction.
  1261. mock_env->set_current_time(100);
  1262. for (auto compaction : {kCompactionStyleLevel, kCompactionStyleUniversal,
  1263. kCompactionStyleNone}) {
  1264. options.compaction_style = compaction;
  1265. options.create_if_missing = true;
  1266. DestroyAndReopen(options);
  1267. ASSERT_OK(Put("foo", "bar"));
  1268. ASSERT_FALSE(dbfull()->GetIntProperty(
  1269. DB::Properties::kEstimateOldestKeyTime, &oldest_key_time));
  1270. }
  1271. options.compaction_style = kCompactionStyleFIFO;
  1272. options.ttl = 300;
  1273. options.compaction_options_fifo.allow_compaction = false;
  1274. DestroyAndReopen(options);
  1275. mock_env->set_current_time(100);
  1276. ASSERT_OK(Put("k1", "v1"));
  1277. ASSERT_TRUE(dbfull()->GetIntProperty(DB::Properties::kEstimateOldestKeyTime,
  1278. &oldest_key_time));
  1279. ASSERT_EQ(100, oldest_key_time);
  1280. ASSERT_OK(Flush());
  1281. ASSERT_EQ("1", FilesPerLevel());
  1282. ASSERT_TRUE(dbfull()->GetIntProperty(DB::Properties::kEstimateOldestKeyTime,
  1283. &oldest_key_time));
  1284. ASSERT_EQ(100, oldest_key_time);
  1285. mock_env->set_current_time(200);
  1286. ASSERT_OK(Put("k2", "v2"));
  1287. ASSERT_OK(Flush());
  1288. ASSERT_EQ("2", FilesPerLevel());
  1289. ASSERT_TRUE(dbfull()->GetIntProperty(DB::Properties::kEstimateOldestKeyTime,
  1290. &oldest_key_time));
  1291. ASSERT_EQ(100, oldest_key_time);
  1292. mock_env->set_current_time(300);
  1293. ASSERT_OK(Put("k3", "v3"));
  1294. ASSERT_OK(Flush());
  1295. ASSERT_EQ("3", FilesPerLevel());
  1296. ASSERT_TRUE(dbfull()->GetIntProperty(DB::Properties::kEstimateOldestKeyTime,
  1297. &oldest_key_time));
  1298. ASSERT_EQ(100, oldest_key_time);
  1299. mock_env->set_current_time(450);
  1300. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  1301. ASSERT_EQ("2", FilesPerLevel());
  1302. ASSERT_TRUE(dbfull()->GetIntProperty(DB::Properties::kEstimateOldestKeyTime,
  1303. &oldest_key_time));
  1304. ASSERT_EQ(200, oldest_key_time);
  1305. mock_env->set_current_time(550);
  1306. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  1307. ASSERT_EQ("1", FilesPerLevel());
  1308. ASSERT_TRUE(dbfull()->GetIntProperty(DB::Properties::kEstimateOldestKeyTime,
  1309. &oldest_key_time));
  1310. ASSERT_EQ(300, oldest_key_time);
  1311. mock_env->set_current_time(650);
  1312. ASSERT_OK(dbfull()->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  1313. ASSERT_EQ("", FilesPerLevel());
  1314. ASSERT_FALSE(dbfull()->GetIntProperty(DB::Properties::kEstimateOldestKeyTime,
  1315. &oldest_key_time));
  1316. // Close before mock_env destructs.
  1317. Close();
  1318. }
  1319. TEST_F(DBPropertiesTest, SstFilesSize) {
  1320. struct TestListener : public EventListener {
  1321. void OnCompactionCompleted(DB* db,
  1322. const CompactionJobInfo& /*info*/) override {
  1323. assert(callback_triggered == false);
  1324. assert(size_before_compaction > 0);
  1325. callback_triggered = true;
  1326. uint64_t total_sst_size = 0;
  1327. uint64_t live_sst_size = 0;
  1328. bool ok = db->GetIntProperty(DB::Properties::kTotalSstFilesSize,
  1329. &total_sst_size);
  1330. ASSERT_TRUE(ok);
  1331. // total_sst_size include files before and after compaction.
  1332. ASSERT_GT(total_sst_size, size_before_compaction);
  1333. ok =
  1334. db->GetIntProperty(DB::Properties::kLiveSstFilesSize, &live_sst_size);
  1335. ASSERT_TRUE(ok);
  1336. // live_sst_size only include files after compaction.
  1337. ASSERT_GT(live_sst_size, 0);
  1338. ASSERT_LT(live_sst_size, size_before_compaction);
  1339. }
  1340. uint64_t size_before_compaction = 0;
  1341. bool callback_triggered = false;
  1342. };
  1343. std::shared_ptr<TestListener> listener = std::make_shared<TestListener>();
  1344. Options options;
  1345. options.disable_auto_compactions = true;
  1346. options.listeners.push_back(listener);
  1347. Reopen(options);
  1348. for (int i = 0; i < 10; i++) {
  1349. ASSERT_OK(Put("key" + ToString(i), std::string(1000, 'v')));
  1350. }
  1351. ASSERT_OK(Flush());
  1352. for (int i = 0; i < 5; i++) {
  1353. ASSERT_OK(Delete("key" + ToString(i)));
  1354. }
  1355. ASSERT_OK(Flush());
  1356. uint64_t sst_size;
  1357. bool ok = db_->GetIntProperty(DB::Properties::kTotalSstFilesSize, &sst_size);
  1358. ASSERT_TRUE(ok);
  1359. ASSERT_GT(sst_size, 0);
  1360. listener->size_before_compaction = sst_size;
  1361. // Compact to clean all keys and trigger listener.
  1362. ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  1363. ASSERT_TRUE(listener->callback_triggered);
  1364. }
  1365. TEST_F(DBPropertiesTest, MinObsoleteSstNumberToKeep) {
  1366. class TestListener : public EventListener {
  1367. public:
  1368. void OnTableFileCreated(const TableFileCreationInfo& info) override {
  1369. if (info.reason == TableFileCreationReason::kCompaction) {
  1370. // Verify the property indicates that SSTs created by a running
  1371. // compaction cannot be deleted.
  1372. uint64_t created_file_num;
  1373. FileType created_file_type;
  1374. std::string filename =
  1375. info.file_path.substr(info.file_path.rfind('/') + 1);
  1376. ASSERT_TRUE(
  1377. ParseFileName(filename, &created_file_num, &created_file_type));
  1378. ASSERT_EQ(kTableFile, created_file_type);
  1379. uint64_t keep_sst_lower_bound;
  1380. ASSERT_TRUE(
  1381. db_->GetIntProperty(DB::Properties::kMinObsoleteSstNumberToKeep,
  1382. &keep_sst_lower_bound));
  1383. ASSERT_LE(keep_sst_lower_bound, created_file_num);
  1384. validated_ = true;
  1385. }
  1386. }
  1387. void SetDB(DB* db) { db_ = db; }
  1388. int GetNumCompactions() { return num_compactions_; }
  1389. // True if we've verified the property for at least one output file
  1390. bool Validated() { return validated_; }
  1391. private:
  1392. int num_compactions_ = 0;
  1393. bool validated_ = false;
  1394. DB* db_ = nullptr;
  1395. };
  1396. const int kNumL0Files = 4;
  1397. std::shared_ptr<TestListener> listener = std::make_shared<TestListener>();
  1398. Options options = CurrentOptions();
  1399. options.listeners.push_back(listener);
  1400. options.level0_file_num_compaction_trigger = kNumL0Files;
  1401. DestroyAndReopen(options);
  1402. listener->SetDB(db_);
  1403. for (int i = 0; i < kNumL0Files; ++i) {
  1404. // Make sure they overlap in keyspace to prevent trivial move
  1405. Put("key1", "val");
  1406. Put("key2", "val");
  1407. Flush();
  1408. }
  1409. dbfull()->TEST_WaitForCompact();
  1410. ASSERT_TRUE(listener->Validated());
  1411. }
  1412. TEST_F(DBPropertiesTest, BlockCacheProperties) {
  1413. Options options;
  1414. uint64_t value;
  1415. // Block cache properties are not available for tables other than
  1416. // block-based table.
  1417. options.table_factory.reset(NewPlainTableFactory());
  1418. Reopen(options);
  1419. ASSERT_FALSE(
  1420. db_->GetIntProperty(DB::Properties::kBlockCacheCapacity, &value));
  1421. ASSERT_FALSE(db_->GetIntProperty(DB::Properties::kBlockCacheUsage, &value));
  1422. ASSERT_FALSE(
  1423. db_->GetIntProperty(DB::Properties::kBlockCachePinnedUsage, &value));
  1424. options.table_factory.reset(NewCuckooTableFactory());
  1425. Reopen(options);
  1426. ASSERT_FALSE(
  1427. db_->GetIntProperty(DB::Properties::kBlockCacheCapacity, &value));
  1428. ASSERT_FALSE(db_->GetIntProperty(DB::Properties::kBlockCacheUsage, &value));
  1429. ASSERT_FALSE(
  1430. db_->GetIntProperty(DB::Properties::kBlockCachePinnedUsage, &value));
  1431. // Block cache properties are not available if block cache is not used.
  1432. BlockBasedTableOptions table_options;
  1433. table_options.no_block_cache = true;
  1434. options.table_factory.reset(NewBlockBasedTableFactory(table_options));
  1435. Reopen(options);
  1436. ASSERT_FALSE(
  1437. db_->GetIntProperty(DB::Properties::kBlockCacheCapacity, &value));
  1438. ASSERT_FALSE(db_->GetIntProperty(DB::Properties::kBlockCacheUsage, &value));
  1439. ASSERT_FALSE(
  1440. db_->GetIntProperty(DB::Properties::kBlockCachePinnedUsage, &value));
  1441. // Test with empty block cache.
  1442. constexpr size_t kCapacity = 100;
  1443. LRUCacheOptions co;
  1444. co.capacity = kCapacity;
  1445. co.num_shard_bits = 0;
  1446. co.metadata_charge_policy = kDontChargeCacheMetadata;
  1447. auto block_cache = NewLRUCache(co);
  1448. table_options.block_cache = block_cache;
  1449. table_options.no_block_cache = false;
  1450. options.table_factory.reset(NewBlockBasedTableFactory(table_options));
  1451. Reopen(options);
  1452. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheCapacity, &value));
  1453. ASSERT_EQ(kCapacity, value);
  1454. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheUsage, &value));
  1455. ASSERT_EQ(0, value);
  1456. ASSERT_TRUE(
  1457. db_->GetIntProperty(DB::Properties::kBlockCachePinnedUsage, &value));
  1458. ASSERT_EQ(0, value);
  1459. // Insert unpinned item to the cache and check size.
  1460. constexpr size_t kSize1 = 50;
  1461. block_cache->Insert("item1", nullptr /*value*/, kSize1, nullptr /*deleter*/);
  1462. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheCapacity, &value));
  1463. ASSERT_EQ(kCapacity, value);
  1464. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheUsage, &value));
  1465. ASSERT_EQ(kSize1, value);
  1466. ASSERT_TRUE(
  1467. db_->GetIntProperty(DB::Properties::kBlockCachePinnedUsage, &value));
  1468. ASSERT_EQ(0, value);
  1469. // Insert pinned item to the cache and check size.
  1470. constexpr size_t kSize2 = 30;
  1471. Cache::Handle* item2 = nullptr;
  1472. block_cache->Insert("item2", nullptr /*value*/, kSize2, nullptr /*deleter*/,
  1473. &item2);
  1474. ASSERT_NE(nullptr, item2);
  1475. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheCapacity, &value));
  1476. ASSERT_EQ(kCapacity, value);
  1477. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheUsage, &value));
  1478. ASSERT_EQ(kSize1 + kSize2, value);
  1479. ASSERT_TRUE(
  1480. db_->GetIntProperty(DB::Properties::kBlockCachePinnedUsage, &value));
  1481. ASSERT_EQ(kSize2, value);
  1482. // Insert another pinned item to make the cache over-sized.
  1483. constexpr size_t kSize3 = 80;
  1484. Cache::Handle* item3 = nullptr;
  1485. block_cache->Insert("item3", nullptr /*value*/, kSize3, nullptr /*deleter*/,
  1486. &item3);
  1487. ASSERT_NE(nullptr, item2);
  1488. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheCapacity, &value));
  1489. ASSERT_EQ(kCapacity, value);
  1490. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheUsage, &value));
  1491. // Item 1 is evicted.
  1492. ASSERT_EQ(kSize2 + kSize3, value);
  1493. ASSERT_TRUE(
  1494. db_->GetIntProperty(DB::Properties::kBlockCachePinnedUsage, &value));
  1495. ASSERT_EQ(kSize2 + kSize3, value);
  1496. // Check size after release.
  1497. block_cache->Release(item2);
  1498. block_cache->Release(item3);
  1499. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheCapacity, &value));
  1500. ASSERT_EQ(kCapacity, value);
  1501. ASSERT_TRUE(db_->GetIntProperty(DB::Properties::kBlockCacheUsage, &value));
  1502. // item2 will be evicted, while item3 remain in cache after release.
  1503. ASSERT_EQ(kSize3, value);
  1504. ASSERT_TRUE(
  1505. db_->GetIntProperty(DB::Properties::kBlockCachePinnedUsage, &value));
  1506. ASSERT_EQ(0, value);
  1507. }
  1508. #endif // ROCKSDB_LITE
  1509. } // namespace ROCKSDB_NAMESPACE
  1510. int main(int argc, char** argv) {
  1511. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  1512. ::testing::InitGoogleTest(&argc, argv);
  1513. return RUN_ALL_TESTS();
  1514. }