test_db_options_parser.py 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  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. from advisor.db_log_parser import NO_COL_FAMILY
  6. from advisor.db_options_parser import DatabaseOptions
  7. from advisor.rule_parser import Condition, OptionCondition
  8. import os
  9. import unittest
  10. class TestDatabaseOptions(unittest.TestCase):
  11. def setUp(self):
  12. self.this_path = os.path.abspath(os.path.dirname(__file__))
  13. self.og_options = os.path.join(
  14. self.this_path, 'input_files/OPTIONS-000005'
  15. )
  16. misc_options = [
  17. 'bloom_bits = 4', 'rate_limiter_bytes_per_sec = 1024000'
  18. ]
  19. # create the options object
  20. self.db_options = DatabaseOptions(self.og_options, misc_options)
  21. # perform clean-up before running tests
  22. self.generated_options = os.path.join(
  23. self.this_path, '../temp/OPTIONS_testing.tmp'
  24. )
  25. if os.path.isfile(self.generated_options):
  26. os.remove(self.generated_options)
  27. def test_get_options_diff(self):
  28. old_opt = {
  29. 'DBOptions.stats_dump_freq_sec': {NO_COL_FAMILY: '20'},
  30. 'CFOptions.write_buffer_size': {
  31. 'default': '1024000',
  32. 'col_fam_A': '128000',
  33. 'col_fam_B': '128000000'
  34. },
  35. 'DBOptions.use_fsync': {NO_COL_FAMILY: 'true'},
  36. 'DBOptions.max_log_file_size': {NO_COL_FAMILY: '128000000'}
  37. }
  38. new_opt = {
  39. 'bloom_bits': {NO_COL_FAMILY: '4'},
  40. 'CFOptions.write_buffer_size': {
  41. 'default': '128000000',
  42. 'col_fam_A': '128000',
  43. 'col_fam_C': '128000000'
  44. },
  45. 'DBOptions.use_fsync': {NO_COL_FAMILY: 'true'},
  46. 'DBOptions.max_log_file_size': {NO_COL_FAMILY: '0'}
  47. }
  48. diff = DatabaseOptions.get_options_diff(old_opt, new_opt)
  49. expected_diff = {
  50. 'DBOptions.stats_dump_freq_sec': {NO_COL_FAMILY: ('20', None)},
  51. 'bloom_bits': {NO_COL_FAMILY: (None, '4')},
  52. 'CFOptions.write_buffer_size': {
  53. 'default': ('1024000', '128000000'),
  54. 'col_fam_B': ('128000000', None),
  55. 'col_fam_C': (None, '128000000')
  56. },
  57. 'DBOptions.max_log_file_size': {NO_COL_FAMILY: ('128000000', '0')}
  58. }
  59. self.assertDictEqual(diff, expected_diff)
  60. def test_is_misc_option(self):
  61. self.assertTrue(DatabaseOptions.is_misc_option('bloom_bits'))
  62. self.assertFalse(
  63. DatabaseOptions.is_misc_option('DBOptions.stats_dump_freq_sec')
  64. )
  65. def test_set_up(self):
  66. options = self.db_options.get_all_options()
  67. self.assertEqual(22, len(options.keys()))
  68. expected_misc_options = {
  69. 'bloom_bits': '4', 'rate_limiter_bytes_per_sec': '1024000'
  70. }
  71. self.assertDictEqual(
  72. expected_misc_options, self.db_options.get_misc_options()
  73. )
  74. self.assertListEqual(
  75. ['default', 'col_fam_A'], self.db_options.get_column_families()
  76. )
  77. def test_get_options(self):
  78. opt_to_get = [
  79. 'DBOptions.manual_wal_flush', 'DBOptions.db_write_buffer_size',
  80. 'bloom_bits', 'CFOptions.compaction_filter_factory',
  81. 'CFOptions.num_levels', 'rate_limiter_bytes_per_sec',
  82. 'TableOptions.BlockBasedTable.block_align', 'random_option'
  83. ]
  84. options = self.db_options.get_options(opt_to_get)
  85. expected_options = {
  86. 'DBOptions.manual_wal_flush': {NO_COL_FAMILY: 'false'},
  87. 'DBOptions.db_write_buffer_size': {NO_COL_FAMILY: '0'},
  88. 'bloom_bits': {NO_COL_FAMILY: '4'},
  89. 'CFOptions.compaction_filter_factory': {
  90. 'default': 'nullptr', 'col_fam_A': 'nullptr'
  91. },
  92. 'CFOptions.num_levels': {'default': '7', 'col_fam_A': '5'},
  93. 'rate_limiter_bytes_per_sec': {NO_COL_FAMILY: '1024000'},
  94. 'TableOptions.BlockBasedTable.block_align': {
  95. 'default': 'false', 'col_fam_A': 'true'
  96. }
  97. }
  98. self.assertDictEqual(expected_options, options)
  99. def test_update_options(self):
  100. # add new, update old, set old
  101. # before updating
  102. expected_old_opts = {
  103. 'DBOptions.db_log_dir': {NO_COL_FAMILY: None},
  104. 'DBOptions.manual_wal_flush': {NO_COL_FAMILY: 'false'},
  105. 'bloom_bits': {NO_COL_FAMILY: '4'},
  106. 'CFOptions.num_levels': {'default': '7', 'col_fam_A': '5'},
  107. 'TableOptions.BlockBasedTable.block_restart_interval': {
  108. 'col_fam_A': '16'
  109. }
  110. }
  111. get_opts = list(expected_old_opts.keys())
  112. options = self.db_options.get_options(get_opts)
  113. self.assertEqual(expected_old_opts, options)
  114. # after updating options
  115. update_opts = {
  116. 'DBOptions.db_log_dir': {NO_COL_FAMILY: '/dev/shm'},
  117. 'DBOptions.manual_wal_flush': {NO_COL_FAMILY: 'true'},
  118. 'bloom_bits': {NO_COL_FAMILY: '2'},
  119. 'CFOptions.num_levels': {'col_fam_A': '7'},
  120. 'TableOptions.BlockBasedTable.block_restart_interval': {
  121. 'default': '32'
  122. },
  123. 'random_misc_option': {NO_COL_FAMILY: 'something'}
  124. }
  125. self.db_options.update_options(update_opts)
  126. update_opts['CFOptions.num_levels']['default'] = '7'
  127. update_opts['TableOptions.BlockBasedTable.block_restart_interval'] = {
  128. 'default': '32', 'col_fam_A': '16'
  129. }
  130. get_opts.append('random_misc_option')
  131. options = self.db_options.get_options(get_opts)
  132. self.assertDictEqual(update_opts, options)
  133. expected_misc_options = {
  134. 'bloom_bits': '2',
  135. 'rate_limiter_bytes_per_sec': '1024000',
  136. 'random_misc_option': 'something'
  137. }
  138. self.assertDictEqual(
  139. expected_misc_options, self.db_options.get_misc_options()
  140. )
  141. def test_generate_options_config(self):
  142. # make sure file does not exist from before
  143. self.assertFalse(os.path.isfile(self.generated_options))
  144. self.db_options.generate_options_config('testing')
  145. self.assertTrue(os.path.isfile(self.generated_options))
  146. def test_check_and_trigger_conditions(self):
  147. # options only from CFOptions
  148. # setup the OptionCondition objects to check and trigger
  149. update_dict = {
  150. 'CFOptions.level0_file_num_compaction_trigger': {'col_fam_A': '4'},
  151. 'CFOptions.max_bytes_for_level_base': {'col_fam_A': '10'}
  152. }
  153. self.db_options.update_options(update_dict)
  154. cond1 = Condition('opt-cond-1')
  155. cond1 = OptionCondition.create(cond1)
  156. cond1.set_parameter(
  157. 'options', [
  158. 'CFOptions.level0_file_num_compaction_trigger',
  159. 'TableOptions.BlockBasedTable.block_restart_interval',
  160. 'CFOptions.max_bytes_for_level_base'
  161. ]
  162. )
  163. cond1.set_parameter(
  164. 'evaluate',
  165. 'int(options[0])*int(options[1])-int(options[2])>=0'
  166. )
  167. # only DBOptions
  168. cond2 = Condition('opt-cond-2')
  169. cond2 = OptionCondition.create(cond2)
  170. cond2.set_parameter(
  171. 'options', [
  172. 'DBOptions.db_write_buffer_size',
  173. 'bloom_bits',
  174. 'rate_limiter_bytes_per_sec'
  175. ]
  176. )
  177. cond2.set_parameter(
  178. 'evaluate',
  179. '(int(options[2]) * int(options[1]) * int(options[0]))==0'
  180. )
  181. # mix of CFOptions and DBOptions
  182. cond3 = Condition('opt-cond-3')
  183. cond3 = OptionCondition.create(cond3)
  184. cond3.set_parameter(
  185. 'options', [
  186. 'DBOptions.db_write_buffer_size', # 0
  187. 'CFOptions.num_levels', # 5, 7
  188. 'bloom_bits' # 4
  189. ]
  190. )
  191. cond3.set_parameter(
  192. 'evaluate', 'int(options[2])*int(options[0])+int(options[1])>6'
  193. )
  194. self.db_options.check_and_trigger_conditions([cond1, cond2, cond3])
  195. cond1_trigger = {'col_fam_A': ['4', '16', '10']}
  196. self.assertDictEqual(cond1_trigger, cond1.get_trigger())
  197. cond2_trigger = {NO_COL_FAMILY: ['0', '4', '1024000']}
  198. self.assertDictEqual(cond2_trigger, cond2.get_trigger())
  199. cond3_trigger = {'default': ['0', '7', '4']}
  200. self.assertDictEqual(cond3_trigger, cond3.get_trigger())
  201. if __name__ == '__main__':
  202. unittest.main()