1 /*
2    Copyright (c) 2012, Monty Program Ab
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; version 2 of the License.
7 
8    This program is distributed in the hope that it will be useful,
9    but WITHOUT ANY WARRANTY; without even the implied warranty of
10    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11    GNU General Public License for more details.
12 
13    You should have received a copy of the GNU General Public License
14    along with this program; if not, write to the Free Software
15    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
16 
17 /* C++ standard header files */
18 #include <map>
19 #include <string>
20 #include <vector>
21 
22 /* MySQL header files */
23 #include <sql_show.h>
24 
25 /* RocksDB header files */
26 #include "rocksdb/compaction_filter.h"
27 #include "rocksdb/convenience.h"
28 #include "rocksdb/filter_policy.h"
29 #include "rocksdb/memtablerep.h"
30 #include "rocksdb/merge_operator.h"
31 #include "rocksdb/slice_transform.h"
32 #include "rocksdb/utilities/transaction_db.h"
33 
34 /* MyRocks header files */
35 #include "./ha_rocksdb.h"
36 #include "./ha_rocksdb_proto.h"
37 #include "./rdb_cf_manager.h"
38 #include "./rdb_datadic.h"
39 #include "./rdb_utils.h"
40 
41 namespace myrocks {
42 
43 /**
44   Define the INFORMATION_SCHEMA (I_S) structures needed by MyRocks storage
45   engine.
46 */
47 
48 #define ROCKSDB_FIELD_INFO(_name_, _len_, _type_, _flag_)                      \
49   { _name_, _len_, _type_, 0, _flag_, nullptr, 0 }
50 
51 #define ROCKSDB_FIELD_INFO_END                                                 \
52   ROCKSDB_FIELD_INFO(nullptr, 0, MYSQL_TYPE_NULL, 0)
53 
54 /*
55   Support for INFORMATION_SCHEMA.ROCKSDB_CFSTATS dynamic table
56  */
57 namespace RDB_CFSTATS_FIELD {
58 enum { CF_NAME = 0, STAT_TYPE, VALUE };
59 } // namespace RDB_CFSTATS_FIELD
60 
61 static ST_FIELD_INFO rdb_i_s_cfstats_fields_info[] = {
62     ROCKSDB_FIELD_INFO("CF_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
63     ROCKSDB_FIELD_INFO("STAT_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
64     ROCKSDB_FIELD_INFO("VALUE", sizeof(uint64_t), MYSQL_TYPE_LONGLONG, 0),
65     ROCKSDB_FIELD_INFO_END};
66 
rdb_i_s_cfstats_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)67 static int rdb_i_s_cfstats_fill_table(my_core::THD *const thd,
68                                       my_core::TABLE_LIST *const tables,
69                                       my_core::Item *const cond
70                                       __attribute__((__unused__))) {
71   DBUG_ENTER_FUNC();
72 
73   bool ret;
74   uint64_t val;
75 
76   const std::vector<std::pair<const std::string, std::string>> cf_properties = {
77       {rocksdb::DB::Properties::kNumImmutableMemTable,
78        "NUM_IMMUTABLE_MEM_TABLE"},
79       {rocksdb::DB::Properties::kMemTableFlushPending,
80        "MEM_TABLE_FLUSH_PENDING"},
81       {rocksdb::DB::Properties::kCompactionPending, "COMPACTION_PENDING"},
82       {rocksdb::DB::Properties::kCurSizeActiveMemTable,
83        "CUR_SIZE_ACTIVE_MEM_TABLE"},
84       {rocksdb::DB::Properties::kCurSizeAllMemTables,
85        "CUR_SIZE_ALL_MEM_TABLES"},
86       {rocksdb::DB::Properties::kNumEntriesActiveMemTable,
87        "NUM_ENTRIES_ACTIVE_MEM_TABLE"},
88       {rocksdb::DB::Properties::kNumEntriesImmMemTables,
89        "NUM_ENTRIES_IMM_MEM_TABLES"},
90       {rocksdb::DB::Properties::kEstimateTableReadersMem,
91        "NON_BLOCK_CACHE_SST_MEM_USAGE"},
92       {rocksdb::DB::Properties::kNumLiveVersions, "NUM_LIVE_VERSIONS"}};
93 
94   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
95   const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
96   DBUG_ASSERT(rdb != nullptr);
97 
98   for (const auto &cf_name : cf_manager.get_cf_names()) {
99     rocksdb::ColumnFamilyHandle *cfh;
100     bool is_automatic;
101 
102     /*
103       Only the cf name is important. Whether it was generated automatically
104       does not matter, so is_automatic is ignored.
105     */
106     cfh = cf_manager.get_cf(cf_name.c_str(), "", nullptr, &is_automatic);
107     if (cfh == nullptr)
108       continue;
109 
110     for (const auto &property : cf_properties) {
111       if (!rdb->GetIntProperty(cfh, property.first, &val))
112         continue;
113 
114       DBUG_ASSERT(tables != nullptr);
115 
116       tables->table->field[RDB_CFSTATS_FIELD::CF_NAME]->store(
117           cf_name.c_str(), cf_name.size(), system_charset_info);
118       tables->table->field[RDB_CFSTATS_FIELD::STAT_TYPE]->store(
119           property.second.c_str(), property.second.size(), system_charset_info);
120       tables->table->field[RDB_CFSTATS_FIELD::VALUE]->store(val, true);
121 
122       ret = my_core::schema_table_store_record(thd, tables->table);
123 
124       if (ret)
125         DBUG_RETURN(ret);
126     }
127   }
128   DBUG_RETURN(0);
129 }
130 
rdb_i_s_cfstats_init(void * p)131 static int rdb_i_s_cfstats_init(void *p) {
132   DBUG_ENTER_FUNC();
133 
134   DBUG_ASSERT(p != nullptr);
135 
136   my_core::ST_SCHEMA_TABLE *schema;
137 
138   schema = (my_core::ST_SCHEMA_TABLE *)p;
139 
140   schema->fields_info = rdb_i_s_cfstats_fields_info;
141   schema->fill_table = rdb_i_s_cfstats_fill_table;
142 
143   DBUG_RETURN(0);
144 }
145 
146 /*
147   Support for INFORMATION_SCHEMA.ROCKSDB_DBSTATS dynamic table
148  */
149 namespace RDB_DBSTATS_FIELD {
150 enum { STAT_TYPE = 0, VALUE };
151 } // namespace RDB_DBSTATS_FIELD
152 
153 static ST_FIELD_INFO rdb_i_s_dbstats_fields_info[] = {
154     ROCKSDB_FIELD_INFO("STAT_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
155     ROCKSDB_FIELD_INFO("VALUE", sizeof(uint64_t), MYSQL_TYPE_LONGLONG, 0),
156     ROCKSDB_FIELD_INFO_END};
157 
rdb_i_s_dbstats_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)158 static int rdb_i_s_dbstats_fill_table(my_core::THD *const thd,
159                                       my_core::TABLE_LIST *const tables,
160                                       my_core::Item *const cond
161                                       __attribute__((__unused__))) {
162   DBUG_ENTER_FUNC();
163 
164   bool ret;
165   uint64_t val;
166 
167   const std::vector<std::pair<std::string, std::string>> db_properties = {
168       {rocksdb::DB::Properties::kBackgroundErrors, "DB_BACKGROUND_ERRORS"},
169       {rocksdb::DB::Properties::kNumSnapshots, "DB_NUM_SNAPSHOTS"},
170       {rocksdb::DB::Properties::kOldestSnapshotTime,
171        "DB_OLDEST_SNAPSHOT_TIME"}};
172 
173   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
174   const rocksdb::BlockBasedTableOptions &table_options =
175       rdb_get_table_options();
176 
177   for (const auto &property : db_properties) {
178     if (!rdb->GetIntProperty(property.first, &val))
179       continue;
180 
181     DBUG_ASSERT(tables != nullptr);
182 
183     tables->table->field[RDB_DBSTATS_FIELD::STAT_TYPE]->store(
184         property.second.c_str(), property.second.size(), system_charset_info);
185     tables->table->field[RDB_DBSTATS_FIELD::VALUE]->store(val, true);
186 
187     ret = my_core::schema_table_store_record(thd, tables->table);
188 
189     if (ret)
190       DBUG_RETURN(ret);
191   }
192 
193   /*
194     Currently, this can only show the usage of a block cache allocated
195     directly by the handlerton. If the column family config specifies a block
196     cache (i.e. the column family option has a parameter such as
197     block_based_table_factory={block_cache=1G}), then the block cache is
198     allocated within the rocksdb::GetColumnFamilyOptionsFromString().
199 
200     There is no interface to retrieve this block cache, nor fetch the usage
201     information from the column family.
202    */
203   val = (table_options.block_cache ? table_options.block_cache->GetUsage() : 0);
204   tables->table->field[RDB_DBSTATS_FIELD::STAT_TYPE]->store(
205       STRING_WITH_LEN("DB_BLOCK_CACHE_USAGE"), system_charset_info);
206   tables->table->field[RDB_DBSTATS_FIELD::VALUE]->store(val, true);
207 
208   ret = my_core::schema_table_store_record(thd, tables->table);
209 
210   DBUG_RETURN(ret);
211 }
212 
rdb_i_s_dbstats_init(void * const p)213 static int rdb_i_s_dbstats_init(void *const p) {
214   DBUG_ENTER_FUNC();
215 
216   DBUG_ASSERT(p != nullptr);
217 
218   my_core::ST_SCHEMA_TABLE *schema;
219 
220   schema = (my_core::ST_SCHEMA_TABLE *)p;
221 
222   schema->fields_info = rdb_i_s_dbstats_fields_info;
223   schema->fill_table = rdb_i_s_dbstats_fill_table;
224 
225   DBUG_RETURN(0);
226 }
227 
228 /*
229   Support for INFORMATION_SCHEMA.ROCKSDB_PERF_CONTEXT dynamic table
230  */
231 namespace RDB_PERF_CONTEXT_FIELD {
232 enum { TABLE_SCHEMA = 0, TABLE_NAME, PARTITION_NAME, STAT_TYPE, VALUE };
233 } // namespace RDB_PERF_CONTEXT_FIELD
234 
235 static ST_FIELD_INFO rdb_i_s_perf_context_fields_info[] = {
236     ROCKSDB_FIELD_INFO("TABLE_SCHEMA", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
237     ROCKSDB_FIELD_INFO("TABLE_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
238     ROCKSDB_FIELD_INFO("PARTITION_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING,
239                        MY_I_S_MAYBE_NULL),
240     ROCKSDB_FIELD_INFO("STAT_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
241     ROCKSDB_FIELD_INFO("VALUE", sizeof(uint64_t), MYSQL_TYPE_LONGLONG, 0),
242     ROCKSDB_FIELD_INFO_END};
243 
rdb_i_s_perf_context_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)244 static int rdb_i_s_perf_context_fill_table(my_core::THD *const thd,
245                                            my_core::TABLE_LIST *const tables,
246                                            my_core::Item *const cond
247                                            __attribute__((__unused__))) {
248   DBUG_ENTER_FUNC();
249 
250   DBUG_ASSERT(thd != nullptr);
251   DBUG_ASSERT(tables != nullptr);
252 
253   int ret = 0;
254   Field **field = tables->table->field;
255 
256   const std::vector<std::string> tablenames = rdb_get_open_table_names();
257   for (const auto &it : tablenames) {
258     std::string str, dbname, tablename, partname;
259     Rdb_perf_counters counters;
260 
261     if (rdb_normalize_tablename(it, &str)) {
262       return HA_ERR_INTERNAL_ERROR;
263     }
264 
265     if (rdb_split_normalized_tablename(str, &dbname, &tablename, &partname)) {
266       continue;
267     }
268 
269     if (rdb_get_table_perf_counters(it.c_str(), &counters)) {
270       continue;
271     }
272 
273     DBUG_ASSERT(field != nullptr);
274 
275     field[RDB_PERF_CONTEXT_FIELD::TABLE_SCHEMA]->store(
276         dbname.c_str(), dbname.size(), system_charset_info);
277     field[RDB_PERF_CONTEXT_FIELD::TABLE_NAME]->store(
278         tablename.c_str(), tablename.size(), system_charset_info);
279     if (partname.size() == 0) {
280       field[RDB_PERF_CONTEXT_FIELD::PARTITION_NAME]->set_null();
281     } else {
282       field[RDB_PERF_CONTEXT_FIELD::PARTITION_NAME]->set_notnull();
283       field[RDB_PERF_CONTEXT_FIELD::PARTITION_NAME]->store(
284           partname.c_str(), partname.size(), system_charset_info);
285     }
286 
287     for (int i = 0; i < PC_MAX_IDX; i++) {
288       field[RDB_PERF_CONTEXT_FIELD::STAT_TYPE]->store(
289           rdb_pc_stat_types[i].c_str(), rdb_pc_stat_types[i].size(),
290           system_charset_info);
291       field[RDB_PERF_CONTEXT_FIELD::VALUE]->store(counters.m_value[i], true);
292 
293       ret = my_core::schema_table_store_record(thd, tables->table);
294       if (ret)
295         DBUG_RETURN(ret);
296     }
297   }
298 
299   DBUG_RETURN(0);
300 }
301 
rdb_i_s_perf_context_init(void * const p)302 static int rdb_i_s_perf_context_init(void *const p) {
303   DBUG_ENTER_FUNC();
304 
305   DBUG_ASSERT(p != nullptr);
306 
307   my_core::ST_SCHEMA_TABLE *schema;
308 
309   schema = (my_core::ST_SCHEMA_TABLE *)p;
310 
311   schema->fields_info = rdb_i_s_perf_context_fields_info;
312   schema->fill_table = rdb_i_s_perf_context_fill_table;
313 
314   DBUG_RETURN(0);
315 }
316 
317 /*
318   Support for INFORMATION_SCHEMA.ROCKSDB_PERF_CONTEXT_GLOBAL dynamic table
319  */
320 namespace RDB_PERF_CONTEXT_GLOBAL_FIELD {
321 enum { STAT_TYPE = 0, VALUE };
322 } // namespace RDB_PERF_CONTEXT_GLOBAL_FIELD
323 
324 static ST_FIELD_INFO rdb_i_s_perf_context_global_fields_info[] = {
325     ROCKSDB_FIELD_INFO("STAT_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
326     ROCKSDB_FIELD_INFO("VALUE", sizeof(uint64_t), MYSQL_TYPE_LONGLONG, 0),
327     ROCKSDB_FIELD_INFO_END};
328 
rdb_i_s_perf_context_global_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)329 static int rdb_i_s_perf_context_global_fill_table(
330     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
331     my_core::Item *const cond __attribute__((__unused__))) {
332   DBUG_ENTER_FUNC();
333 
334   DBUG_ASSERT(thd != nullptr);
335   DBUG_ASSERT(tables != nullptr);
336 
337   int ret = 0;
338 
339   // Get a copy of the global perf counters.
340   Rdb_perf_counters global_counters;
341   rdb_get_global_perf_counters(&global_counters);
342 
343   for (int i = 0; i < PC_MAX_IDX; i++) {
344     DBUG_ASSERT(tables->table != nullptr);
345     DBUG_ASSERT(tables->table->field != nullptr);
346 
347     tables->table->field[RDB_PERF_CONTEXT_GLOBAL_FIELD::STAT_TYPE]->store(
348         rdb_pc_stat_types[i].c_str(), rdb_pc_stat_types[i].size(),
349         system_charset_info);
350     tables->table->field[RDB_PERF_CONTEXT_GLOBAL_FIELD::VALUE]->store(
351         global_counters.m_value[i], true);
352 
353     ret = my_core::schema_table_store_record(thd, tables->table);
354     if (ret)
355       DBUG_RETURN(ret);
356   }
357 
358   DBUG_RETURN(0);
359 }
360 
rdb_i_s_perf_context_global_init(void * const p)361 static int rdb_i_s_perf_context_global_init(void *const p) {
362   DBUG_ENTER_FUNC();
363 
364   DBUG_ASSERT(p != nullptr);
365 
366   my_core::ST_SCHEMA_TABLE *schema;
367 
368   schema = (my_core::ST_SCHEMA_TABLE *)p;
369 
370   schema->fields_info = rdb_i_s_perf_context_global_fields_info;
371   schema->fill_table = rdb_i_s_perf_context_global_fill_table;
372 
373   DBUG_RETURN(0);
374 }
375 
376 /*
377   Support for INFORMATION_SCHEMA.ROCKSDB_CFOPTIONS dynamic table
378  */
379 namespace RDB_CFOPTIONS_FIELD {
380 enum { CF_NAME = 0, OPTION_TYPE, VALUE };
381 } // namespace RDB_CFOPTIONS_FIELD
382 
383 static ST_FIELD_INFO rdb_i_s_cfoptions_fields_info[] = {
384     ROCKSDB_FIELD_INFO("CF_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
385     ROCKSDB_FIELD_INFO("OPTION_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
386     ROCKSDB_FIELD_INFO("VALUE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
387     ROCKSDB_FIELD_INFO_END};
388 
rdb_i_s_cfoptions_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)389 static int rdb_i_s_cfoptions_fill_table(my_core::THD *const thd,
390                                         my_core::TABLE_LIST *const tables,
391                                         my_core::Item *const cond
392                                         __attribute__((__unused__))) {
393   DBUG_ENTER_FUNC();
394 
395   DBUG_ASSERT(thd != nullptr);
396   DBUG_ASSERT(tables != nullptr);
397 
398   bool ret;
399 
400   Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
401 
402   for (const auto &cf_name : cf_manager.get_cf_names()) {
403     std::string val;
404     rocksdb::ColumnFamilyOptions opts;
405     cf_manager.get_cf_options(cf_name, &opts);
406 
407     std::vector<std::pair<std::string, std::string>> cf_option_types = {
408         {"COMPARATOR", opts.comparator == nullptr
409                            ? "NULL"
410                            : std::string(opts.comparator->Name())},
411         {"MERGE_OPERATOR", opts.merge_operator == nullptr
412                                ? "NULL"
413                                : std::string(opts.merge_operator->Name())},
414         {"COMPACTION_FILTER",
415          opts.compaction_filter == nullptr
416              ? "NULL"
417              : std::string(opts.compaction_filter->Name())},
418         {"COMPACTION_FILTER_FACTORY",
419          opts.compaction_filter_factory == nullptr
420              ? "NULL"
421              : std::string(opts.compaction_filter_factory->Name())},
422         {"WRITE_BUFFER_SIZE", std::to_string(opts.write_buffer_size)},
423         {"MAX_WRITE_BUFFER_NUMBER",
424          std::to_string(opts.max_write_buffer_number)},
425         {"MIN_WRITE_BUFFER_NUMBER_TO_MERGE",
426          std::to_string(opts.min_write_buffer_number_to_merge)},
427         {"NUM_LEVELS", std::to_string(opts.num_levels)},
428         {"LEVEL0_FILE_NUM_COMPACTION_TRIGGER",
429          std::to_string(opts.level0_file_num_compaction_trigger)},
430         {"LEVEL0_SLOWDOWN_WRITES_TRIGGER",
431          std::to_string(opts.level0_slowdown_writes_trigger)},
432         {"LEVEL0_STOP_WRITES_TRIGGER",
433          std::to_string(opts.level0_stop_writes_trigger)},
434         {"MAX_MEM_COMPACTION_LEVEL",
435          std::to_string(opts.max_mem_compaction_level)},
436         {"TARGET_FILE_SIZE_BASE", std::to_string(opts.target_file_size_base)},
437         {"TARGET_FILE_SIZE_MULTIPLIER",
438          std::to_string(opts.target_file_size_multiplier)},
439         {"MAX_BYTES_FOR_LEVEL_BASE",
440          std::to_string(opts.max_bytes_for_level_base)},
441         {"LEVEL_COMPACTION_DYNAMIC_LEVEL_BYTES",
442          opts.level_compaction_dynamic_level_bytes ? "ON" : "OFF"},
443         {"MAX_BYTES_FOR_LEVEL_MULTIPLIER",
444          std::to_string(opts.max_bytes_for_level_multiplier)},
445         {"SOFT_RATE_LIMIT", std::to_string(opts.soft_rate_limit)},
446         {"HARD_RATE_LIMIT", std::to_string(opts.hard_rate_limit)},
447         {"RATE_LIMIT_DELAY_MAX_MILLISECONDS",
448          std::to_string(opts.rate_limit_delay_max_milliseconds)},
449         {"ARENA_BLOCK_SIZE", std::to_string(opts.arena_block_size)},
450         {"DISABLE_AUTO_COMPACTIONS",
451          opts.disable_auto_compactions ? "ON" : "OFF"},
452         {"PURGE_REDUNDANT_KVS_WHILE_FLUSH",
453          opts.purge_redundant_kvs_while_flush ? "ON" : "OFF"},
454         {"VERIFY_CHECKSUM_IN_COMPACTION",
455          opts.verify_checksums_in_compaction ? "ON" : "OFF"},
456         {"MAX_SEQUENTIAL_SKIP_IN_ITERATIONS",
457          std::to_string(opts.max_sequential_skip_in_iterations)},
458         {"MEMTABLE_FACTORY", opts.memtable_factory == nullptr
459                                  ? "NULL"
460                                  : opts.memtable_factory->Name()},
461         {"INPLACE_UPDATE_SUPPORT", opts.inplace_update_support ? "ON" : "OFF"},
462         {"INPLACE_UPDATE_NUM_LOCKS",
463          opts.inplace_update_num_locks ? "ON" : "OFF"},
464         {"MEMTABLE_PREFIX_BLOOM_BITS_RATIO",
465          std::to_string(opts.memtable_prefix_bloom_size_ratio)},
466         {"MEMTABLE_PREFIX_BLOOM_HUGE_PAGE_TLB_SIZE",
467          std::to_string(opts.memtable_huge_page_size)},
468         {"BLOOM_LOCALITY", std::to_string(opts.bloom_locality)},
469         {"MAX_SUCCESSIVE_MERGES", std::to_string(opts.max_successive_merges)},
470         {"MIN_PARTIAL_MERGE_OPERANDS",
471          std::to_string(opts.min_partial_merge_operands)},
472         {"OPTIMIZE_FILTERS_FOR_HITS",
473          (opts.optimize_filters_for_hits ? "ON" : "OFF")},
474     };
475 
476     // get MAX_BYTES_FOR_LEVEL_MULTIPLIER_ADDITIONAL option value
477     val = opts.max_bytes_for_level_multiplier_additional.empty() ? "NULL" : "";
478     for (const auto &level : opts.max_bytes_for_level_multiplier_additional) {
479       val.append(std::to_string(level) + ":");
480     }
481     val.pop_back();
482     cf_option_types.push_back(
483         {"MAX_BYTES_FOR_LEVEL_MULTIPLIER_ADDITIONAL", val});
484 
485     // get COMPRESSION_TYPE option value
486     GetStringFromCompressionType(&val, opts.compression);
487     if (val.empty()) {
488       val = "NULL";
489     }
490     cf_option_types.push_back({"COMPRESSION_TYPE", val});
491 
492     // get COMPRESSION_PER_LEVEL option value
493     val = opts.compression_per_level.empty() ? "NULL" : "";
494     for (const auto &compression_type : opts.compression_per_level) {
495       std::string res;
496       GetStringFromCompressionType(&res, compression_type);
497       if (!res.empty()) {
498         val.append(res + ":");
499       }
500     }
501     val.pop_back();
502     cf_option_types.push_back({"COMPRESSION_PER_LEVEL", val});
503 
504     // get compression_opts value
505     val = std::to_string(opts.compression_opts.window_bits) + ":";
506     val.append(std::to_string(opts.compression_opts.level) + ":");
507     val.append(std::to_string(opts.compression_opts.strategy));
508     cf_option_types.push_back({"COMPRESSION_OPTS", val});
509 
510     // bottommost_compression
511     if (opts.bottommost_compression) {
512       std::string res;
513       GetStringFromCompressionType(&res, opts.bottommost_compression);
514       if (!res.empty()) {
515         cf_option_types.push_back({"BOTTOMMOST_COMPRESSION", res});
516       }
517     }
518 
519     // get PREFIX_EXTRACTOR option
520     cf_option_types.push_back(
521         {"PREFIX_EXTRACTOR", opts.prefix_extractor == nullptr
522                                  ? "NULL"
523                                  : std::string(opts.prefix_extractor->Name())});
524 
525     // get COMPACTION_STYLE option
526     switch (opts.compaction_style) {
527     case rocksdb::kCompactionStyleLevel:
528       val = "kCompactionStyleLevel";
529       break;
530     case rocksdb::kCompactionStyleUniversal:
531       val = "kCompactionStyleUniversal";
532       break;
533     case rocksdb::kCompactionStyleFIFO:
534       val = "kCompactionStyleFIFO";
535       break;
536     case rocksdb::kCompactionStyleNone:
537       val = "kCompactionStyleNone";
538       break;
539     default:
540       val = "NULL";
541     }
542     cf_option_types.push_back({"COMPACTION_STYLE", val});
543 
544     // get COMPACTION_OPTIONS_UNIVERSAL related options
545     const rocksdb::CompactionOptionsUniversal compac_opts =
546         opts.compaction_options_universal;
547     val = "{SIZE_RATIO=";
548     val.append(std::to_string(compac_opts.size_ratio));
549     val.append("; MIN_MERGE_WIDTH=");
550     val.append(std::to_string(compac_opts.min_merge_width));
551     val.append("; MAX_MERGE_WIDTH=");
552     val.append(std::to_string(compac_opts.max_merge_width));
553     val.append("; MAX_SIZE_AMPLIFICATION_PERCENT=");
554     val.append(std::to_string(compac_opts.max_size_amplification_percent));
555     val.append("; COMPRESSION_SIZE_PERCENT=");
556     val.append(std::to_string(compac_opts.compression_size_percent));
557     val.append("; STOP_STYLE=");
558     switch (compac_opts.stop_style) {
559     case rocksdb::kCompactionStopStyleSimilarSize:
560       val.append("kCompactionStopStyleSimilarSize}");
561       break;
562     case rocksdb::kCompactionStopStyleTotalSize:
563       val.append("kCompactionStopStyleTotalSize}");
564       break;
565     default:
566       val.append("}");
567     }
568     cf_option_types.push_back({"COMPACTION_OPTIONS_UNIVERSAL", val});
569 
570     // get COMPACTION_OPTION_FIFO option
571     cf_option_types.push_back(
572         {"COMPACTION_OPTION_FIFO::MAX_TABLE_FILES_SIZE",
573          std::to_string(opts.compaction_options_fifo.max_table_files_size)});
574 
575     // get block-based table related options
576     const rocksdb::BlockBasedTableOptions &table_options =
577         rdb_get_table_options();
578 
579     // get BLOCK_BASED_TABLE_FACTORY::CACHE_INDEX_AND_FILTER_BLOCKS option
580     cf_option_types.push_back(
581         {"BLOCK_BASED_TABLE_FACTORY::CACHE_INDEX_AND_FILTER_BLOCKS",
582          table_options.cache_index_and_filter_blocks ? "1" : "0"});
583 
584     // get BLOCK_BASED_TABLE_FACTORY::INDEX_TYPE option value
585     switch (table_options.index_type) {
586     case rocksdb::BlockBasedTableOptions::kBinarySearch:
587       val = "kBinarySearch";
588       break;
589     case rocksdb::BlockBasedTableOptions::kHashSearch:
590       val = "kHashSearch";
591       break;
592     default:
593       val = "NULL";
594     }
595     cf_option_types.push_back({"BLOCK_BASED_TABLE_FACTORY::INDEX_TYPE", val});
596 
597     // get BLOCK_BASED_TABLE_FACTORY::HASH_INDEX_ALLOW_COLLISION option value
598     cf_option_types.push_back(
599         {"BLOCK_BASED_TABLE_FACTORY::HASH_INDEX_ALLOW_COLLISION",
600          table_options.hash_index_allow_collision ? "ON" : "OFF"});
601 
602     // get BLOCK_BASED_TABLE_FACTORY::CHECKSUM option value
603     switch (table_options.checksum) {
604     case rocksdb::kNoChecksum:
605       val = "kNoChecksum";
606       break;
607     case rocksdb::kCRC32c:
608       val = "kCRC32c";
609       break;
610     case rocksdb::kxxHash:
611       val = "kxxHash";
612       break;
613     default:
614       val = "NULL";
615     }
616     cf_option_types.push_back({"BLOCK_BASED_TABLE_FACTORY::CHECKSUM", val});
617 
618     // get BLOCK_BASED_TABLE_FACTORY::NO_BLOCK_CACHE option value
619     cf_option_types.push_back({"BLOCK_BASED_TABLE_FACTORY::NO_BLOCK_CACHE",
620                                table_options.no_block_cache ? "ON" : "OFF"});
621 
622     // get BLOCK_BASED_TABLE_FACTORY::FILTER_POLICY option
623     cf_option_types.push_back(
624         {"BLOCK_BASED_TABLE_FACTORY::FILTER_POLICY",
625          table_options.filter_policy == nullptr
626              ? "NULL"
627              : std::string(table_options.filter_policy->Name())});
628 
629     // get BLOCK_BASED_TABLE_FACTORY::WHOLE_KEY_FILTERING option
630     cf_option_types.push_back({"BLOCK_BASED_TABLE_FACTORY::WHOLE_KEY_FILTERING",
631                                table_options.whole_key_filtering ? "1" : "0"});
632 
633     // get BLOCK_BASED_TABLE_FACTORY::BLOCK_CACHE option
634     cf_option_types.push_back(
635         {"BLOCK_BASED_TABLE_FACTORY::BLOCK_CACHE",
636          table_options.block_cache == nullptr
637              ? "NULL"
638              : std::to_string(table_options.block_cache->GetUsage())});
639 
640     // get BLOCK_BASED_TABLE_FACTORY::BLOCK_CACHE_COMPRESSED option
641     cf_option_types.push_back(
642         {"BLOCK_BASED_TABLE_FACTORY::BLOCK_CACHE_COMPRESSED",
643          table_options.block_cache_compressed == nullptr
644              ? "NULL"
645              : std::to_string(
646                    table_options.block_cache_compressed->GetUsage())});
647 
648     // get BLOCK_BASED_TABLE_FACTORY::BLOCK_SIZE option
649     cf_option_types.push_back({"BLOCK_BASED_TABLE_FACTORY::BLOCK_SIZE",
650                                std::to_string(table_options.block_size)});
651 
652     // get BLOCK_BASED_TABLE_FACTORY::BLOCK_SIZE_DEVIATION option
653     cf_option_types.push_back(
654         {"BLOCK_BASED_TABLE_FACTORY::BLOCK_SIZE_DEVIATION",
655          std::to_string(table_options.block_size_deviation)});
656 
657     // get BLOCK_BASED_TABLE_FACTORY::BLOCK_RESTART_INTERVAL option
658     cf_option_types.push_back(
659         {"BLOCK_BASED_TABLE_FACTORY::BLOCK_RESTART_INTERVAL",
660          std::to_string(table_options.block_restart_interval)});
661 
662     // get BLOCK_BASED_TABLE_FACTORY::FORMAT_VERSION option
663     cf_option_types.push_back({"BLOCK_BASED_TABLE_FACTORY::FORMAT_VERSION",
664                                std::to_string(table_options.format_version)});
665 
666     for (const auto &cf_option_type : cf_option_types) {
667       DBUG_ASSERT(tables->table != nullptr);
668       DBUG_ASSERT(tables->table->field != nullptr);
669 
670       tables->table->field[RDB_CFOPTIONS_FIELD::CF_NAME]->store(
671           cf_name.c_str(), cf_name.size(), system_charset_info);
672       tables->table->field[RDB_CFOPTIONS_FIELD::OPTION_TYPE]->store(
673           cf_option_type.first.c_str(), cf_option_type.first.size(),
674           system_charset_info);
675       tables->table->field[RDB_CFOPTIONS_FIELD::VALUE]->store(
676           cf_option_type.second.c_str(), cf_option_type.second.size(),
677           system_charset_info);
678 
679       ret = my_core::schema_table_store_record(thd, tables->table);
680 
681       if (ret)
682         DBUG_RETURN(ret);
683     }
684   }
685   DBUG_RETURN(0);
686 }
687 
688 /*
689   Support for INFORMATION_SCHEMA.ROCKSDB_GLOBAL_INFO dynamic table
690  */
691 namespace RDB_GLOBAL_INFO_FIELD {
692 enum { TYPE = 0, NAME, VALUE };
693 }
694 
695 static ST_FIELD_INFO rdb_i_s_global_info_fields_info[] = {
696     ROCKSDB_FIELD_INFO("TYPE", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
697     ROCKSDB_FIELD_INFO("NAME", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
698     ROCKSDB_FIELD_INFO("VALUE", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
699     ROCKSDB_FIELD_INFO_END};
700 
701 /*
702  * helper function for rdb_i_s_global_info_fill_table
703  * to insert (TYPE, KEY, VALUE) rows into
704  * information_schema.rocksdb_global_info
705  */
rdb_global_info_fill_row(my_core::THD * const thd,my_core::TABLE_LIST * const tables,const char * const type,const char * const name,const char * const value)706 static int rdb_global_info_fill_row(my_core::THD *const thd,
707                                     my_core::TABLE_LIST *const tables,
708                                     const char *const type,
709                                     const char *const name,
710                                     const char *const value) {
711   DBUG_ASSERT(thd != nullptr);
712   DBUG_ASSERT(tables != nullptr);
713   DBUG_ASSERT(tables->table != nullptr);
714   DBUG_ASSERT(type != nullptr);
715   DBUG_ASSERT(name != nullptr);
716   DBUG_ASSERT(value != nullptr);
717 
718   Field **field = tables->table->field;
719   DBUG_ASSERT(field != nullptr);
720 
721   field[RDB_GLOBAL_INFO_FIELD::TYPE]->store(type, strlen(type),
722                                             system_charset_info);
723   field[RDB_GLOBAL_INFO_FIELD::NAME]->store(name, strlen(name),
724                                             system_charset_info);
725   field[RDB_GLOBAL_INFO_FIELD::VALUE]->store(value, strlen(value),
726                                              system_charset_info);
727 
728   return my_core::schema_table_store_record(thd, tables->table);
729 }
730 
rdb_i_s_global_info_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)731 static int rdb_i_s_global_info_fill_table(my_core::THD *const thd,
732                                           my_core::TABLE_LIST *const tables,
733                                           my_core::Item *const cond
734                                           __attribute__((__unused__))) {
735   DBUG_ENTER_FUNC();
736 
737   DBUG_ASSERT(thd != nullptr);
738   DBUG_ASSERT(tables != nullptr);
739 
740   static const uint32_t INT_BUF_LEN = 21;
741   static const uint32_t CF_ID_INDEX_BUF_LEN = 60;
742 
743   int ret = 0;
744 
745   /* max index info */
746   const Rdb_dict_manager *const dict_manager = rdb_get_dict_manager();
747   DBUG_ASSERT(dict_manager != nullptr);
748 
749   uint32_t max_index_id;
750   char max_index_id_buf[INT_BUF_LEN] = {0};
751 
752   if (dict_manager->get_max_index_id(&max_index_id)) {
753     snprintf(max_index_id_buf, INT_BUF_LEN, "%u", max_index_id);
754     ret |= rdb_global_info_fill_row(thd, tables, "MAX_INDEX_ID", "MAX_INDEX_ID",
755                                     max_index_id_buf);
756   }
757 
758   /* cf_id -> cf_flags */
759   char cf_id_buf[INT_BUF_LEN] = {0};
760   char cf_value_buf[FN_REFLEN + 1] = {0};
761   const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
762 
763   for (const auto &cf_handle : cf_manager.get_all_cf()) {
764     DBUG_ASSERT(cf_handle != nullptr);
765 
766     uint flags;
767 
768     if (!dict_manager->get_cf_flags(cf_handle->GetID(), &flags)) {
769       // NO_LINT_DEBUG
770       sql_print_error("RocksDB: Failed to get column family flags "
771                       "from CF with id = %u. MyRocks data dictionary may "
772                       "be corrupted.",
773                       cf_handle->GetID());
774       abort_with_stack_traces();
775     }
776 
777     snprintf(cf_id_buf, INT_BUF_LEN, "%u", cf_handle->GetID());
778     snprintf(cf_value_buf, FN_REFLEN, "%s [%u]", cf_handle->GetName().c_str(),
779              flags);
780 
781     ret |= rdb_global_info_fill_row(thd, tables, "CF_FLAGS", cf_id_buf,
782                                     cf_value_buf);
783 
784     if (ret) {
785       break;
786     }
787   }
788 
789   /* DDL_DROP_INDEX_ONGOING */
790   std::unordered_set<GL_INDEX_ID> gl_index_ids;
791   dict_manager->get_ongoing_index_operation(
792       &gl_index_ids, Rdb_key_def::DDL_DROP_INDEX_ONGOING);
793   char cf_id_index_buf[CF_ID_INDEX_BUF_LEN] = {0};
794   for (auto gl_index_id : gl_index_ids) {
795     snprintf(cf_id_index_buf, CF_ID_INDEX_BUF_LEN, "cf_id:%u,index_id:%u",
796              gl_index_id.cf_id, gl_index_id.index_id);
797     ret |= rdb_global_info_fill_row(thd, tables, "DDL_DROP_INDEX_ONGOING",
798                                     cf_id_index_buf, "");
799 
800     if (ret)
801       break;
802   }
803 
804   DBUG_RETURN(ret);
805 }
806 
807 /*
808   Support for INFORMATION_SCHEMA.ROCKSDB_COMPACTION_STATS dynamic table
809  */
rdb_i_s_compact_stats_fill_table(my_core::THD * thd,my_core::TABLE_LIST * tables,my_core::Item * cond)810 static int rdb_i_s_compact_stats_fill_table(my_core::THD *thd,
811                                             my_core::TABLE_LIST *tables,
812                                             my_core::Item *cond
813                                             __attribute__((__unused__))) {
814   DBUG_ASSERT(thd != nullptr);
815   DBUG_ASSERT(tables != nullptr);
816 
817   DBUG_ENTER("rdb_i_s_global_compact_stats_table");
818 
819   int ret = 0;
820 
821   rocksdb::DB *rdb = rdb_get_rocksdb_db();
822   Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
823   DBUG_ASSERT(rdb != nullptr);
824 
825   for (auto cf_name : cf_manager.get_cf_names()) {
826     rocksdb::ColumnFamilyHandle *cfh;
827     bool is_automatic;
828     /*
829        Only the cf name is important. Whether it was generated automatically
830        does not matter, so is_automatic is ignored.
831     */
832     cfh = cf_manager.get_cf(cf_name.c_str(), "", nullptr, &is_automatic);
833     if (cfh == nullptr) {
834       continue;
835     }
836     std::map<std::string, double> props;
837     bool bool_ret __attribute__((__unused__));
838     bool_ret = rdb->GetMapProperty(cfh, "rocksdb.cfstats", &props);
839     DBUG_ASSERT(bool_ret);
840 
841     for (auto const &prop_ent : props) {
842       std::string prop_name = prop_ent.first;
843       double value = prop_ent.second;
844       std::size_t del_pos = prop_name.find('.');
845       DBUG_ASSERT(del_pos != std::string::npos);
846       std::string level_str = prop_name.substr(0, del_pos);
847       std::string type_str = prop_name.substr(del_pos + 1);
848 
849       Field **field = tables->table->field;
850       DBUG_ASSERT(field != nullptr);
851       field[0]->store(cf_name.c_str(), cf_name.size(), system_charset_info);
852       field[1]->store(level_str.c_str(), level_str.size(), system_charset_info);
853       field[2]->store(type_str.c_str(), type_str.size(), system_charset_info);
854       field[3]->store(value, true);
855 
856       ret |= my_core::schema_table_store_record(thd, tables->table);
857       if (ret != 0) {
858         DBUG_RETURN(ret);
859       }
860     }
861   }
862 
863   DBUG_RETURN(ret);
864 }
865 
866 static ST_FIELD_INFO rdb_i_s_compact_stats_fields_info[] = {
867     ROCKSDB_FIELD_INFO("CF_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
868     ROCKSDB_FIELD_INFO("LEVEL", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
869     ROCKSDB_FIELD_INFO("TYPE", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
870     ROCKSDB_FIELD_INFO("VALUE", sizeof(double), MYSQL_TYPE_DOUBLE, 0),
871     ROCKSDB_FIELD_INFO_END};
872 
873 namespace // anonymous namespace = not visible outside this source file
874 {
875 struct Rdb_ddl_scanner : public Rdb_tables_scanner {
876   my_core::THD *m_thd;
877   my_core::TABLE *m_table;
878 
879   int add_table(Rdb_tbl_def *tdef) override;
880 };
881 } // anonymous namespace
882 
883 /*
884   Support for INFORMATION_SCHEMA.ROCKSDB_DDL dynamic table
885  */
886 namespace RDB_DDL_FIELD {
887 enum {
888   TABLE_SCHEMA = 0,
889   TABLE_NAME,
890   PARTITION_NAME,
891   INDEX_NAME,
892   COLUMN_FAMILY,
893   INDEX_NUMBER,
894   INDEX_TYPE,
895   KV_FORMAT_VERSION,
896   CF
897 };
898 } // namespace RDB_DDL_FIELD
899 
900 static ST_FIELD_INFO rdb_i_s_ddl_fields_info[] = {
901     ROCKSDB_FIELD_INFO("TABLE_SCHEMA", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
902     ROCKSDB_FIELD_INFO("TABLE_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
903     ROCKSDB_FIELD_INFO("PARTITION_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING,
904                        MY_I_S_MAYBE_NULL),
905     ROCKSDB_FIELD_INFO("INDEX_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
906     ROCKSDB_FIELD_INFO("COLUMN_FAMILY", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
907     ROCKSDB_FIELD_INFO("INDEX_NUMBER", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
908     ROCKSDB_FIELD_INFO("INDEX_TYPE", sizeof(uint16_t), MYSQL_TYPE_SHORT, 0),
909     ROCKSDB_FIELD_INFO("KV_FORMAT_VERSION", sizeof(uint16_t), MYSQL_TYPE_SHORT,
910                        0),
911     ROCKSDB_FIELD_INFO("CF", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
912     ROCKSDB_FIELD_INFO_END};
913 
add_table(Rdb_tbl_def * tdef)914 int Rdb_ddl_scanner::add_table(Rdb_tbl_def *tdef) {
915   DBUG_ASSERT(tdef != nullptr);
916 
917   int ret = 0;
918 
919   DBUG_ASSERT(m_table != nullptr);
920   Field **field = m_table->field;
921   DBUG_ASSERT(field != nullptr);
922 
923   const std::string &dbname = tdef->base_dbname();
924   field[RDB_DDL_FIELD::TABLE_SCHEMA]->store(dbname.c_str(), dbname.size(),
925                                             system_charset_info);
926 
927   const std::string &tablename = tdef->base_tablename();
928   field[RDB_DDL_FIELD::TABLE_NAME]->store(tablename.c_str(), tablename.size(),
929                                           system_charset_info);
930 
931   const std::string &partname = tdef->base_partition();
932   if (partname.length() == 0) {
933     field[RDB_DDL_FIELD::PARTITION_NAME]->set_null();
934   } else {
935     field[RDB_DDL_FIELD::PARTITION_NAME]->set_notnull();
936     field[RDB_DDL_FIELD::PARTITION_NAME]->store(
937         partname.c_str(), partname.size(), system_charset_info);
938   }
939 
940   for (uint i = 0; i < tdef->m_key_count; i++) {
941     const Rdb_key_def &kd = *tdef->m_key_descr_arr[i];
942 
943     field[RDB_DDL_FIELD::INDEX_NAME]->store(kd.m_name.c_str(), kd.m_name.size(),
944                                             system_charset_info);
945 
946     GL_INDEX_ID gl_index_id = kd.get_gl_index_id();
947     field[RDB_DDL_FIELD::COLUMN_FAMILY]->store(gl_index_id.cf_id, true);
948     field[RDB_DDL_FIELD::INDEX_NUMBER]->store(gl_index_id.index_id, true);
949     field[RDB_DDL_FIELD::INDEX_TYPE]->store(kd.m_index_type, true);
950     field[RDB_DDL_FIELD::KV_FORMAT_VERSION]->store(kd.m_kv_format_version,
951                                                    true);
952 
953     std::string cf_name = kd.get_cf()->GetName();
954     field[RDB_DDL_FIELD::CF]->store(cf_name.c_str(), cf_name.size(),
955                                     system_charset_info);
956 
957     ret = my_core::schema_table_store_record(m_thd, m_table);
958     if (ret)
959       return ret;
960   }
961   return HA_EXIT_SUCCESS;
962 }
963 
rdb_i_s_ddl_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)964 static int rdb_i_s_ddl_fill_table(my_core::THD *const thd,
965                                   my_core::TABLE_LIST *const tables,
966                                   my_core::Item *const cond) {
967   DBUG_ENTER_FUNC();
968 
969   DBUG_ASSERT(thd != nullptr);
970   DBUG_ASSERT(tables != nullptr);
971 
972   Rdb_ddl_scanner ddl_arg;
973   ddl_arg.m_thd = thd;
974   ddl_arg.m_table = tables->table;
975 
976   Rdb_ddl_manager *ddl_manager = rdb_get_ddl_manager();
977   DBUG_ASSERT(ddl_manager != nullptr);
978   int ret = ddl_manager->scan_for_tables(&ddl_arg);
979 
980   DBUG_RETURN(ret);
981 }
982 
rdb_i_s_ddl_init(void * const p)983 static int rdb_i_s_ddl_init(void *const p) {
984   DBUG_ENTER_FUNC();
985 
986   my_core::ST_SCHEMA_TABLE *schema;
987 
988   DBUG_ASSERT(p != nullptr);
989 
990   schema = (my_core::ST_SCHEMA_TABLE *)p;
991 
992   schema->fields_info = rdb_i_s_ddl_fields_info;
993   schema->fill_table = rdb_i_s_ddl_fill_table;
994 
995   DBUG_RETURN(0);
996 }
997 
rdb_i_s_cfoptions_init(void * const p)998 static int rdb_i_s_cfoptions_init(void *const p) {
999   DBUG_ENTER_FUNC();
1000 
1001   DBUG_ASSERT(p != nullptr);
1002 
1003   my_core::ST_SCHEMA_TABLE *schema;
1004 
1005   schema = (my_core::ST_SCHEMA_TABLE *)p;
1006 
1007   schema->fields_info = rdb_i_s_cfoptions_fields_info;
1008   schema->fill_table = rdb_i_s_cfoptions_fill_table;
1009 
1010   DBUG_RETURN(0);
1011 }
1012 
rdb_i_s_global_info_init(void * const p)1013 static int rdb_i_s_global_info_init(void *const p) {
1014   DBUG_ENTER_FUNC();
1015 
1016   DBUG_ASSERT(p != nullptr);
1017 
1018   my_core::ST_SCHEMA_TABLE *schema;
1019 
1020   schema = reinterpret_cast<my_core::ST_SCHEMA_TABLE *>(p);
1021 
1022   schema->fields_info = rdb_i_s_global_info_fields_info;
1023   schema->fill_table = rdb_i_s_global_info_fill_table;
1024 
1025   DBUG_RETURN(0);
1026 }
1027 
rdb_i_s_compact_stats_init(void * p)1028 static int rdb_i_s_compact_stats_init(void *p) {
1029   my_core::ST_SCHEMA_TABLE *schema;
1030 
1031   DBUG_ENTER("rdb_i_s_compact_stats_init");
1032   DBUG_ASSERT(p != nullptr);
1033 
1034   schema = reinterpret_cast<my_core::ST_SCHEMA_TABLE *>(p);
1035 
1036   schema->fields_info = rdb_i_s_compact_stats_fields_info;
1037   schema->fill_table = rdb_i_s_compact_stats_fill_table;
1038 
1039   DBUG_RETURN(0);
1040 }
1041 
1042 /* Given a path to a file return just the filename portion. */
rdb_filename_without_path(const std::string & path)1043 static std::string rdb_filename_without_path(const std::string &path) {
1044   /* Find last slash in path */
1045   const size_t pos = path.rfind('/');
1046 
1047   /* None found?  Just return the original string */
1048   if (pos == std::string::npos) {
1049     return std::string(path);
1050   }
1051 
1052   /* Return everything after the slash (or backslash) */
1053   return path.substr(pos + 1);
1054 }
1055 
1056 /*
1057   Support for INFORMATION_SCHEMA.ROCKSDB_INDEX_FILE_MAP dynamic table
1058  */
1059 namespace RDB_INDEX_FILE_MAP_FIELD {
1060 enum {
1061   COLUMN_FAMILY = 0,
1062   INDEX_NUMBER,
1063   SST_NAME,
1064   NUM_ROWS,
1065   DATA_SIZE,
1066   ENTRY_DELETES,
1067   ENTRY_SINGLEDELETES,
1068   ENTRY_MERGES,
1069   ENTRY_OTHERS
1070 };
1071 } // namespace RDB_INDEX_FILE_MAP_FIELD
1072 
1073 static ST_FIELD_INFO rdb_i_s_index_file_map_fields_info[] = {
1074     /* The information_schema.rocksdb_index_file_map virtual table has four
1075      * fields:
1076      *   COLUMN_FAMILY => the index's column family contained in the SST file
1077      *   INDEX_NUMBER => the index id contained in the SST file
1078      *   SST_NAME => the name of the SST file containing some indexes
1079      *   NUM_ROWS => the number of entries of this index id in this SST file
1080      *   DATA_SIZE => the data size stored in this SST file for this index id */
1081     ROCKSDB_FIELD_INFO("COLUMN_FAMILY", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1082     ROCKSDB_FIELD_INFO("INDEX_NUMBER", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1083     ROCKSDB_FIELD_INFO("SST_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1084     ROCKSDB_FIELD_INFO("NUM_ROWS", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1085     ROCKSDB_FIELD_INFO("DATA_SIZE", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1086     ROCKSDB_FIELD_INFO("ENTRY_DELETES", sizeof(int64_t), MYSQL_TYPE_LONGLONG,
1087                        0),
1088     ROCKSDB_FIELD_INFO("ENTRY_SINGLEDELETES", sizeof(int64_t),
1089                        MYSQL_TYPE_LONGLONG, 0),
1090     ROCKSDB_FIELD_INFO("ENTRY_MERGES", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1091     ROCKSDB_FIELD_INFO("ENTRY_OTHERS", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1092     ROCKSDB_FIELD_INFO_END};
1093 
1094 /* Fill the information_schema.rocksdb_index_file_map virtual table */
rdb_i_s_index_file_map_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)1095 static int rdb_i_s_index_file_map_fill_table(my_core::THD *const thd,
1096                                              my_core::TABLE_LIST *const tables,
1097                                              my_core::Item *const cond
1098                                              __attribute__((__unused__))) {
1099   DBUG_ENTER_FUNC();
1100 
1101   DBUG_ASSERT(thd != nullptr);
1102   DBUG_ASSERT(tables != nullptr);
1103   DBUG_ASSERT(tables->table != nullptr);
1104 
1105   int ret = 0;
1106   Field **field = tables->table->field;
1107   DBUG_ASSERT(field != nullptr);
1108 
1109   /* Iterate over all the column families */
1110   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
1111   DBUG_ASSERT(rdb != nullptr);
1112 
1113   const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
1114   for (const auto &cf_handle : cf_manager.get_all_cf()) {
1115     /* Grab the the properties of all the tables in the column family */
1116     rocksdb::TablePropertiesCollection table_props_collection;
1117     const rocksdb::Status s =
1118         rdb->GetPropertiesOfAllTables(cf_handle, &table_props_collection);
1119     if (!s.ok()) {
1120       continue;
1121     }
1122 
1123     /* Iterate over all the items in the collection, each of which contains a
1124      * name and the actual properties */
1125     for (const auto &props : table_props_collection) {
1126       /* Add the SST name into the output */
1127       const std::string sst_name = rdb_filename_without_path(props.first);
1128       field[RDB_INDEX_FILE_MAP_FIELD::SST_NAME]->store(
1129           sst_name.data(), sst_name.size(), system_charset_info);
1130 
1131       /* Get the __indexstats__ data out of the table property */
1132       std::vector<Rdb_index_stats> stats;
1133       Rdb_tbl_prop_coll::read_stats_from_tbl_props(props.second, &stats);
1134       if (stats.empty()) {
1135         field[RDB_INDEX_FILE_MAP_FIELD::COLUMN_FAMILY]->store(-1, true);
1136         field[RDB_INDEX_FILE_MAP_FIELD::INDEX_NUMBER]->store(-1, true);
1137         field[RDB_INDEX_FILE_MAP_FIELD::NUM_ROWS]->store(-1, true);
1138         field[RDB_INDEX_FILE_MAP_FIELD::DATA_SIZE]->store(-1, true);
1139         field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_DELETES]->store(-1, true);
1140         field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_SINGLEDELETES]->store(-1, true);
1141         field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_MERGES]->store(-1, true);
1142         field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_OTHERS]->store(-1, true);
1143       } else {
1144         for (auto it : stats) {
1145           /* Add the index number, the number of rows, and data size to the
1146            * output */
1147           field[RDB_INDEX_FILE_MAP_FIELD::COLUMN_FAMILY]->store(
1148               it.m_gl_index_id.cf_id, true);
1149           field[RDB_INDEX_FILE_MAP_FIELD::INDEX_NUMBER]->store(
1150               it.m_gl_index_id.index_id, true);
1151           field[RDB_INDEX_FILE_MAP_FIELD::NUM_ROWS]->store(it.m_rows, true);
1152           field[RDB_INDEX_FILE_MAP_FIELD::DATA_SIZE]->store(it.m_data_size,
1153                                                             true);
1154           field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_DELETES]->store(
1155               it.m_entry_deletes, true);
1156           field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_SINGLEDELETES]->store(
1157               it.m_entry_single_deletes, true);
1158           field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_MERGES]->store(
1159               it.m_entry_merges, true);
1160           field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_OTHERS]->store(
1161               it.m_entry_others, true);
1162 
1163           /* Tell MySQL about this row in the virtual table */
1164           ret = my_core::schema_table_store_record(thd, tables->table);
1165           if (ret != 0) {
1166             break;
1167           }
1168         }
1169       }
1170     }
1171   }
1172 
1173   DBUG_RETURN(ret);
1174 }
1175 
1176 /* Initialize the information_schema.rocksdb_index_file_map virtual table */
rdb_i_s_index_file_map_init(void * const p)1177 static int rdb_i_s_index_file_map_init(void *const p) {
1178   DBUG_ENTER_FUNC();
1179 
1180   DBUG_ASSERT(p != nullptr);
1181 
1182   my_core::ST_SCHEMA_TABLE *schema;
1183 
1184   schema = (my_core::ST_SCHEMA_TABLE *)p;
1185 
1186   schema->fields_info = rdb_i_s_index_file_map_fields_info;
1187   schema->fill_table = rdb_i_s_index_file_map_fill_table;
1188 
1189   DBUG_RETURN(0);
1190 }
1191 
1192 /*
1193   Support for INFORMATION_SCHEMA.ROCKSDB_LOCKS dynamic table
1194  */
1195 namespace RDB_LOCKS_FIELD {
1196 enum { COLUMN_FAMILY_ID = 0, TRANSACTION_ID, KEY, MODE };
1197 } // namespace RDB_LOCKS_FIELD
1198 
1199 static ST_FIELD_INFO rdb_i_s_lock_info_fields_info[] = {
1200     ROCKSDB_FIELD_INFO("COLUMN_FAMILY_ID", sizeof(uint32_t), MYSQL_TYPE_LONG,
1201                        0),
1202     ROCKSDB_FIELD_INFO("TRANSACTION_ID", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1203     ROCKSDB_FIELD_INFO("KEY", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
1204     ROCKSDB_FIELD_INFO("MODE", 32, MYSQL_TYPE_STRING, 0),
1205     ROCKSDB_FIELD_INFO_END};
1206 
1207 /* Fill the information_schema.rocksdb_locks virtual table */
rdb_i_s_lock_info_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)1208 static int rdb_i_s_lock_info_fill_table(my_core::THD *const thd,
1209                                         my_core::TABLE_LIST *const tables,
1210                                         my_core::Item *const cond
1211                                         __attribute__((__unused__))) {
1212   DBUG_ENTER_FUNC();
1213 
1214   DBUG_ASSERT(thd != nullptr);
1215   DBUG_ASSERT(tables != nullptr);
1216   DBUG_ASSERT(tables->table != nullptr);
1217 
1218   int ret = 0;
1219 
1220   rocksdb::TransactionDB *const rdb = rdb_get_rocksdb_db();
1221   DBUG_ASSERT(rdb != nullptr);
1222 
1223   /* cf id -> rocksdb::KeyLockInfo */
1224   std::unordered_multimap<uint32_t, rocksdb::KeyLockInfo> lock_info =
1225       rdb->GetLockStatusData();
1226 
1227   for (const auto &lock : lock_info) {
1228     const uint32_t cf_id = lock.first;
1229     const auto &key_lock_info = lock.second;
1230     const auto key_hexstr = rdb_hexdump(key_lock_info.key.c_str(),
1231                                         key_lock_info.key.length(), FN_REFLEN);
1232 
1233     for (const auto &id : key_lock_info.ids) {
1234       tables->table->field[RDB_LOCKS_FIELD::COLUMN_FAMILY_ID]->store(cf_id,
1235                                                                      true);
1236       tables->table->field[RDB_LOCKS_FIELD::TRANSACTION_ID]->store(id, true);
1237 
1238       tables->table->field[RDB_LOCKS_FIELD::KEY]->store(
1239           key_hexstr.c_str(), key_hexstr.size(), system_charset_info);
1240       tables->table->field[RDB_LOCKS_FIELD::MODE]->store(
1241           key_lock_info.exclusive ? "X" : "S", 1, system_charset_info);
1242 
1243       /* Tell MySQL about this row in the virtual table */
1244       ret = my_core::schema_table_store_record(thd, tables->table);
1245       if (ret != 0) {
1246         break;
1247       }
1248     }
1249   }
1250   DBUG_RETURN(ret);
1251 }
1252 
1253 /* Initialize the information_schema.rocksdb_lock_info virtual table */
rdb_i_s_lock_info_init(void * const p)1254 static int rdb_i_s_lock_info_init(void *const p) {
1255   DBUG_ENTER_FUNC();
1256 
1257   DBUG_ASSERT(p != nullptr);
1258 
1259   my_core::ST_SCHEMA_TABLE *schema;
1260 
1261   schema = (my_core::ST_SCHEMA_TABLE *)p;
1262 
1263   schema->fields_info = rdb_i_s_lock_info_fields_info;
1264   schema->fill_table = rdb_i_s_lock_info_fill_table;
1265 
1266   DBUG_RETURN(0);
1267 }
1268 
1269 /*
1270   Support for INFORMATION_SCHEMA.ROCKSDB_TRX dynamic table
1271  */
1272 namespace RDB_TRX_FIELD {
1273 enum {
1274   TRANSACTION_ID = 0,
1275   STATE,
1276   NAME,
1277   WRITE_COUNT,
1278   LOCK_COUNT,
1279   TIMEOUT_SEC,
1280   WAITING_KEY,
1281   WAITING_COLUMN_FAMILY_ID,
1282   IS_REPLICATION,
1283   SKIP_TRX_API,
1284   READ_ONLY,
1285   HAS_DEADLOCK_DETECTION,
1286   NUM_ONGOING_BULKLOAD,
1287   THREAD_ID,
1288   QUERY
1289 };
1290 } // namespace RDB_TRX_FIELD
1291 
1292 static ST_FIELD_INFO rdb_i_s_trx_info_fields_info[] = {
1293     ROCKSDB_FIELD_INFO("TRANSACTION_ID", sizeof(ulonglong), MYSQL_TYPE_LONGLONG,
1294                        0),
1295     ROCKSDB_FIELD_INFO("STATE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1296     ROCKSDB_FIELD_INFO("NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1297     ROCKSDB_FIELD_INFO("WRITE_COUNT", sizeof(ulonglong), MYSQL_TYPE_LONGLONG,
1298                        0),
1299     ROCKSDB_FIELD_INFO("LOCK_COUNT", sizeof(ulonglong), MYSQL_TYPE_LONGLONG, 0),
1300     ROCKSDB_FIELD_INFO("TIMEOUT_SEC", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1301     ROCKSDB_FIELD_INFO("WAITING_KEY", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
1302     ROCKSDB_FIELD_INFO("WAITING_COLUMN_FAMILY_ID", sizeof(uint32_t),
1303                        MYSQL_TYPE_LONG, 0),
1304     ROCKSDB_FIELD_INFO("IS_REPLICATION", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1305     ROCKSDB_FIELD_INFO("SKIP_TRX_API", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1306     ROCKSDB_FIELD_INFO("READ_ONLY", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1307     ROCKSDB_FIELD_INFO("HAS_DEADLOCK_DETECTION", sizeof(uint32_t),
1308                        MYSQL_TYPE_LONG, 0),
1309     ROCKSDB_FIELD_INFO("NUM_ONGOING_BULKLOAD", sizeof(uint32_t),
1310                        MYSQL_TYPE_LONG, 0),
1311     ROCKSDB_FIELD_INFO("THREAD_ID", sizeof(ulong), MYSQL_TYPE_LONG, 0),
1312     ROCKSDB_FIELD_INFO("QUERY", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1313     ROCKSDB_FIELD_INFO_END};
1314 
1315 /* Fill the information_schema.rocksdb_trx virtual table */
rdb_i_s_trx_info_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)1316 static int rdb_i_s_trx_info_fill_table(my_core::THD *const thd,
1317                                        my_core::TABLE_LIST *const tables,
1318                                        my_core::Item *const cond
1319                                        __attribute__((__unused__))) {
1320   DBUG_ENTER_FUNC();
1321 
1322   DBUG_ASSERT(thd != nullptr);
1323   DBUG_ASSERT(tables != nullptr);
1324   DBUG_ASSERT(tables->table != nullptr);
1325 
1326   int ret = 0;
1327 
1328   const std::vector<Rdb_trx_info> &all_trx_info = rdb_get_all_trx_info();
1329 
1330   for (const auto &info : all_trx_info) {
1331     auto name_hexstr =
1332         rdb_hexdump(info.name.c_str(), info.name.length(), NAME_LEN);
1333     auto key_hexstr = rdb_hexdump(info.waiting_key.c_str(),
1334                                   info.waiting_key.length(), FN_REFLEN);
1335     tables->table->field[RDB_TRX_FIELD::TRANSACTION_ID]->store(info.trx_id,
1336                                                                true);
1337     tables->table->field[RDB_TRX_FIELD::STATE]->store(
1338         info.state.c_str(), info.state.length(), system_charset_info);
1339     tables->table->field[RDB_TRX_FIELD::NAME]->store(
1340         name_hexstr.c_str(), name_hexstr.length(), system_charset_info);
1341     tables->table->field[RDB_TRX_FIELD::WRITE_COUNT]->store(info.write_count,
1342                                                             true);
1343     tables->table->field[RDB_TRX_FIELD::LOCK_COUNT]->store(info.lock_count,
1344                                                            true);
1345     tables->table->field[RDB_TRX_FIELD::TIMEOUT_SEC]->store(info.timeout_sec,
1346                                                             false);
1347     tables->table->field[RDB_TRX_FIELD::WAITING_KEY]->store(
1348         key_hexstr.c_str(), key_hexstr.length(), system_charset_info);
1349     tables->table->field[RDB_TRX_FIELD::WAITING_COLUMN_FAMILY_ID]->store(
1350         info.waiting_cf_id, true);
1351     tables->table->field[RDB_TRX_FIELD::IS_REPLICATION]->store(
1352         info.is_replication, false);
1353     tables->table->field[RDB_TRX_FIELD::SKIP_TRX_API]->store(info.skip_trx_api,
1354                                                              false);
1355     tables->table->field[RDB_TRX_FIELD::READ_ONLY]->store(info.read_only,
1356                                                           false);
1357     tables->table->field[RDB_TRX_FIELD::HAS_DEADLOCK_DETECTION]->store(
1358         info.deadlock_detect, false);
1359     tables->table->field[RDB_TRX_FIELD::NUM_ONGOING_BULKLOAD]->store(
1360         info.num_ongoing_bulk_load, false);
1361     tables->table->field[RDB_TRX_FIELD::THREAD_ID]->store(info.thread_id, true);
1362     tables->table->field[RDB_TRX_FIELD::QUERY]->store(
1363         info.query_str.c_str(), info.query_str.length(), system_charset_info);
1364 
1365     /* Tell MySQL about this row in the virtual table */
1366     ret = my_core::schema_table_store_record(thd, tables->table);
1367     if (ret != 0) {
1368       break;
1369     }
1370   }
1371 
1372   DBUG_RETURN(ret);
1373 }
1374 
1375 /* Initialize the information_schema.rocksdb_trx_info virtual table */
rdb_i_s_trx_info_init(void * const p)1376 static int rdb_i_s_trx_info_init(void *const p) {
1377   DBUG_ENTER_FUNC();
1378 
1379   DBUG_ASSERT(p != nullptr);
1380 
1381   my_core::ST_SCHEMA_TABLE *schema;
1382 
1383   schema = (my_core::ST_SCHEMA_TABLE *)p;
1384 
1385   schema->fields_info = rdb_i_s_trx_info_fields_info;
1386   schema->fill_table = rdb_i_s_trx_info_fill_table;
1387 
1388   DBUG_RETURN(0);
1389 }
1390 
rdb_i_s_deinit(void * p)1391 static int rdb_i_s_deinit(void *p __attribute__((__unused__))) {
1392   DBUG_ENTER_FUNC();
1393   DBUG_RETURN(0);
1394 }
1395 
1396 static struct st_mysql_information_schema rdb_i_s_info = {
1397     MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION};
1398 
1399 struct st_mysql_plugin rdb_i_s_cfstats = {
1400     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1401     &rdb_i_s_info,
1402     "ROCKSDB_CFSTATS",
1403     "Facebook",
1404     "RocksDB column family stats",
1405     PLUGIN_LICENSE_GPL,
1406     rdb_i_s_cfstats_init,
1407     rdb_i_s_deinit,
1408     0x0001,  /* version number (0.1) */
1409     nullptr, /* status variables */
1410     nullptr, /* system variables */
1411     nullptr, /* config options */
1412     0,       /* flags */
1413 };
1414 
1415 struct st_mysql_plugin rdb_i_s_dbstats = {
1416     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1417     &rdb_i_s_info,
1418     "ROCKSDB_DBSTATS",
1419     "Facebook",
1420     "RocksDB database stats",
1421     PLUGIN_LICENSE_GPL,
1422     rdb_i_s_dbstats_init,
1423     rdb_i_s_deinit,
1424     0x0001,  /* version number (0.1) */
1425     nullptr, /* status variables */
1426     nullptr, /* system variables */
1427     nullptr, /* config options */
1428     0,       /* flags */
1429 };
1430 
1431 struct st_mysql_plugin rdb_i_s_perf_context = {
1432     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1433     &rdb_i_s_info,
1434     "ROCKSDB_PERF_CONTEXT",
1435     "Facebook",
1436     "RocksDB perf context stats",
1437     PLUGIN_LICENSE_GPL,
1438     rdb_i_s_perf_context_init,
1439     rdb_i_s_deinit,
1440     0x0001,  /* version number (0.1) */
1441     nullptr, /* status variables */
1442     nullptr, /* system variables */
1443     nullptr, /* config options */
1444     0,       /* flags */
1445 };
1446 
1447 struct st_mysql_plugin rdb_i_s_perf_context_global = {
1448     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1449     &rdb_i_s_info,
1450     "ROCKSDB_PERF_CONTEXT_GLOBAL",
1451     "Facebook",
1452     "RocksDB perf context stats (all)",
1453     PLUGIN_LICENSE_GPL,
1454     rdb_i_s_perf_context_global_init,
1455     rdb_i_s_deinit,
1456     0x0001,  /* version number (0.1) */
1457     nullptr, /* status variables */
1458     nullptr, /* system variables */
1459     nullptr, /* config options */
1460     0,       /* flags */
1461 };
1462 
1463 struct st_mysql_plugin rdb_i_s_cfoptions = {
1464     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1465     &rdb_i_s_info,
1466     "ROCKSDB_CF_OPTIONS",
1467     "Facebook",
1468     "RocksDB column family options",
1469     PLUGIN_LICENSE_GPL,
1470     rdb_i_s_cfoptions_init,
1471     rdb_i_s_deinit,
1472     0x0001,  /* version number (0.1) */
1473     nullptr, /* status variables */
1474     nullptr, /* system variables */
1475     nullptr, /* config options */
1476     0,       /* flags */
1477 };
1478 
1479 struct st_mysql_plugin rdb_i_s_global_info = {
1480     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1481     &rdb_i_s_info,
1482     "ROCKSDB_GLOBAL_INFO",
1483     "Facebook",
1484     "RocksDB global info",
1485     PLUGIN_LICENSE_GPL,
1486     rdb_i_s_global_info_init,
1487     rdb_i_s_deinit,
1488     0x0001,  /* version number (0.1) */
1489     nullptr, /* status variables */
1490     nullptr, /* system variables */
1491     nullptr, /* config options */
1492     0,       /* flags */
1493 };
1494 
1495 struct st_mysql_plugin rdb_i_s_compact_stats = {
1496     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1497     &rdb_i_s_info,
1498     "ROCKSDB_COMPACTION_STATS",
1499     "Facebook",
1500     "RocksDB compaction stats",
1501     PLUGIN_LICENSE_GPL,
1502     rdb_i_s_compact_stats_init,
1503     rdb_i_s_deinit,
1504     0x0001,  /* version number (0.1) */
1505     nullptr, /* status variables */
1506     nullptr, /* system variables */
1507     nullptr, /* config options */
1508     0,       /* flags */
1509 };
1510 
1511 struct st_mysql_plugin rdb_i_s_ddl = {
1512     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1513     &rdb_i_s_info,
1514     "ROCKSDB_DDL",
1515     "Facebook",
1516     "RocksDB Data Dictionary",
1517     PLUGIN_LICENSE_GPL,
1518     rdb_i_s_ddl_init,
1519     rdb_i_s_deinit,
1520     0x0001,  /* version number (0.1) */
1521     nullptr, /* status variables */
1522     nullptr, /* system variables */
1523     nullptr, /* config options */
1524     0,       /* flags */
1525 };
1526 
1527 struct st_mysql_plugin rdb_i_s_index_file_map = {
1528     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1529     &rdb_i_s_info,
1530     "ROCKSDB_INDEX_FILE_MAP",
1531     "Facebook",
1532     "RocksDB index file map",
1533     PLUGIN_LICENSE_GPL,
1534     rdb_i_s_index_file_map_init,
1535     rdb_i_s_deinit,
1536     0x0001,  /* version number (0.1) */
1537     nullptr, /* status variables */
1538     nullptr, /* system variables */
1539     nullptr, /* config options */
1540     0,       /* flags */
1541 };
1542 
1543 struct st_mysql_plugin rdb_i_s_lock_info = {
1544     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1545     &rdb_i_s_info,
1546     "ROCKSDB_LOCKS",
1547     "Facebook",
1548     "RocksDB lock information",
1549     PLUGIN_LICENSE_GPL,
1550     rdb_i_s_lock_info_init,
1551     nullptr,
1552     0x0001,  /* version number (0.1) */
1553     nullptr, /* status variables */
1554     nullptr, /* system variables */
1555     nullptr, /* config options */
1556     0,       /* flags */
1557 };
1558 
1559 struct st_mysql_plugin rdb_i_s_trx_info = {
1560     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1561     &rdb_i_s_info,
1562     "ROCKSDB_TRX",
1563     "Facebook",
1564     "RocksDB transaction information",
1565     PLUGIN_LICENSE_GPL,
1566     rdb_i_s_trx_info_init,
1567     nullptr,
1568     0x0001,  /* version number (0.1) */
1569     nullptr, /* status variables */
1570     nullptr, /* system variables */
1571     nullptr, /* config options */
1572     0,       /* flags */
1573 };
1574 } // namespace myrocks
1575