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 <algorithm>
19 #include <cctype>
20 #include <map>
21 #include <string>
22 #include <vector>
23 
24 /* MySQL header files */
25 #include "sql_string.h" /* for now this must violate clang-format style as it */
26                         /* is needed before sql_show.h */
27 #include "sql_show.h"
28 #include "debug_sync.h"
29 
30 /* RocksDB header files */
31 #include "rocksdb/compaction_filter.h"
32 #include "rocksdb/convenience.h"
33 #include "rocksdb/filter_policy.h"
34 #include "rocksdb/memtablerep.h"
35 #include "rocksdb/merge_operator.h"
36 #include "rocksdb/slice_transform.h"
37 #include "rocksdb/utilities/transaction_db.h"
38 
39 /* MyRocks header files */
40 #include "./ha_rocksdb.h"
41 #include "./ha_rocksdb_proto.h"
42 #include "./rdb_cf_manager.h"
43 #include "./rdb_datadic.h"
44 #include "./rdb_utils.h"
45 
46 namespace myrocks {
47 
48 /**
49   Define the INFORMATION_SCHEMA (I_S) structures needed by MyRocks storage
50   engine.
51 */
52 
53 #define ROCKSDB_FIELD_INFO(_name_, _len_, _type_, _flag_) \
54   { _name_, _len_, _type_, 0, _flag_, nullptr, 0 }
55 
56 #define ROCKSDB_FIELD_INFO_END \
57   ROCKSDB_FIELD_INFO(nullptr, 0, MYSQL_TYPE_NULL, 0)
58 
59 /*
60   Support for INFORMATION_SCHEMA.ROCKSDB_CFSTATS dynamic table
61  */
62 namespace RDB_CFSTATS_FIELD {
63 enum { CF_NAME = 0, STAT_TYPE, VALUE };
64 }  // namespace RDB_CFSTATS_FIELD
65 
66 static ST_FIELD_INFO rdb_i_s_cfstats_fields_info[] = {
67     ROCKSDB_FIELD_INFO("CF_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
68     ROCKSDB_FIELD_INFO("STAT_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
69     ROCKSDB_FIELD_INFO("VALUE", sizeof(uint64_t), MYSQL_TYPE_LONGLONG, 0),
70     ROCKSDB_FIELD_INFO_END};
71 
rdb_i_s_cfstats_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond MY_ATTRIBUTE ((__unused__)))72 static int rdb_i_s_cfstats_fill_table(
73     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
74     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
75   DBUG_ENTER_FUNC();
76 
77   assert(tables != nullptr);
78   assert(tables->table != nullptr);
79   assert(tables->table->field != nullptr);
80 
81   int ret = 0;
82   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
83                                               false);
84   if (!rdb_get_hton_init_state()->initialized()) {
85     ret = ER_PLUGIN_IS_NOT_LOADED;
86     my_error(ret, MYF(0), rocksdb_hton_name);
87     DBUG_RETURN(ret);
88   }
89   uint64_t val;
90 
91   const std::vector<std::pair<const std::string, std::string>> cf_properties = {
92       {rocksdb::DB::Properties::kNumImmutableMemTable,
93        "NUM_IMMUTABLE_MEM_TABLE"},
94       {rocksdb::DB::Properties::kMemTableFlushPending,
95        "MEM_TABLE_FLUSH_PENDING"},
96       {rocksdb::DB::Properties::kCompactionPending, "COMPACTION_PENDING"},
97       {rocksdb::DB::Properties::kCurSizeActiveMemTable,
98        "CUR_SIZE_ACTIVE_MEM_TABLE"},
99       {rocksdb::DB::Properties::kCurSizeAllMemTables,
100        "CUR_SIZE_ALL_MEM_TABLES"},
101       {rocksdb::DB::Properties::kNumEntriesActiveMemTable,
102        "NUM_ENTRIES_ACTIVE_MEM_TABLE"},
103       {rocksdb::DB::Properties::kNumEntriesImmMemTables,
104        "NUM_ENTRIES_IMM_MEM_TABLES"},
105       {rocksdb::DB::Properties::kEstimateTableReadersMem,
106        "NON_BLOCK_CACHE_SST_MEM_USAGE"},
107       {rocksdb::DB::Properties::kNumLiveVersions, "NUM_LIVE_VERSIONS"},
108       {rocksdb::DB::Properties::kNumImmutableMemTableFlushed,
109        "NUM_IMMUTABLE_MEM_TABLE_FLUSHED"},
110       {rocksdb::DB::Properties::kNumRunningFlushes, "NUM_RUNNING_FLUSHES"},
111       {rocksdb::DB::Properties::kNumRunningCompactions,
112        "NUM_RUNNING_COMPACTIONS"},
113       {rocksdb::DB::Properties::kSizeAllMemTables, "SIZE_ALL_MEM_TABLES"},
114       {rocksdb::DB::Properties::kNumDeletesActiveMemTable,
115        "NUM_DELETES_ACTIVE_MEM_TABLE"},
116       {rocksdb::DB::Properties::kNumDeletesImmMemTables,
117        "NUM_DELETES_IMM_MEM_TABLES"},
118       {rocksdb::DB::Properties::kEstimateNumKeys, "ESTIMATE_NUM_KEYS"},
119       {rocksdb::DB::Properties::kEstimateLiveDataSize,
120        "ESTIMATE_LIVE_DATA_SIZE"},
121       {rocksdb::DB::Properties::kEstimatePendingCompactionBytes,
122        "ESTIMATE_PENDING_COMPACTION_BYTES"}};
123 
124   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
125 
126   if (!rdb) {
127     DBUG_RETURN(ret);
128   }
129 
130   const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
131 
132   for (const auto &cf_name : cf_manager.get_cf_names()) {
133     assert(!cf_name.empty());
134     std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
135         cf_manager.get_cf(cf_name);
136     if (!cfh) {
137       continue;
138     }
139 
140     // It is safe if the CF is removed from cf_manager at
141     // this point. The CF handle object is valid and sufficient here.
142     for (const auto &property : cf_properties) {
143       if (!rdb->GetIntProperty(cfh.get(), property.first, &val)) {
144         continue;
145       }
146 
147       tables->table->field[RDB_CFSTATS_FIELD::CF_NAME]->store(
148           cf_name.c_str(), cf_name.size(), system_charset_info);
149       tables->table->field[RDB_CFSTATS_FIELD::STAT_TYPE]->store(
150           property.second.c_str(), property.second.size(), system_charset_info);
151       tables->table->field[RDB_CFSTATS_FIELD::VALUE]->store(val, true);
152 
153       ret = static_cast<int>(
154           my_core::schema_table_store_record(thd, tables->table));
155 
156       if (ret) {
157         DBUG_RETURN(ret);
158       }
159     }
160   }
161 
162   DBUG_RETURN(0);
163 }
164 
rdb_i_s_cfstats_init(void * p)165 static int rdb_i_s_cfstats_init(void *p) {
166   DBUG_ENTER_FUNC();
167 
168   assert(p != nullptr);
169 
170   my_core::ST_SCHEMA_TABLE *schema;
171 
172   schema = (my_core::ST_SCHEMA_TABLE *)p;
173 
174   schema->fields_info = rdb_i_s_cfstats_fields_info;
175   schema->fill_table = rdb_i_s_cfstats_fill_table;
176 
177   DBUG_RETURN(0);
178 }
179 
180 /*
181   Support for INFORMATION_SCHEMA.ROCKSDB_DBSTATS dynamic table
182  */
183 namespace RDB_DBSTATS_FIELD {
184 enum { STAT_TYPE = 0, VALUE };
185 }  // namespace RDB_DBSTATS_FIELD
186 
187 static ST_FIELD_INFO rdb_i_s_dbstats_fields_info[] = {
188     ROCKSDB_FIELD_INFO("STAT_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
189     ROCKSDB_FIELD_INFO("VALUE", sizeof(uint64_t), MYSQL_TYPE_LONGLONG, 0),
190     ROCKSDB_FIELD_INFO_END};
191 
rdb_i_s_dbstats_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond MY_ATTRIBUTE ((__unused__)))192 static int rdb_i_s_dbstats_fill_table(
193     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
194     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
195   DBUG_ENTER_FUNC();
196 
197   assert(tables != nullptr);
198   assert(tables->table != nullptr);
199   assert(tables->table->field != nullptr);
200 
201   int ret = 0;
202   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
203                                               false);
204   if (!rdb_get_hton_init_state()->initialized()) {
205     ret = ER_PLUGIN_IS_NOT_LOADED;
206     my_error(ret, MYF(0), rocksdb_hton_name);
207     DBUG_RETURN(ret);
208   }
209   uint64_t val;
210 
211   const std::vector<std::pair<std::string, std::string>> db_properties = {
212       {rocksdb::DB::Properties::kBackgroundErrors, "DB_BACKGROUND_ERRORS"},
213       {rocksdb::DB::Properties::kNumSnapshots, "DB_NUM_SNAPSHOTS"},
214       {rocksdb::DB::Properties::kOldestSnapshotTime,
215        "DB_OLDEST_SNAPSHOT_TIME"}};
216 
217   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
218 
219   if (!rdb) {
220     DBUG_RETURN(ret);
221   }
222 
223   const rocksdb::BlockBasedTableOptions &table_options =
224       rdb_get_table_options();
225 
226   for (const auto &property : db_properties) {
227     if (!rdb->GetIntProperty(property.first, &val)) {
228       continue;
229     }
230 
231     tables->table->field[RDB_DBSTATS_FIELD::STAT_TYPE]->store(
232         property.second.c_str(), property.second.size(), system_charset_info);
233     tables->table->field[RDB_DBSTATS_FIELD::VALUE]->store(val, true);
234 
235     ret = static_cast<int>(
236         my_core::schema_table_store_record(thd, tables->table));
237 
238     if (ret) {
239       DBUG_RETURN(ret);
240     }
241   }
242 
243   /*
244     Currently, this can only show the usage of a block cache allocated
245     directly by the handlerton. If the column family config specifies a block
246     cache (i.e. the column family option has a parameter such as
247     block_based_table_factory={block_cache=1G}), then the block cache is
248     allocated within the rocksdb::GetColumnFamilyOptionsFromString().
249 
250     There is no interface to retrieve this block cache, nor fetch the usage
251     information from the column family.
252    */
253   val = (table_options.block_cache ? table_options.block_cache->GetUsage() : 0);
254 
255   tables->table->field[RDB_DBSTATS_FIELD::STAT_TYPE]->store(
256       STRING_WITH_LEN("DB_BLOCK_CACHE_USAGE"), system_charset_info);
257   tables->table->field[RDB_DBSTATS_FIELD::VALUE]->store(val, true);
258 
259   ret =
260       static_cast<int>(my_core::schema_table_store_record(thd, tables->table));
261 
262   DBUG_RETURN(ret);
263 }
264 
rdb_i_s_dbstats_init(void * const p)265 static int rdb_i_s_dbstats_init(void *const p) {
266   DBUG_ENTER_FUNC();
267 
268   assert(p != nullptr);
269 
270   my_core::ST_SCHEMA_TABLE *schema;
271 
272   schema = (my_core::ST_SCHEMA_TABLE *)p;
273 
274   schema->fields_info = rdb_i_s_dbstats_fields_info;
275   schema->fill_table = rdb_i_s_dbstats_fill_table;
276 
277   DBUG_RETURN(0);
278 }
279 
280 /*
281   Support for INFORMATION_SCHEMA.ROCKSDB_PERF_CONTEXT dynamic table
282  */
283 namespace RDB_PERF_CONTEXT_FIELD {
284 enum { TABLE_SCHEMA = 0, TABLE_NAME, PARTITION_NAME, STAT_TYPE, VALUE };
285 }  // namespace RDB_PERF_CONTEXT_FIELD
286 
287 static ST_FIELD_INFO rdb_i_s_perf_context_fields_info[] = {
288     ROCKSDB_FIELD_INFO("TABLE_SCHEMA", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
289     ROCKSDB_FIELD_INFO("TABLE_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
290     ROCKSDB_FIELD_INFO("PARTITION_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING,
291                        MY_I_S_MAYBE_NULL),
292     ROCKSDB_FIELD_INFO("STAT_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
293     ROCKSDB_FIELD_INFO("VALUE", sizeof(uint64_t), MYSQL_TYPE_LONGLONG, 0),
294     ROCKSDB_FIELD_INFO_END};
295 
rdb_i_s_perf_context_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond MY_ATTRIBUTE ((__unused__)))296 static int rdb_i_s_perf_context_fill_table(
297     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
298     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
299   DBUG_ENTER_FUNC();
300 
301   assert(thd != nullptr);
302   assert(tables != nullptr);
303   assert(tables->table != nullptr);
304 
305   int ret = 0;
306   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
307                                               false);
308   if (!rdb_get_hton_init_state()->initialized()) {
309     ret = ER_PLUGIN_IS_NOT_LOADED;
310     my_error(ret, MYF(0), rocksdb_hton_name);
311     DBUG_RETURN(ret);
312   }
313 
314   Field **field = tables->table->field;
315   assert(field != nullptr);
316 
317   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
318 
319   if (!rdb) {
320     DBUG_RETURN(ret);
321   }
322 
323   const std::vector<std::string> tablenames = rdb_get_open_table_names();
324 
325   for (const auto &it : tablenames) {
326     std::string str, dbname, tablename, partname;
327     Rdb_perf_counters counters;
328 
329     int rc = rdb_normalize_tablename(it, &str);
330 
331     if (rc != HA_EXIT_SUCCESS) {
332       DBUG_RETURN(rc);
333     }
334 
335     if (rdb_split_normalized_tablename(str, &dbname, &tablename, &partname)) {
336       continue;
337     }
338 
339     if (rdb_get_table_perf_counters(it.c_str(), &counters)) {
340       continue;
341     }
342 
343     field[RDB_PERF_CONTEXT_FIELD::TABLE_SCHEMA]->store(
344         dbname.c_str(), dbname.size(), system_charset_info);
345     field[RDB_PERF_CONTEXT_FIELD::TABLE_NAME]->store(
346         tablename.c_str(), tablename.size(), system_charset_info);
347 
348     if (partname.size() == 0) {
349       field[RDB_PERF_CONTEXT_FIELD::PARTITION_NAME]->set_null();
350     } else {
351       field[RDB_PERF_CONTEXT_FIELD::PARTITION_NAME]->set_notnull();
352       field[RDB_PERF_CONTEXT_FIELD::PARTITION_NAME]->store(
353           partname.c_str(), partname.size(), system_charset_info);
354     }
355 
356     for (int i = 0; i < PC_MAX_IDX; i++) {
357       field[RDB_PERF_CONTEXT_FIELD::STAT_TYPE]->store(
358           rdb_pc_stat_types[i].c_str(), rdb_pc_stat_types[i].size(),
359           system_charset_info);
360       field[RDB_PERF_CONTEXT_FIELD::VALUE]->store(counters.m_value[i], true);
361 
362       ret = static_cast<int>(
363           my_core::schema_table_store_record(thd, tables->table));
364 
365       if (ret) {
366         DBUG_RETURN(ret);
367       }
368     }
369   }
370 
371   DBUG_RETURN(0);
372 }
373 
rdb_i_s_perf_context_init(void * const p)374 static int rdb_i_s_perf_context_init(void *const p) {
375   DBUG_ENTER_FUNC();
376 
377   assert(p != nullptr);
378 
379   my_core::ST_SCHEMA_TABLE *schema;
380 
381   schema = (my_core::ST_SCHEMA_TABLE *)p;
382 
383   schema->fields_info = rdb_i_s_perf_context_fields_info;
384   schema->fill_table = rdb_i_s_perf_context_fill_table;
385 
386   DBUG_RETURN(0);
387 }
388 
389 /*
390   Support for INFORMATION_SCHEMA.ROCKSDB_PERF_CONTEXT_GLOBAL dynamic table
391  */
392 namespace RDB_PERF_CONTEXT_GLOBAL_FIELD {
393 enum { STAT_TYPE = 0, VALUE };
394 }  // namespace RDB_PERF_CONTEXT_GLOBAL_FIELD
395 
396 static ST_FIELD_INFO rdb_i_s_perf_context_global_fields_info[] = {
397     ROCKSDB_FIELD_INFO("STAT_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
398     ROCKSDB_FIELD_INFO("VALUE", sizeof(uint64_t), MYSQL_TYPE_LONGLONG, 0),
399     ROCKSDB_FIELD_INFO_END};
400 
rdb_i_s_perf_context_global_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond MY_ATTRIBUTE ((__unused__)))401 static int rdb_i_s_perf_context_global_fill_table(
402     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
403     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
404   DBUG_ENTER_FUNC();
405 
406   assert(thd != nullptr);
407   assert(tables != nullptr);
408   assert(tables->table != nullptr);
409   assert(tables->table->field != nullptr);
410 
411   int ret = 0;
412   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
413                                               false);
414   if (!rdb_get_hton_init_state()->initialized()) {
415     ret = ER_PLUGIN_IS_NOT_LOADED;
416     my_error(ret, MYF(0), rocksdb_hton_name);
417     DBUG_RETURN(ret);
418   }
419 
420   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
421 
422   if (!rdb) {
423     DBUG_RETURN(ret);
424   }
425 
426   // Get a copy of the global perf counters.
427   Rdb_perf_counters global_counters;
428   rdb_get_global_perf_counters(&global_counters);
429 
430   for (int i = 0; i < PC_MAX_IDX; i++) {
431     tables->table->field[RDB_PERF_CONTEXT_GLOBAL_FIELD::STAT_TYPE]->store(
432         rdb_pc_stat_types[i].c_str(), rdb_pc_stat_types[i].size(),
433         system_charset_info);
434     tables->table->field[RDB_PERF_CONTEXT_GLOBAL_FIELD::VALUE]->store(
435         global_counters.m_value[i], true);
436 
437     ret = static_cast<int>(
438         my_core::schema_table_store_record(thd, tables->table));
439 
440     if (ret) {
441       DBUG_RETURN(ret);
442     }
443   }
444 
445   DBUG_RETURN(0);
446 }
447 
rdb_i_s_perf_context_global_init(void * const p)448 static int rdb_i_s_perf_context_global_init(void *const p) {
449   DBUG_ENTER_FUNC();
450 
451   assert(p != nullptr);
452 
453   my_core::ST_SCHEMA_TABLE *schema;
454 
455   schema = (my_core::ST_SCHEMA_TABLE *)p;
456 
457   schema->fields_info = rdb_i_s_perf_context_global_fields_info;
458   schema->fill_table = rdb_i_s_perf_context_global_fill_table;
459 
460   DBUG_RETURN(0);
461 }
462 
463 /*
464   Support for INFORMATION_SCHEMA.ROCKSDB_CFOPTIONS dynamic table
465  */
466 namespace RDB_CFOPTIONS_FIELD {
467 enum { CF_NAME = 0, OPTION_TYPE, VALUE };
468 }  // namespace RDB_CFOPTIONS_FIELD
469 
470 static ST_FIELD_INFO rdb_i_s_cfoptions_fields_info[] = {
471     ROCKSDB_FIELD_INFO("CF_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
472     ROCKSDB_FIELD_INFO("OPTION_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
473     ROCKSDB_FIELD_INFO("VALUE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
474     ROCKSDB_FIELD_INFO_END};
475 
rdb_i_s_cfoptions_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond MY_ATTRIBUTE ((__unused__)))476 static int rdb_i_s_cfoptions_fill_table(
477     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
478     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
479   DBUG_ENTER_FUNC();
480 
481   assert(thd != nullptr);
482   assert(tables != nullptr);
483 
484   int ret = 0;
485   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
486                                               false);
487   if (!rdb_get_hton_init_state()->initialized()) {
488     ret = ER_PLUGIN_IS_NOT_LOADED;
489     my_error(ret, MYF(0), rocksdb_hton_name);
490     DBUG_RETURN(ret);
491   }
492 
493   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
494 
495   if (!rdb) {
496     DBUG_RETURN(ret);
497   }
498 
499   Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
500 
501   for (const auto &cf_name : cf_manager.get_cf_names()) {
502     std::string val;
503     rocksdb::ColumnFamilyOptions opts;
504 
505     assert(!cf_name.empty());
506     cf_manager.get_cf_options(cf_name, &opts);
507 
508     std::vector<std::pair<std::string, std::string>> cf_option_types = {
509         {"COMPARATOR", opts.comparator == nullptr
510                            ? "NULL"
511                            : std::string(opts.comparator->Name())},
512         {"MERGE_OPERATOR", opts.merge_operator == nullptr
513                                ? "NULL"
514                                : std::string(opts.merge_operator->Name())},
515         {"COMPACTION_FILTER",
516          opts.compaction_filter == nullptr
517              ? "NULL"
518              : std::string(opts.compaction_filter->Name())},
519         {"COMPACTION_FILTER_FACTORY",
520          opts.compaction_filter_factory == nullptr
521              ? "NULL"
522              : std::string(opts.compaction_filter_factory->Name())},
523         {"WRITE_BUFFER_SIZE", std::to_string(opts.write_buffer_size)},
524         {"MAX_WRITE_BUFFER_NUMBER",
525          std::to_string(opts.max_write_buffer_number)},
526         {"MIN_WRITE_BUFFER_NUMBER_TO_MERGE",
527          std::to_string(opts.min_write_buffer_number_to_merge)},
528         {"NUM_LEVELS", std::to_string(opts.num_levels)},
529         {"LEVEL0_FILE_NUM_COMPACTION_TRIGGER",
530          std::to_string(opts.level0_file_num_compaction_trigger)},
531         {"LEVEL0_SLOWDOWN_WRITES_TRIGGER",
532          std::to_string(opts.level0_slowdown_writes_trigger)},
533         {"LEVEL0_STOP_WRITES_TRIGGER",
534          std::to_string(opts.level0_stop_writes_trigger)},
535         {"MAX_MEM_COMPACTION_LEVEL",
536          std::to_string(opts.max_mem_compaction_level)},
537         {"TARGET_FILE_SIZE_BASE", std::to_string(opts.target_file_size_base)},
538         {"TARGET_FILE_SIZE_MULTIPLIER",
539          std::to_string(opts.target_file_size_multiplier)},
540         {"MAX_BYTES_FOR_LEVEL_BASE",
541          std::to_string(opts.max_bytes_for_level_base)},
542         {"LEVEL_COMPACTION_DYNAMIC_LEVEL_BYTES",
543          opts.level_compaction_dynamic_level_bytes ? "ON" : "OFF"},
544         {"MAX_BYTES_FOR_LEVEL_MULTIPLIER",
545          std::to_string(opts.max_bytes_for_level_multiplier)},
546         {"SOFT_RATE_LIMIT", std::to_string(opts.soft_rate_limit)},
547         {"HARD_RATE_LIMIT", std::to_string(opts.hard_rate_limit)},
548         {"RATE_LIMIT_DELAY_MAX_MILLISECONDS",
549          std::to_string(opts.rate_limit_delay_max_milliseconds)},
550         {"ARENA_BLOCK_SIZE", std::to_string(opts.arena_block_size)},
551         {"DISABLE_AUTO_COMPACTIONS",
552          opts.disable_auto_compactions ? "ON" : "OFF"},
553         {"PURGE_REDUNDANT_KVS_WHILE_FLUSH",
554          opts.purge_redundant_kvs_while_flush ? "ON" : "OFF"},
555         {"MAX_SEQUENTIAL_SKIP_IN_ITERATIONS",
556          std::to_string(opts.max_sequential_skip_in_iterations)},
557         {"MEMTABLE_FACTORY", opts.memtable_factory == nullptr
558                                  ? "NULL"
559                                  : opts.memtable_factory->Name()},
560         {"INPLACE_UPDATE_SUPPORT", opts.inplace_update_support ? "ON" : "OFF"},
561         {"INPLACE_UPDATE_NUM_LOCKS",
562          opts.inplace_update_num_locks ? "ON" : "OFF"},
563         {"MEMTABLE_PREFIX_BLOOM_BITS_RATIO",
564          std::to_string(opts.memtable_prefix_bloom_size_ratio)},
565         {"MEMTABLE_PREFIX_BLOOM_HUGE_PAGE_TLB_SIZE",
566          std::to_string(opts.memtable_huge_page_size)},
567         {"BLOOM_LOCALITY", std::to_string(opts.bloom_locality)},
568         {"MAX_SUCCESSIVE_MERGES", std::to_string(opts.max_successive_merges)},
569         {"OPTIMIZE_FILTERS_FOR_HITS",
570          (opts.optimize_filters_for_hits ? "ON" : "OFF")},
571     };
572 
573     // get MAX_BYTES_FOR_LEVEL_MULTIPLIER_ADDITIONAL option value
574     val = opts.max_bytes_for_level_multiplier_additional.empty() ? "NULL" : "";
575 
576     for (const auto &level : opts.max_bytes_for_level_multiplier_additional) {
577       val.append(std::to_string(level) + ":");
578     }
579 
580     val.pop_back();
581     cf_option_types.push_back(
582         {"MAX_BYTES_FOR_LEVEL_MULTIPLIER_ADDITIONAL", val});
583 
584     // get COMPRESSION_TYPE option value
585     GetStringFromCompressionType(&val, opts.compression);
586 
587     if (val.empty()) {
588       val = "NULL";
589     }
590 
591     cf_option_types.push_back({"COMPRESSION_TYPE", val});
592 
593     // get COMPRESSION_PER_LEVEL option value
594     val = opts.compression_per_level.empty() ? "NULL" : "";
595 
596     for (const auto &compression_type : opts.compression_per_level) {
597       std::string res;
598 
599       GetStringFromCompressionType(&res, compression_type);
600 
601       if (!res.empty()) {
602         val.append(res + ":");
603       }
604     }
605 
606     val.pop_back();
607     cf_option_types.push_back({"COMPRESSION_PER_LEVEL", val});
608 
609     // get compression_opts value
610     val = std::to_string(opts.compression_opts.window_bits) + ":";
611     val.append(std::to_string(opts.compression_opts.level) + ":");
612     val.append(std::to_string(opts.compression_opts.strategy));
613 
614     cf_option_types.push_back({"COMPRESSION_OPTS", val});
615 
616     // bottommost_compression
617     if (opts.bottommost_compression) {
618       std::string res;
619 
620       GetStringFromCompressionType(&res, opts.bottommost_compression);
621 
622       if (!res.empty()) {
623         cf_option_types.push_back({"BOTTOMMOST_COMPRESSION", res});
624       }
625     }
626 
627     // get PREFIX_EXTRACTOR option
628     cf_option_types.push_back(
629         {"PREFIX_EXTRACTOR", opts.prefix_extractor == nullptr
630                                  ? "NULL"
631                                  : std::string(opts.prefix_extractor->Name())});
632 
633     // get COMPACTION_STYLE option
634     switch (opts.compaction_style) {
635       case rocksdb::kCompactionStyleLevel:
636         val = "kCompactionStyleLevel";
637         break;
638       case rocksdb::kCompactionStyleUniversal:
639         val = "kCompactionStyleUniversal";
640         break;
641       case rocksdb::kCompactionStyleFIFO:
642         val = "kCompactionStyleFIFO";
643         break;
644       case rocksdb::kCompactionStyleNone:
645         val = "kCompactionStyleNone";
646         break;
647       default:
648         val = "NULL";
649     }
650 
651     cf_option_types.push_back({"COMPACTION_STYLE", val});
652 
653     // get COMPACTION_OPTIONS_UNIVERSAL related options
654     const rocksdb::CompactionOptionsUniversal compac_opts =
655         opts.compaction_options_universal;
656 
657     val = "{SIZE_RATIO=";
658 
659     val.append(std::to_string(compac_opts.size_ratio));
660     val.append("; MIN_MERGE_WIDTH=");
661     val.append(std::to_string(compac_opts.min_merge_width));
662     val.append("; MAX_MERGE_WIDTH=");
663     val.append(std::to_string(compac_opts.max_merge_width));
664     val.append("; MAX_SIZE_AMPLIFICATION_PERCENT=");
665     val.append(std::to_string(compac_opts.max_size_amplification_percent));
666     val.append("; COMPRESSION_SIZE_PERCENT=");
667     val.append(std::to_string(compac_opts.compression_size_percent));
668     val.append("; STOP_STYLE=");
669 
670     switch (compac_opts.stop_style) {
671       case rocksdb::kCompactionStopStyleSimilarSize:
672         val.append("kCompactionStopStyleSimilarSize}");
673         break;
674       case rocksdb::kCompactionStopStyleTotalSize:
675         val.append("kCompactionStopStyleTotalSize}");
676         break;
677       default:
678         val.append("}");
679     }
680 
681     cf_option_types.push_back({"COMPACTION_OPTIONS_UNIVERSAL", val});
682 
683     // get COMPACTION_OPTION_FIFO option
684     cf_option_types.push_back(
685         {"COMPACTION_OPTION_FIFO::MAX_TABLE_FILES_SIZE",
686          std::to_string(opts.compaction_options_fifo.max_table_files_size)});
687 
688     // get table related options
689     std::vector<std::string> table_options =
690         split_into_vector(opts.table_factory->GetPrintableOptions(), '\n');
691 
692     for (std::string option : table_options) {
693       option.erase(std::remove(option.begin(), option.end(), ' '),
694                    option.end());
695 
696       int pos = option.find(":");
697       std::string option_name = option.substr(0, pos);
698       std::string option_value = option.substr(pos + 1, option.length());
699       std::transform(option_name.begin(), option_name.end(),
700                      option_name.begin(),
701                      [](unsigned char c) { return std::toupper(c); });
702 
703       cf_option_types.push_back(
704           {"TABLE_FACTORY::" + option_name, option_value});
705     }
706 
707     for (const auto &cf_option_type : cf_option_types) {
708       assert(tables->table != nullptr);
709       assert(tables->table->field != nullptr);
710 
711       tables->table->field[RDB_CFOPTIONS_FIELD::CF_NAME]->store(
712           cf_name.c_str(), cf_name.size(), system_charset_info);
713       tables->table->field[RDB_CFOPTIONS_FIELD::OPTION_TYPE]->store(
714           cf_option_type.first.c_str(), cf_option_type.first.size(),
715           system_charset_info);
716       tables->table->field[RDB_CFOPTIONS_FIELD::VALUE]->store(
717           cf_option_type.second.c_str(), cf_option_type.second.size(),
718           system_charset_info);
719 
720       ret = static_cast<int>(
721           my_core::schema_table_store_record(thd, tables->table));
722 
723       if (ret) {
724         DBUG_RETURN(ret);
725       }
726     }
727   }
728 
729   DBUG_RETURN(0);
730 }
731 
732 /*
733   Support for INFORMATION_SCHEMA.ROCKSDB_GLOBAL_INFO dynamic table
734  */
735 namespace RDB_GLOBAL_INFO_FIELD {
736 enum { TYPE = 0, NAME, VALUE };
737 }
738 
739 static ST_FIELD_INFO rdb_i_s_global_info_fields_info[] = {
740     ROCKSDB_FIELD_INFO("TYPE", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
741     ROCKSDB_FIELD_INFO("NAME", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
742     ROCKSDB_FIELD_INFO("VALUE", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
743     ROCKSDB_FIELD_INFO_END};
744 
745 /*
746  * helper function for rdb_i_s_global_info_fill_table
747  * to insert (TYPE, KEY, VALUE) rows into
748  * information_schema.rocksdb_global_info
749  */
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)750 static int rdb_global_info_fill_row(my_core::THD *const thd,
751                                     my_core::TABLE_LIST *const tables,
752                                     const char *const type,
753                                     const char *const name,
754                                     const char *const value) {
755   assert(thd != nullptr);
756   assert(tables != nullptr);
757   assert(tables->table != nullptr);
758   assert(type != nullptr);
759   assert(name != nullptr);
760   assert(value != nullptr);
761 
762   Field **field = tables->table->field;
763   assert(field != nullptr);
764 
765   field[RDB_GLOBAL_INFO_FIELD::TYPE]->store(type, strlen(type),
766                                             system_charset_info);
767   field[RDB_GLOBAL_INFO_FIELD::NAME]->store(name, strlen(name),
768                                             system_charset_info);
769   field[RDB_GLOBAL_INFO_FIELD::VALUE]->store(value, strlen(value),
770                                              system_charset_info);
771 
772   return my_core::schema_table_store_record(thd, tables->table);
773 }
774 
rdb_i_s_global_info_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond MY_ATTRIBUTE ((__unused__)))775 static int rdb_i_s_global_info_fill_table(
776     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
777     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
778   DBUG_ENTER_FUNC();
779 
780   assert(thd != nullptr);
781   assert(tables != nullptr);
782 
783   static const uint32_t INT_BUF_LEN = 21;
784   static const uint32_t CF_ID_INDEX_BUF_LEN = 60;
785 
786   int ret = 0;
787   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
788                                               false);
789   if (!rdb_get_hton_init_state()->initialized()) {
790     ret = ER_PLUGIN_IS_NOT_LOADED;
791     my_error(ret, MYF(0), rocksdb_hton_name);
792     DBUG_RETURN(ret);
793   }
794 
795   /* max index info */
796   Rdb_dict_manager *const dict_manager = rdb_get_dict_manager();
797   assert(dict_manager != nullptr);
798 
799   uint32_t max_index_id;
800   char max_index_id_buf[INT_BUF_LEN] = {0};
801 
802   if (dict_manager->get_max_index_id(&max_index_id)) {
803     snprintf(max_index_id_buf, INT_BUF_LEN, "%u", max_index_id);
804 
805     ret |= rdb_global_info_fill_row(thd, tables, "MAX_INDEX_ID", "MAX_INDEX_ID",
806                                     max_index_id_buf);
807   }
808 
809   /* cf_id -> cf_flags */
810   char cf_id_buf[INT_BUF_LEN] = {0};
811   char cf_value_buf[FN_REFLEN + 1] = {0};
812   const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
813 
814   for (const auto &cf_handle : cf_manager.get_all_cf()) {
815     assert(cf_handle != nullptr);
816 
817     DBUG_EXECUTE_IF("information_schema_global_info", {
818       if (cf_handle->GetName() == "cf_primary_key") {
819         const char act[] =
820             "now signal ready_to_mark_cf_dropped_in_global_info "
821             "wait_for mark_cf_dropped_done_in_global_info";
822         assert(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
823       }
824     });
825 
826     uint flags;
827 
828     if (!dict_manager->get_cf_flags(cf_handle->GetID(), &flags)) {
829       // If cf flags cannot be retrieved, set flags to 0. It can happen
830       // if the CF is dropped. flags is only used to print information
831       // here and so it doesn't affect functional correctness.
832       flags = 0;
833     }
834 
835     snprintf(cf_id_buf, INT_BUF_LEN, "%u", cf_handle->GetID());
836     snprintf(cf_value_buf, FN_REFLEN, "%s [%u]", cf_handle->GetName().c_str(),
837              flags);
838 
839     ret |= rdb_global_info_fill_row(thd, tables, "CF_FLAGS", cf_id_buf,
840                                     cf_value_buf);
841 
842     if (ret) {
843       break;
844     }
845   }
846 
847   /* DDL_DROP_INDEX_ONGOING */
848   std::unordered_set<GL_INDEX_ID> gl_index_ids;
849   dict_manager->get_ongoing_index_operation(
850       &gl_index_ids, Rdb_key_def::DDL_DROP_INDEX_ONGOING);
851   char cf_id_index_buf[CF_ID_INDEX_BUF_LEN] = {0};
852 
853   for (auto gl_index_id : gl_index_ids) {
854     snprintf(cf_id_index_buf, CF_ID_INDEX_BUF_LEN, "cf_id:%u,index_id:%u",
855              gl_index_id.cf_id, gl_index_id.index_id);
856 
857     ret |= rdb_global_info_fill_row(thd, tables, "DDL_DROP_INDEX_ONGOING",
858                                     cf_id_index_buf, "");
859 
860     if (ret) {
861       break;
862     }
863   }
864 
865   DBUG_RETURN(ret);
866 }
867 
868 /*
869   Support for INFORMATION_SCHEMA.ROCKSDB_COMPACTION_STATS dynamic table
870  */
rdb_i_s_compact_stats_fill_table(my_core::THD * thd,my_core::TABLE_LIST * tables,my_core::Item * cond MY_ATTRIBUTE ((__unused__)))871 static int rdb_i_s_compact_stats_fill_table(
872     my_core::THD *thd, my_core::TABLE_LIST *tables,
873     my_core::Item *cond MY_ATTRIBUTE((__unused__))) {
874   assert(thd != nullptr);
875   assert(tables != nullptr);
876 
877   DBUG_ENTER_FUNC();
878 
879   int ret = 0;
880   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
881                                               false);
882   if (!rdb_get_hton_init_state()->initialized()) {
883     ret = ER_PLUGIN_IS_NOT_LOADED;
884     my_error(ret, MYF(0), rocksdb_hton_name);
885     DBUG_RETURN(ret);
886   }
887 
888   rocksdb::DB *rdb = rdb_get_rocksdb_db();
889 
890   if (!rdb) {
891     DBUG_RETURN(ret);
892   }
893 
894   Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
895 
896   for (const auto &cf_name : cf_manager.get_cf_names()) {
897     std::shared_ptr<rocksdb::ColumnFamilyHandle> cfh =
898         cf_manager.get_cf(cf_name);
899 
900     if (!cfh) {
901       continue;
902     }
903 
904     // It is safe if the CF is removed from cf_manager at
905     // this point. The CF handle object is valid and sufficient here.
906     std::map<std::string, std::string> props;
907     bool bool_ret MY_ATTRIBUTE((__unused__));
908     bool_ret = rdb->GetMapProperty(cfh.get(), "rocksdb.cfstats", &props);
909 
910     assert(bool_ret);
911 
912     const std::string prop_name_prefix = "compaction.";
913     for (auto const &prop_ent : props) {
914       std::string prop_name = prop_ent.first;
915       if (prop_name.find(prop_name_prefix) != 0) {
916         continue;
917       }
918       std::string value = prop_ent.second;
919       std::size_t del_pos = prop_name.find('.', prop_name_prefix.size());
920       assert(del_pos != std::string::npos);
921       std::string level_str = prop_name.substr(
922           prop_name_prefix.size(), del_pos - prop_name_prefix.size());
923       std::string type_str = prop_name.substr(del_pos + 1);
924 
925       Field **field = tables->table->field;
926       assert(field != nullptr);
927 
928       field[0]->store(cf_name.c_str(), cf_name.size(), system_charset_info);
929       field[1]->store(level_str.c_str(), level_str.size(), system_charset_info);
930       field[2]->store(type_str.c_str(), type_str.size(), system_charset_info);
931       field[3]->store(std::stod(value));
932 
933       ret |= static_cast<int>(
934           my_core::schema_table_store_record(thd, tables->table));
935 
936       if (ret != 0) {
937         DBUG_RETURN(ret);
938       }
939     }
940   }
941 
942   DBUG_RETURN(ret);
943 }
944 
945 static ST_FIELD_INFO rdb_i_s_compact_stats_fields_info[] = {
946     ROCKSDB_FIELD_INFO("CF_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
947     ROCKSDB_FIELD_INFO("LEVEL", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
948     ROCKSDB_FIELD_INFO("TYPE", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
949     ROCKSDB_FIELD_INFO("VALUE", sizeof(double), MYSQL_TYPE_DOUBLE, 0),
950     ROCKSDB_FIELD_INFO_END};
951 
952 namespace  // anonymous namespace = not visible outside this source file
953 {
954 struct Rdb_ddl_scanner : public Rdb_tables_scanner {
955   my_core::THD *m_thd;
956   my_core::TABLE *m_table;
957 
958   int add_table(Rdb_tbl_def *tdef) override;
959 };
960 }  // anonymous namespace
961 
962 /*
963   Support for INFORMATION_SCHEMA.ROCKSDB_DDL dynamic table
964  */
965 namespace RDB_DDL_FIELD {
966 enum {
967   TABLE_SCHEMA = 0,
968   TABLE_NAME,
969   PARTITION_NAME,
970   INDEX_NAME,
971   COLUMN_FAMILY,
972   INDEX_NUMBER,
973   INDEX_TYPE,
974   KV_FORMAT_VERSION,
975   TTL_DURATION,
976   INDEX_FLAGS,
977   CF,
978   AUTO_INCREMENT
979 };
980 }  // namespace RDB_DDL_FIELD
981 
982 static ST_FIELD_INFO rdb_i_s_ddl_fields_info[] = {
983     ROCKSDB_FIELD_INFO("TABLE_SCHEMA", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
984     ROCKSDB_FIELD_INFO("TABLE_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
985     ROCKSDB_FIELD_INFO("PARTITION_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING,
986                        MY_I_S_MAYBE_NULL),
987     ROCKSDB_FIELD_INFO("INDEX_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
988     ROCKSDB_FIELD_INFO("COLUMN_FAMILY", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
989     ROCKSDB_FIELD_INFO("INDEX_NUMBER", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
990     ROCKSDB_FIELD_INFO("INDEX_TYPE", sizeof(uint16_t), MYSQL_TYPE_SHORT, 0),
991     ROCKSDB_FIELD_INFO("KV_FORMAT_VERSION", sizeof(uint16_t), MYSQL_TYPE_SHORT,
992                        0),
993     ROCKSDB_FIELD_INFO("TTL_DURATION", sizeof(uint64), MYSQL_TYPE_LONGLONG, 0),
994     ROCKSDB_FIELD_INFO("INDEX_FLAGS", sizeof(uint64), MYSQL_TYPE_LONGLONG, 0),
995     ROCKSDB_FIELD_INFO("CF", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
996     ROCKSDB_FIELD_INFO("AUTO_INCREMENT", sizeof(uint64_t), MYSQL_TYPE_LONGLONG,
997                        MY_I_S_MAYBE_NULL | MY_I_S_UNSIGNED),
998     ROCKSDB_FIELD_INFO_END};
999 
add_table(Rdb_tbl_def * tdef)1000 int Rdb_ddl_scanner::add_table(Rdb_tbl_def *tdef) {
1001   assert(tdef != nullptr);
1002 
1003   int ret = 0;
1004 
1005   assert(m_table != nullptr);
1006   Field **field = m_table->field;
1007   assert(field != nullptr);
1008   const Rdb_dict_manager *dict_manager = rdb_get_dict_manager();
1009 
1010   const std::string &dbname = tdef->base_dbname();
1011   field[RDB_DDL_FIELD::TABLE_SCHEMA]->store(dbname.c_str(), dbname.size(),
1012                                             system_charset_info);
1013 
1014   const std::string &tablename = tdef->base_tablename();
1015   field[RDB_DDL_FIELD::TABLE_NAME]->store(tablename.c_str(), tablename.size(),
1016                                           system_charset_info);
1017 
1018   const std::string &partname = tdef->base_partition();
1019   if (partname.length() == 0) {
1020     field[RDB_DDL_FIELD::PARTITION_NAME]->set_null();
1021   } else {
1022     field[RDB_DDL_FIELD::PARTITION_NAME]->set_notnull();
1023     field[RDB_DDL_FIELD::PARTITION_NAME]->store(
1024         partname.c_str(), partname.size(), system_charset_info);
1025   }
1026 
1027   for (uint i = 0; i < tdef->m_key_count; i++) {
1028     const Rdb_key_def &kd = *tdef->m_key_descr_arr[i];
1029 
1030     field[RDB_DDL_FIELD::INDEX_NAME]->store(kd.m_name.c_str(), kd.m_name.size(),
1031                                             system_charset_info);
1032 
1033     GL_INDEX_ID gl_index_id = kd.get_gl_index_id();
1034     field[RDB_DDL_FIELD::COLUMN_FAMILY]->store(gl_index_id.cf_id, true);
1035     field[RDB_DDL_FIELD::INDEX_NUMBER]->store(gl_index_id.index_id, true);
1036     field[RDB_DDL_FIELD::INDEX_TYPE]->store(kd.m_index_type, true);
1037     field[RDB_DDL_FIELD::KV_FORMAT_VERSION]->store(kd.m_kv_format_version,
1038                                                    true);
1039     field[RDB_DDL_FIELD::TTL_DURATION]->store(kd.m_ttl_duration, true);
1040     field[RDB_DDL_FIELD::INDEX_FLAGS]->store(kd.m_index_flags_bitmap, true);
1041 
1042     std::string cf_name = kd.get_cf()->GetName();
1043     field[RDB_DDL_FIELD::CF]->store(cf_name.c_str(), cf_name.size(),
1044                                     system_charset_info);
1045     ulonglong auto_incr;
1046     if (dict_manager->get_auto_incr_val(tdef->get_autoincr_gl_index_id(),
1047                                         &auto_incr)) {
1048       field[RDB_DDL_FIELD::AUTO_INCREMENT]->set_notnull();
1049       field[RDB_DDL_FIELD::AUTO_INCREMENT]->store(auto_incr, true);
1050     } else {
1051       field[RDB_DDL_FIELD::AUTO_INCREMENT]->set_null();
1052     }
1053 
1054     ret = my_core::schema_table_store_record(m_thd, m_table);
1055     if (ret) return ret;
1056   }
1057   return HA_EXIT_SUCCESS;
1058 }
1059 
rdb_i_s_ddl_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond)1060 static int rdb_i_s_ddl_fill_table(my_core::THD *const thd,
1061                                   my_core::TABLE_LIST *const tables,
1062                                   my_core::Item *const cond) {
1063   DBUG_ENTER_FUNC();
1064 
1065   assert(thd != nullptr);
1066   assert(tables != nullptr);
1067   assert(tables->table != nullptr);
1068 
1069   int ret = 0;
1070   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
1071                                               false);
1072   if (!rdb_get_hton_init_state()->initialized()) {
1073     ret = ER_PLUGIN_IS_NOT_LOADED;
1074     my_error(ret, MYF(0), rocksdb_hton_name);
1075     DBUG_RETURN(ret);
1076   }
1077 
1078   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
1079 
1080   if (!rdb) {
1081     DBUG_RETURN(ret);
1082   }
1083 
1084   Rdb_ddl_scanner ddl_arg;
1085 
1086   ddl_arg.m_thd = thd;
1087   ddl_arg.m_table = tables->table;
1088 
1089   Rdb_ddl_manager *ddl_manager = rdb_get_ddl_manager();
1090   assert(ddl_manager != nullptr);
1091 
1092   ret = ddl_manager->scan_for_tables(&ddl_arg);
1093 
1094   DBUG_RETURN(ret);
1095 }
1096 
rdb_i_s_ddl_init(void * const p)1097 static int rdb_i_s_ddl_init(void *const p) {
1098   DBUG_ENTER_FUNC();
1099 
1100   my_core::ST_SCHEMA_TABLE *schema;
1101 
1102   assert(p != nullptr);
1103 
1104   schema = (my_core::ST_SCHEMA_TABLE *)p;
1105 
1106   schema->fields_info = rdb_i_s_ddl_fields_info;
1107   schema->fill_table = rdb_i_s_ddl_fill_table;
1108 
1109   DBUG_RETURN(0);
1110 }
1111 
rdb_i_s_cfoptions_init(void * const p)1112 static int rdb_i_s_cfoptions_init(void *const p) {
1113   DBUG_ENTER_FUNC();
1114 
1115   assert(p != nullptr);
1116 
1117   my_core::ST_SCHEMA_TABLE *schema;
1118 
1119   schema = (my_core::ST_SCHEMA_TABLE *)p;
1120 
1121   schema->fields_info = rdb_i_s_cfoptions_fields_info;
1122   schema->fill_table = rdb_i_s_cfoptions_fill_table;
1123 
1124   DBUG_RETURN(0);
1125 }
1126 
rdb_i_s_global_info_init(void * const p)1127 static int rdb_i_s_global_info_init(void *const p) {
1128   DBUG_ENTER_FUNC();
1129 
1130   assert(p != nullptr);
1131 
1132   my_core::ST_SCHEMA_TABLE *schema;
1133 
1134   schema = reinterpret_cast<my_core::ST_SCHEMA_TABLE *>(p);
1135 
1136   schema->fields_info = rdb_i_s_global_info_fields_info;
1137   schema->fill_table = rdb_i_s_global_info_fill_table;
1138 
1139   DBUG_RETURN(0);
1140 }
1141 
rdb_i_s_compact_stats_init(void * p)1142 static int rdb_i_s_compact_stats_init(void *p) {
1143   my_core::ST_SCHEMA_TABLE *schema;
1144 
1145   DBUG_ENTER_FUNC();
1146   assert(p != nullptr);
1147 
1148   schema = reinterpret_cast<my_core::ST_SCHEMA_TABLE *>(p);
1149 
1150   schema->fields_info = rdb_i_s_compact_stats_fields_info;
1151   schema->fill_table = rdb_i_s_compact_stats_fill_table;
1152 
1153   DBUG_RETURN(0);
1154 }
1155 
1156 /* Given a path to a file return just the filename portion. */
rdb_filename_without_path(const std::string & path)1157 static std::string rdb_filename_without_path(const std::string &path) {
1158   /* Find last slash in path */
1159   const size_t pos = path.rfind('/');
1160 
1161   /* None found?  Just return the original string */
1162   if (pos == std::string::npos) {
1163     return std::string(path);
1164   }
1165 
1166   /* Return everything after the slash (or backslash) */
1167   return path.substr(pos + 1);
1168 }
1169 
1170 /*
1171   Support for INFORMATION_SCHEMA.ROCKSDB_SST_PROPS dynamic table
1172  */
1173 namespace RDB_SST_PROPS_FIELD {
1174 enum {
1175   SST_NAME = 0,
1176   COLUMN_FAMILY,
1177   DATA_BLOCKS,
1178   ENTRIES,
1179   RAW_KEY_SIZE,
1180   RAW_VALUE_SIZE,
1181   DATA_BLOCK_SIZE,
1182   INDEX_BLOCK_SIZE,
1183   INDEX_PARTITIONS,
1184   TOP_LEVEL_INDEX_SIZE,
1185   FILTER_BLOCK_SIZE,
1186   COMPRESSION_ALGO,
1187   CREATION_TIME,
1188   FILE_CREATION_TIME,
1189   OLDEST_KEY_TIME,
1190   FILTER_POLICY,
1191   COMPRESSION_OPTIONS,
1192 };
1193 }  // namespace RDB_SST_PROPS_FIELD
1194 
1195 static ST_FIELD_INFO rdb_i_s_sst_props_fields_info[] = {
1196     ROCKSDB_FIELD_INFO("SST_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1197     ROCKSDB_FIELD_INFO("COLUMN_FAMILY", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1198     ROCKSDB_FIELD_INFO("DATA_BLOCKS", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1199     ROCKSDB_FIELD_INFO("ENTRIES", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1200     ROCKSDB_FIELD_INFO("RAW_KEY_SIZE", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1201     ROCKSDB_FIELD_INFO("RAW_VALUE_SIZE", sizeof(int64_t), MYSQL_TYPE_LONGLONG,
1202                        0),
1203     ROCKSDB_FIELD_INFO("DATA_BLOCK_SIZE", sizeof(int64_t), MYSQL_TYPE_LONGLONG,
1204                        0),
1205     ROCKSDB_FIELD_INFO("INDEX_BLOCK_SIZE", sizeof(int64_t), MYSQL_TYPE_LONGLONG,
1206                        0),
1207     ROCKSDB_FIELD_INFO("INDEX_PARTITIONS", sizeof(uint32_t), MYSQL_TYPE_LONG,
1208                        0),
1209     ROCKSDB_FIELD_INFO("TOP_LEVEL_INDEX_SIZE", sizeof(int64_t),
1210                        MYSQL_TYPE_LONGLONG, 0),
1211     ROCKSDB_FIELD_INFO("FILTER_BLOCK_SIZE", sizeof(int64_t),
1212                        MYSQL_TYPE_LONGLONG, 0),
1213     ROCKSDB_FIELD_INFO("COMPRESSION_ALGO", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1214     ROCKSDB_FIELD_INFO("CREATION_TIME", sizeof(int64_t), MYSQL_TYPE_LONGLONG,
1215                        0),
1216     ROCKSDB_FIELD_INFO("FILE_CREATION_TIME", sizeof(int64_t),
1217                        MYSQL_TYPE_LONGLONG, 0),
1218     ROCKSDB_FIELD_INFO("OLDEST_KEY_TIME", sizeof(int64_t), MYSQL_TYPE_LONGLONG,
1219                        0),
1220     ROCKSDB_FIELD_INFO("FILTER_POLICY", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1221     ROCKSDB_FIELD_INFO("COMPRESSION_OPTIONS", NAME_LEN + 1, MYSQL_TYPE_STRING,
1222                        0),
1223     ROCKSDB_FIELD_INFO_END};
1224 
rdb_i_s_sst_props_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond MY_ATTRIBUTE ((__unused__)))1225 static int rdb_i_s_sst_props_fill_table(
1226     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
1227     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
1228   DBUG_ENTER_FUNC();
1229 
1230   assert(thd != nullptr);
1231   assert(tables != nullptr);
1232   assert(tables->table != nullptr);
1233 
1234   int ret = 0;
1235   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
1236                                               false);
1237   if (!rdb_get_hton_init_state()->initialized()) {
1238     ret = ER_PLUGIN_IS_NOT_LOADED;
1239     my_error(ret, MYF(0), rocksdb_hton_name);
1240     DBUG_RETURN(ret);
1241   }
1242 
1243   Field **field = tables->table->field;
1244   assert(field != nullptr);
1245 
1246   /* Iterate over all the column families */
1247   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
1248 
1249   if (!rdb) {
1250     DBUG_RETURN(ret);
1251   }
1252 
1253   const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
1254 
1255   for (const auto &cf_handle : cf_manager.get_all_cf()) {
1256     /* Grab the the properties of all the tables in the column family */
1257     rocksdb::TablePropertiesCollection table_props_collection;
1258     const rocksdb::Status s =
1259         rdb->GetPropertiesOfAllTables(cf_handle.get(), &table_props_collection);
1260 
1261     if (!s.ok()) {
1262       continue;
1263     }
1264 
1265     // It is safe if the CF is removed from cf_manager at
1266     // this point. The CF handle object is valid and sufficient here.
1267     /* Iterate over all the items in the collection, each of which contains a
1268      * name and the actual properties */
1269     for (const auto &props : table_props_collection) {
1270       /* Add the SST name into the output */
1271       const std::string sst_name = rdb_filename_without_path(props.first);
1272 
1273       field[RDB_SST_PROPS_FIELD::SST_NAME]->store(
1274           sst_name.data(), sst_name.size(), system_charset_info);
1275 
1276       field[RDB_SST_PROPS_FIELD::COLUMN_FAMILY]->store(
1277           props.second->column_family_id, true);
1278       field[RDB_SST_PROPS_FIELD::DATA_BLOCKS]->store(
1279           props.second->num_data_blocks, true);
1280       field[RDB_SST_PROPS_FIELD::ENTRIES]->store(props.second->num_entries,
1281                                                  true);
1282       field[RDB_SST_PROPS_FIELD::RAW_KEY_SIZE]->store(
1283           props.second->raw_key_size, true);
1284       field[RDB_SST_PROPS_FIELD::RAW_VALUE_SIZE]->store(
1285           props.second->raw_value_size, true);
1286       field[RDB_SST_PROPS_FIELD::DATA_BLOCK_SIZE]->store(
1287           props.second->data_size, true);
1288       field[RDB_SST_PROPS_FIELD::INDEX_BLOCK_SIZE]->store(
1289           props.second->index_size, true);
1290       field[RDB_SST_PROPS_FIELD::INDEX_PARTITIONS]->store(
1291           props.second->index_partitions, true);
1292       field[RDB_SST_PROPS_FIELD::TOP_LEVEL_INDEX_SIZE]->store(
1293           props.second->top_level_index_size, true);
1294       field[RDB_SST_PROPS_FIELD::FILTER_BLOCK_SIZE]->store(
1295           props.second->filter_size, true);
1296       if (props.second->compression_name.empty()) {
1297         field[RDB_SST_PROPS_FIELD::COMPRESSION_ALGO]->set_null();
1298       } else {
1299         field[RDB_SST_PROPS_FIELD::COMPRESSION_ALGO]->store(
1300             props.second->compression_name.c_str(),
1301             props.second->compression_name.size(), system_charset_info);
1302       }
1303       field[RDB_SST_PROPS_FIELD::CREATION_TIME]->store(
1304           props.second->creation_time, true);
1305       field[RDB_SST_PROPS_FIELD::FILE_CREATION_TIME]->store(
1306           props.second->file_creation_time, true);
1307       field[RDB_SST_PROPS_FIELD::OLDEST_KEY_TIME]->store(
1308           props.second->oldest_key_time, true);
1309       if (props.second->filter_policy_name.empty()) {
1310         field[RDB_SST_PROPS_FIELD::FILTER_POLICY]->set_null();
1311       } else {
1312         field[RDB_SST_PROPS_FIELD::FILTER_POLICY]->store(
1313             props.second->filter_policy_name.c_str(),
1314             props.second->filter_policy_name.size(), system_charset_info);
1315       }
1316       if (props.second->compression_options.empty()) {
1317         field[RDB_SST_PROPS_FIELD::COMPRESSION_OPTIONS]->set_null();
1318       } else {
1319         field[RDB_SST_PROPS_FIELD::COMPRESSION_OPTIONS]->store(
1320             props.second->compression_options.c_str(),
1321             props.second->compression_options.size(), system_charset_info);
1322       }
1323 
1324       /* Tell MySQL about this row in the virtual table */
1325       ret = static_cast<int>(
1326           my_core::schema_table_store_record(thd, tables->table));
1327 
1328       if (ret != 0) {
1329         DBUG_RETURN(ret);
1330       }
1331     }
1332   }
1333 
1334   DBUG_RETURN(ret);
1335 }
1336 
1337 /* Initialize the information_schema.rocksdb_sst_props virtual table */
rdb_i_s_sst_props_init(void * const p)1338 static int rdb_i_s_sst_props_init(void *const p) {
1339   DBUG_ENTER_FUNC();
1340 
1341   assert(p != nullptr);
1342 
1343   my_core::ST_SCHEMA_TABLE *schema;
1344 
1345   schema = (my_core::ST_SCHEMA_TABLE *)p;
1346 
1347   schema->fields_info = rdb_i_s_sst_props_fields_info;
1348   schema->fill_table = rdb_i_s_sst_props_fill_table;
1349 
1350   DBUG_RETURN(0);
1351 }
1352 
1353 /*
1354   Support for INFORMATION_SCHEMA.ROCKSDB_INDEX_FILE_MAP dynamic table
1355  */
1356 namespace RDB_INDEX_FILE_MAP_FIELD {
1357 enum {
1358   COLUMN_FAMILY = 0,
1359   INDEX_NUMBER,
1360   SST_NAME,
1361   NUM_ROWS,
1362   DATA_SIZE,
1363   ENTRY_DELETES,
1364   ENTRY_SINGLEDELETES,
1365   ENTRY_MERGES,
1366   ENTRY_OTHERS,
1367   DISTINCT_KEYS_PREFIX
1368 };
1369 }  // namespace RDB_INDEX_FILE_MAP_FIELD
1370 
1371 static ST_FIELD_INFO rdb_i_s_index_file_map_fields_info[] = {
1372     /* The information_schema.rocksdb_index_file_map virtual table has four
1373      * fields:
1374      *   COLUMN_FAMILY => the index's column family contained in the SST file
1375      *   INDEX_NUMBER => the index id contained in the SST file
1376      *   SST_NAME => the name of the SST file containing some indexes
1377      *   NUM_ROWS => the number of entries of this index id in this SST file
1378      *   DATA_SIZE => the data size stored in this SST file for this index id */
1379     ROCKSDB_FIELD_INFO("COLUMN_FAMILY", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1380     ROCKSDB_FIELD_INFO("INDEX_NUMBER", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1381     ROCKSDB_FIELD_INFO("SST_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1382     ROCKSDB_FIELD_INFO("NUM_ROWS", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1383     ROCKSDB_FIELD_INFO("DATA_SIZE", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1384     ROCKSDB_FIELD_INFO("ENTRY_DELETES", sizeof(int64_t), MYSQL_TYPE_LONGLONG,
1385                        0),
1386     ROCKSDB_FIELD_INFO("ENTRY_SINGLEDELETES", sizeof(int64_t),
1387                        MYSQL_TYPE_LONGLONG, 0),
1388     ROCKSDB_FIELD_INFO("ENTRY_MERGES", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1389     ROCKSDB_FIELD_INFO("ENTRY_OTHERS", sizeof(int64_t), MYSQL_TYPE_LONGLONG, 0),
1390     ROCKSDB_FIELD_INFO("DISTINCT_KEYS_PREFIX", MAX_REF_PARTS * 25,
1391                        MYSQL_TYPE_STRING, 0),
1392     ROCKSDB_FIELD_INFO_END};
1393 
1394 /* 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 MY_ATTRIBUTE ((__unused__)))1395 static int rdb_i_s_index_file_map_fill_table(
1396     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
1397     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
1398   DBUG_ENTER_FUNC();
1399 
1400   assert(thd != nullptr);
1401   assert(tables != nullptr);
1402   assert(tables->table != nullptr);
1403 
1404   int ret = 0;
1405   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
1406                                               false);
1407   if (!rdb_get_hton_init_state()->initialized()) {
1408     ret = ER_PLUGIN_IS_NOT_LOADED;
1409     my_error(ret, MYF(0), rocksdb_hton_name);
1410     DBUG_RETURN(ret);
1411   }
1412 
1413   Field **field = tables->table->field;
1414   assert(field != nullptr);
1415 
1416   /* Iterate over all the column families */
1417   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
1418 
1419   if (!rdb) {
1420     DBUG_RETURN(ret);
1421   }
1422 
1423   const Rdb_cf_manager &cf_manager = rdb_get_cf_manager();
1424 
1425   for (const auto &cf_handle : cf_manager.get_all_cf()) {
1426     /* Grab the the properties of all the tables in the column family */
1427     rocksdb::TablePropertiesCollection table_props_collection;
1428 
1429     // It is safe if the CF is removed from cf_manager at
1430     // this point. The CF handle object is valid and sufficient here.
1431     const rocksdb::Status s =
1432         rdb->GetPropertiesOfAllTables(cf_handle.get(), &table_props_collection);
1433 
1434     if (!s.ok()) {
1435       continue;
1436     }
1437 
1438     /* Iterate over all the items in the collection, each of which contains a
1439      * name and the actual properties */
1440     for (const auto &props : table_props_collection) {
1441       /* Add the SST name into the output */
1442       const std::string sst_name = rdb_filename_without_path(props.first);
1443 
1444       field[RDB_INDEX_FILE_MAP_FIELD::SST_NAME]->store(
1445           sst_name.data(), sst_name.size(), system_charset_info);
1446 
1447       /* Get the __indexstats__ data out of the table property */
1448       std::vector<Rdb_index_stats> stats;
1449       Rdb_tbl_prop_coll::read_stats_from_tbl_props(props.second, &stats);
1450 
1451       if (stats.empty()) {
1452         field[RDB_INDEX_FILE_MAP_FIELD::COLUMN_FAMILY]->store(-1, true);
1453         field[RDB_INDEX_FILE_MAP_FIELD::INDEX_NUMBER]->store(-1, true);
1454         field[RDB_INDEX_FILE_MAP_FIELD::NUM_ROWS]->store(-1, true);
1455         field[RDB_INDEX_FILE_MAP_FIELD::DATA_SIZE]->store(-1, true);
1456         field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_DELETES]->store(-1, true);
1457         field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_SINGLEDELETES]->store(-1, true);
1458         field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_MERGES]->store(-1, true);
1459         field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_OTHERS]->store(-1, true);
1460       } else {
1461         for (const auto &it : stats) {
1462           /* Add the index number, the number of rows, and data size to the
1463            * output */
1464           field[RDB_INDEX_FILE_MAP_FIELD::COLUMN_FAMILY]->store(
1465               it.m_gl_index_id.cf_id, true);
1466           field[RDB_INDEX_FILE_MAP_FIELD::INDEX_NUMBER]->store(
1467               it.m_gl_index_id.index_id, true);
1468           field[RDB_INDEX_FILE_MAP_FIELD::NUM_ROWS]->store(it.m_rows, true);
1469           field[RDB_INDEX_FILE_MAP_FIELD::DATA_SIZE]->store(it.m_data_size,
1470                                                             true);
1471           field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_DELETES]->store(
1472               it.m_entry_deletes, true);
1473           field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_SINGLEDELETES]->store(
1474               it.m_entry_single_deletes, true);
1475           field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_MERGES]->store(
1476               it.m_entry_merges, true);
1477           field[RDB_INDEX_FILE_MAP_FIELD::ENTRY_OTHERS]->store(
1478               it.m_entry_others, true);
1479 
1480           std::string distinct_keys_prefix;
1481 
1482           for (size_t i = 0; i < it.m_distinct_keys_per_prefix.size(); i++) {
1483             if (i > 0) {
1484               distinct_keys_prefix += ",";
1485             }
1486 
1487             distinct_keys_prefix +=
1488                 std::to_string(it.m_distinct_keys_per_prefix[i]);
1489           }
1490 
1491           field[RDB_INDEX_FILE_MAP_FIELD::DISTINCT_KEYS_PREFIX]->store(
1492               distinct_keys_prefix.data(), distinct_keys_prefix.size(),
1493               system_charset_info);
1494 
1495           /* Tell MySQL about this row in the virtual table */
1496           ret = static_cast<int>(
1497               my_core::schema_table_store_record(thd, tables->table));
1498 
1499           if (ret != 0) {
1500             break;
1501           }
1502         }
1503       }
1504     }
1505   }
1506 
1507   DBUG_RETURN(ret);
1508 }
1509 
1510 /* Initialize the information_schema.rocksdb_index_file_map virtual table */
rdb_i_s_index_file_map_init(void * const p)1511 static int rdb_i_s_index_file_map_init(void *const p) {
1512   DBUG_ENTER_FUNC();
1513 
1514   assert(p != nullptr);
1515 
1516   my_core::ST_SCHEMA_TABLE *schema;
1517 
1518   schema = (my_core::ST_SCHEMA_TABLE *)p;
1519 
1520   schema->fields_info = rdb_i_s_index_file_map_fields_info;
1521   schema->fill_table = rdb_i_s_index_file_map_fill_table;
1522 
1523   DBUG_RETURN(0);
1524 }
1525 
1526 /*
1527   Support for INFORMATION_SCHEMA.ROCKSDB_LOCKS dynamic table
1528  */
1529 namespace RDB_LOCKS_FIELD {
1530 enum { COLUMN_FAMILY_ID = 0, TRANSACTION_ID, KEY, MODE };
1531 }  // namespace RDB_LOCKS_FIELD
1532 
1533 static ST_FIELD_INFO rdb_i_s_lock_info_fields_info[] = {
1534     ROCKSDB_FIELD_INFO("COLUMN_FAMILY_ID", sizeof(uint32_t), MYSQL_TYPE_LONG,
1535                        0),
1536     ROCKSDB_FIELD_INFO("TRANSACTION_ID", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1537     ROCKSDB_FIELD_INFO("KEY", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
1538     ROCKSDB_FIELD_INFO("MODE", 32, MYSQL_TYPE_STRING, 0),
1539     ROCKSDB_FIELD_INFO_END};
1540 
1541 /* 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 MY_ATTRIBUTE ((__unused__)))1542 static int rdb_i_s_lock_info_fill_table(
1543     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
1544     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
1545   DBUG_ENTER_FUNC();
1546 
1547   assert(thd != nullptr);
1548   assert(tables != nullptr);
1549   assert(tables->table != nullptr);
1550   assert(tables->table->field != nullptr);
1551 
1552   int ret = 0;
1553   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
1554                                               false);
1555   if (!rdb_get_hton_init_state()->initialized()) {
1556     ret = ER_PLUGIN_IS_NOT_LOADED;
1557     my_error(ret, MYF(0), rocksdb_hton_name);
1558     DBUG_RETURN(ret);
1559   }
1560 
1561   rocksdb::TransactionDB *const rdb = rdb_get_rocksdb_db();
1562 
1563   if (!rdb) {
1564     DBUG_RETURN(ret);
1565   }
1566 
1567   /* cf id -> rocksdb::KeyLockInfo */
1568   std::unordered_multimap<uint32_t, rocksdb::KeyLockInfo> lock_info =
1569       rdb->GetLockStatusData();
1570 
1571   for (const auto &lock : lock_info) {
1572     const uint32_t cf_id = lock.first;
1573     const auto &key_lock_info = lock.second;
1574     const auto key_hexstr = rdb_hexdump(key_lock_info.key.c_str(),
1575                                         key_lock_info.key.length(), FN_REFLEN);
1576 
1577     for (const auto &id : key_lock_info.ids) {
1578       tables->table->field[RDB_LOCKS_FIELD::COLUMN_FAMILY_ID]->store(cf_id,
1579                                                                      true);
1580       tables->table->field[RDB_LOCKS_FIELD::TRANSACTION_ID]->store(id, true);
1581 
1582       tables->table->field[RDB_LOCKS_FIELD::KEY]->store(
1583           key_hexstr.c_str(), key_hexstr.size(), system_charset_info);
1584       tables->table->field[RDB_LOCKS_FIELD::MODE]->store(
1585           key_lock_info.exclusive ? "X" : "S", 1, system_charset_info);
1586 
1587       /* Tell MySQL about this row in the virtual table */
1588       ret = static_cast<int>(
1589           my_core::schema_table_store_record(thd, tables->table));
1590 
1591       if (ret != 0) {
1592         break;
1593       }
1594     }
1595   }
1596 
1597   DBUG_RETURN(ret);
1598 }
1599 
1600 /* Initialize the information_schema.rocksdb_lock_info virtual table */
rdb_i_s_lock_info_init(void * const p)1601 static int rdb_i_s_lock_info_init(void *const p) {
1602   DBUG_ENTER_FUNC();
1603 
1604   assert(p != nullptr);
1605 
1606   my_core::ST_SCHEMA_TABLE *schema;
1607 
1608   schema = (my_core::ST_SCHEMA_TABLE *)p;
1609 
1610   schema->fields_info = rdb_i_s_lock_info_fields_info;
1611   schema->fill_table = rdb_i_s_lock_info_fill_table;
1612 
1613   DBUG_RETURN(0);
1614 }
1615 
1616 /*
1617   Support for INFORMATION_SCHEMA.ROCKSDB_TRX dynamic table
1618  */
1619 namespace RDB_TRX_FIELD {
1620 enum {
1621   TRANSACTION_ID = 0,
1622   STATE,
1623   NAME,
1624   WRITE_COUNT,
1625   LOCK_COUNT,
1626   TIMEOUT_SEC,
1627   WAITING_KEY,
1628   WAITING_COLUMN_FAMILY_ID,
1629   IS_REPLICATION,
1630   SKIP_TRX_API,
1631   READ_ONLY,
1632   HAS_DEADLOCK_DETECTION,
1633   NUM_ONGOING_BULKLOAD,
1634   THREAD_ID,
1635   QUERY
1636 };
1637 }  // namespace RDB_TRX_FIELD
1638 
1639 static ST_FIELD_INFO rdb_i_s_trx_info_fields_info[] = {
1640     ROCKSDB_FIELD_INFO("TRANSACTION_ID", sizeof(ulonglong), MYSQL_TYPE_LONGLONG,
1641                        0),
1642     ROCKSDB_FIELD_INFO("STATE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1643     ROCKSDB_FIELD_INFO("NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1644     ROCKSDB_FIELD_INFO("WRITE_COUNT", sizeof(ulonglong), MYSQL_TYPE_LONGLONG,
1645                        0),
1646     ROCKSDB_FIELD_INFO("LOCK_COUNT", sizeof(ulonglong), MYSQL_TYPE_LONGLONG, 0),
1647     ROCKSDB_FIELD_INFO("TIMEOUT_SEC", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1648     ROCKSDB_FIELD_INFO("WAITING_KEY", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
1649     ROCKSDB_FIELD_INFO("WAITING_COLUMN_FAMILY_ID", sizeof(uint32_t),
1650                        MYSQL_TYPE_LONG, 0),
1651     ROCKSDB_FIELD_INFO("IS_REPLICATION", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1652     ROCKSDB_FIELD_INFO("SKIP_TRX_API", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1653     ROCKSDB_FIELD_INFO("READ_ONLY", sizeof(uint32_t), MYSQL_TYPE_LONG, 0),
1654     ROCKSDB_FIELD_INFO("HAS_DEADLOCK_DETECTION", sizeof(uint32_t),
1655                        MYSQL_TYPE_LONG, 0),
1656     ROCKSDB_FIELD_INFO("NUM_ONGOING_BULKLOAD", sizeof(uint32_t),
1657                        MYSQL_TYPE_LONG, 0),
1658     ROCKSDB_FIELD_INFO("THREAD_ID", sizeof(ulong), MYSQL_TYPE_LONG, 0),
1659     ROCKSDB_FIELD_INFO("QUERY", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1660     ROCKSDB_FIELD_INFO_END};
1661 
1662 /* 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 MY_ATTRIBUTE ((__unused__)))1663 static int rdb_i_s_trx_info_fill_table(
1664     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
1665     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
1666   DBUG_ENTER_FUNC();
1667 
1668   assert(thd != nullptr);
1669   assert(tables != nullptr);
1670   assert(tables->table != nullptr);
1671   assert(tables->table->field != nullptr);
1672 
1673   int ret = 0;
1674   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
1675                                               false);
1676   if (!rdb_get_hton_init_state()->initialized()) {
1677     ret = ER_PLUGIN_IS_NOT_LOADED;
1678     my_error(ret, MYF(0), rocksdb_hton_name);
1679     DBUG_RETURN(ret);
1680   }
1681 
1682   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
1683 
1684   if (!rdb) {
1685     DBUG_RETURN(ret);
1686   }
1687 
1688   const std::vector<Rdb_trx_info> &all_trx_info = rdb_get_all_trx_info();
1689 
1690   for (const auto &info : all_trx_info) {
1691     auto name_hexstr =
1692         rdb_hexdump(info.name.c_str(), info.name.length(), NAME_LEN);
1693     auto key_hexstr = rdb_hexdump(info.waiting_key.c_str(),
1694                                   info.waiting_key.length(), FN_REFLEN);
1695 
1696     tables->table->field[RDB_TRX_FIELD::TRANSACTION_ID]->store(info.trx_id,
1697                                                                true);
1698     tables->table->field[RDB_TRX_FIELD::STATE]->store(
1699         info.state.c_str(), info.state.length(), system_charset_info);
1700     tables->table->field[RDB_TRX_FIELD::NAME]->store(
1701         name_hexstr.c_str(), name_hexstr.length(), system_charset_info);
1702     tables->table->field[RDB_TRX_FIELD::WRITE_COUNT]->store(info.write_count,
1703                                                             true);
1704     tables->table->field[RDB_TRX_FIELD::LOCK_COUNT]->store(info.lock_count,
1705                                                            true);
1706     tables->table->field[RDB_TRX_FIELD::TIMEOUT_SEC]->store(info.timeout_sec,
1707                                                             false);
1708     tables->table->field[RDB_TRX_FIELD::WAITING_KEY]->store(
1709         key_hexstr.c_str(), key_hexstr.length(), system_charset_info);
1710     tables->table->field[RDB_TRX_FIELD::WAITING_COLUMN_FAMILY_ID]->store(
1711         info.waiting_cf_id, true);
1712     tables->table->field[RDB_TRX_FIELD::IS_REPLICATION]->store(
1713         info.is_replication, false);
1714     tables->table->field[RDB_TRX_FIELD::SKIP_TRX_API]->store(info.skip_trx_api,
1715                                                              false);
1716     tables->table->field[RDB_TRX_FIELD::READ_ONLY]->store(info.read_only,
1717                                                           false);
1718     tables->table->field[RDB_TRX_FIELD::HAS_DEADLOCK_DETECTION]->store(
1719         info.deadlock_detect, false);
1720     tables->table->field[RDB_TRX_FIELD::NUM_ONGOING_BULKLOAD]->store(
1721         info.num_ongoing_bulk_load, false);
1722     tables->table->field[RDB_TRX_FIELD::THREAD_ID]->store(info.thread_id, true);
1723     tables->table->field[RDB_TRX_FIELD::QUERY]->store(
1724         info.query_str.c_str(), info.query_str.length(), system_charset_info);
1725 
1726     /* Tell MySQL about this row in the virtual table */
1727     ret = static_cast<int>(
1728         my_core::schema_table_store_record(thd, tables->table));
1729 
1730     if (ret != 0) {
1731       break;
1732     }
1733   }
1734 
1735   DBUG_RETURN(ret);
1736 }
1737 
1738 /* Initialize the information_schema.rocksdb_trx_info virtual table */
rdb_i_s_trx_info_init(void * const p)1739 static int rdb_i_s_trx_info_init(void *const p) {
1740   DBUG_ENTER_FUNC();
1741 
1742   assert(p != nullptr);
1743 
1744   my_core::ST_SCHEMA_TABLE *schema;
1745 
1746   schema = (my_core::ST_SCHEMA_TABLE *)p;
1747 
1748   schema->fields_info = rdb_i_s_trx_info_fields_info;
1749   schema->fill_table = rdb_i_s_trx_info_fill_table;
1750 
1751   DBUG_RETURN(0);
1752 }
1753 
1754 /*
1755   Support for INFORMATION_SCHEMA.ROCKSDB_DEADLOCK dynamic table
1756  */
1757 namespace RDB_DEADLOCK_FIELD {
1758 enum {
1759   DEADLOCK_ID = 0,
1760   TIMESTAMP,
1761   TRANSACTION_ID,
1762   CF_NAME,
1763   WAITING_KEY,
1764   LOCK_TYPE,
1765   INDEX_NAME,
1766   TABLE_NAME,
1767   ROLLED_BACK,
1768 };
1769 }  // namespace RDB_DEADLOCK_FIELD
1770 
1771 static ST_FIELD_INFO rdb_i_s_deadlock_info_fields_info[] = {
1772     ROCKSDB_FIELD_INFO("DEADLOCK_ID", sizeof(ulonglong), MYSQL_TYPE_LONGLONG,
1773                        0),
1774     ROCKSDB_FIELD_INFO("TIMESTAMP", sizeof(ulonglong), MYSQL_TYPE_LONGLONG, 0),
1775     ROCKSDB_FIELD_INFO("TRANSACTION_ID", sizeof(ulonglong), MYSQL_TYPE_LONGLONG,
1776                        0),
1777     ROCKSDB_FIELD_INFO("CF_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1778     ROCKSDB_FIELD_INFO("WAITING_KEY", FN_REFLEN + 1, MYSQL_TYPE_STRING, 0),
1779     ROCKSDB_FIELD_INFO("LOCK_TYPE", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1780     ROCKSDB_FIELD_INFO("INDEX_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1781     ROCKSDB_FIELD_INFO("TABLE_NAME", NAME_LEN + 1, MYSQL_TYPE_STRING, 0),
1782     ROCKSDB_FIELD_INFO("ROLLED_BACK", sizeof(ulonglong), MYSQL_TYPE_LONGLONG,
1783                        0),
1784     ROCKSDB_FIELD_INFO_END};
1785 
1786 /* Fill the information_schema.rocksdb_trx virtual table */
rdb_i_s_deadlock_info_fill_table(my_core::THD * const thd,my_core::TABLE_LIST * const tables,my_core::Item * const cond MY_ATTRIBUTE ((__unused__)))1787 static int rdb_i_s_deadlock_info_fill_table(
1788     my_core::THD *const thd, my_core::TABLE_LIST *const tables,
1789     my_core::Item *const cond MY_ATTRIBUTE((__unused__))) {
1790   DBUG_ENTER_FUNC();
1791 
1792   assert(thd != nullptr);
1793   assert(tables != nullptr);
1794   assert(tables->table != nullptr);
1795   assert(tables->table->field != nullptr);
1796 
1797   static const std::string str_exclusive("EXCLUSIVE");
1798   static const std::string str_shared("SHARED");
1799 
1800   int ret = 0;
1801   Rdb_hton_init_state::Scoped_lock state_lock(*rdb_get_hton_init_state(),
1802                                               false);
1803   if (!rdb_get_hton_init_state()->initialized()) {
1804     ret = ER_PLUGIN_IS_NOT_LOADED;
1805     my_error(ret, MYF(0), rocksdb_hton_name);
1806     DBUG_RETURN(ret);
1807   }
1808 
1809   rocksdb::DB *const rdb = rdb_get_rocksdb_db();
1810 
1811   if (!rdb) {
1812     DBUG_RETURN(ret);
1813   }
1814 
1815   const std::vector<Rdb_deadlock_info> &all_dl_info = rdb_get_deadlock_info();
1816 
1817   ulonglong id = 0;
1818   for (const auto &info : all_dl_info) {
1819     auto deadlock_time = info.deadlock_time;
1820     for (const auto &trx_info : info.path) {
1821       tables->table->field[RDB_DEADLOCK_FIELD::DEADLOCK_ID]->store(id, true);
1822       tables->table->field[RDB_DEADLOCK_FIELD::TIMESTAMP]->store(deadlock_time,
1823                                                                  true);
1824       tables->table->field[RDB_DEADLOCK_FIELD::TRANSACTION_ID]->store(
1825           trx_info.trx_id, true);
1826       tables->table->field[RDB_DEADLOCK_FIELD::CF_NAME]->store(
1827           trx_info.cf_name.c_str(), trx_info.cf_name.length(),
1828           system_charset_info);
1829       tables->table->field[RDB_DEADLOCK_FIELD::WAITING_KEY]->store(
1830           trx_info.waiting_key.c_str(), trx_info.waiting_key.length(),
1831           system_charset_info);
1832       if (trx_info.exclusive_lock) {
1833         tables->table->field[RDB_DEADLOCK_FIELD::LOCK_TYPE]->store(
1834             str_exclusive.c_str(), str_exclusive.length(), system_charset_info);
1835       } else {
1836         tables->table->field[RDB_DEADLOCK_FIELD::LOCK_TYPE]->store(
1837             str_shared.c_str(), str_shared.length(), system_charset_info);
1838       }
1839       tables->table->field[RDB_DEADLOCK_FIELD::INDEX_NAME]->store(
1840           trx_info.index_name.c_str(), trx_info.index_name.length(),
1841           system_charset_info);
1842       tables->table->field[RDB_DEADLOCK_FIELD::TABLE_NAME]->store(
1843           trx_info.table_name.c_str(), trx_info.table_name.length(),
1844           system_charset_info);
1845       tables->table->field[RDB_DEADLOCK_FIELD::ROLLED_BACK]->store(
1846           trx_info.trx_id == info.victim_trx_id, true);
1847 
1848       /* Tell MySQL about this row in the virtual table */
1849       ret = static_cast<int>(
1850           my_core::schema_table_store_record(thd, tables->table));
1851 
1852       if (ret != 0) {
1853         break;
1854       }
1855     }
1856     id++;
1857   }
1858 
1859   DBUG_RETURN(ret);
1860 }
1861 
1862 /* Initialize the information_schema.rocksdb_trx_info virtual table */
rdb_i_s_deadlock_info_init(void * const p)1863 static int rdb_i_s_deadlock_info_init(void *const p) {
1864   DBUG_ENTER_FUNC();
1865 
1866   assert(p != nullptr);
1867 
1868   my_core::ST_SCHEMA_TABLE *schema;
1869 
1870   schema = (my_core::ST_SCHEMA_TABLE *)p;
1871 
1872   schema->fields_info = rdb_i_s_deadlock_info_fields_info;
1873   schema->fill_table = rdb_i_s_deadlock_info_fill_table;
1874 
1875   DBUG_RETURN(0);
1876 }
1877 
rdb_i_s_deinit(void * p MY_ATTRIBUTE ((__unused__)))1878 static int rdb_i_s_deinit(void *p MY_ATTRIBUTE((__unused__))) {
1879   DBUG_ENTER_FUNC();
1880   DBUG_RETURN(0);
1881 }
1882 
1883 static struct st_mysql_information_schema rdb_i_s_info = {
1884     MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION};
1885 
1886 struct st_mysql_plugin rdb_i_s_cfstats = {
1887     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1888     &rdb_i_s_info,
1889     "ROCKSDB_CFSTATS",
1890     "Facebook",
1891     "RocksDB column family stats",
1892     PLUGIN_LICENSE_GPL,
1893     rdb_i_s_cfstats_init,
1894     rdb_i_s_deinit,
1895     0x0001,  /* version number (0.1) */
1896     nullptr, /* status variables */
1897     nullptr, /* system variables */
1898     nullptr, /* config options */
1899     0,       /* flags */
1900 };
1901 
1902 struct st_mysql_plugin rdb_i_s_dbstats = {
1903     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1904     &rdb_i_s_info,
1905     "ROCKSDB_DBSTATS",
1906     "Facebook",
1907     "RocksDB database stats",
1908     PLUGIN_LICENSE_GPL,
1909     rdb_i_s_dbstats_init,
1910     rdb_i_s_deinit,
1911     0x0001,  /* version number (0.1) */
1912     nullptr, /* status variables */
1913     nullptr, /* system variables */
1914     nullptr, /* config options */
1915     0,       /* flags */
1916 };
1917 
1918 struct st_mysql_plugin rdb_i_s_perf_context = {
1919     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1920     &rdb_i_s_info,
1921     "ROCKSDB_PERF_CONTEXT",
1922     "Facebook",
1923     "RocksDB perf context stats",
1924     PLUGIN_LICENSE_GPL,
1925     rdb_i_s_perf_context_init,
1926     rdb_i_s_deinit,
1927     0x0001,  /* version number (0.1) */
1928     nullptr, /* status variables */
1929     nullptr, /* system variables */
1930     nullptr, /* config options */
1931     0,       /* flags */
1932 };
1933 
1934 struct st_mysql_plugin rdb_i_s_perf_context_global = {
1935     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1936     &rdb_i_s_info,
1937     "ROCKSDB_PERF_CONTEXT_GLOBAL",
1938     "Facebook",
1939     "RocksDB perf context stats (all)",
1940     PLUGIN_LICENSE_GPL,
1941     rdb_i_s_perf_context_global_init,
1942     rdb_i_s_deinit,
1943     0x0001,  /* version number (0.1) */
1944     nullptr, /* status variables */
1945     nullptr, /* system variables */
1946     nullptr, /* config options */
1947     0,       /* flags */
1948 };
1949 
1950 struct st_mysql_plugin rdb_i_s_cfoptions = {
1951     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1952     &rdb_i_s_info,
1953     "ROCKSDB_CF_OPTIONS",
1954     "Facebook",
1955     "RocksDB column family options",
1956     PLUGIN_LICENSE_GPL,
1957     rdb_i_s_cfoptions_init,
1958     rdb_i_s_deinit,
1959     0x0001,  /* version number (0.1) */
1960     nullptr, /* status variables */
1961     nullptr, /* system variables */
1962     nullptr, /* config options */
1963     0,       /* flags */
1964 };
1965 
1966 struct st_mysql_plugin rdb_i_s_global_info = {
1967     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1968     &rdb_i_s_info,
1969     "ROCKSDB_GLOBAL_INFO",
1970     "Facebook",
1971     "RocksDB global info",
1972     PLUGIN_LICENSE_GPL,
1973     rdb_i_s_global_info_init,
1974     rdb_i_s_deinit,
1975     0x0001,  /* version number (0.1) */
1976     nullptr, /* status variables */
1977     nullptr, /* system variables */
1978     nullptr, /* config options */
1979     0,       /* flags */
1980 };
1981 
1982 struct st_mysql_plugin rdb_i_s_compact_stats = {
1983     MYSQL_INFORMATION_SCHEMA_PLUGIN,
1984     &rdb_i_s_info,
1985     "ROCKSDB_COMPACTION_STATS",
1986     "Facebook",
1987     "RocksDB compaction stats",
1988     PLUGIN_LICENSE_GPL,
1989     rdb_i_s_compact_stats_init,
1990     rdb_i_s_deinit,
1991     0x0001,  /* version number (0.1) */
1992     nullptr, /* status variables */
1993     nullptr, /* system variables */
1994     nullptr, /* config options */
1995     0,       /* flags */
1996 };
1997 
1998 struct st_mysql_plugin rdb_i_s_ddl = {
1999     MYSQL_INFORMATION_SCHEMA_PLUGIN,
2000     &rdb_i_s_info,
2001     "ROCKSDB_DDL",
2002     "Facebook",
2003     "RocksDB Data Dictionary",
2004     PLUGIN_LICENSE_GPL,
2005     rdb_i_s_ddl_init,
2006     rdb_i_s_deinit,
2007     0x0001,  /* version number (0.1) */
2008     nullptr, /* status variables */
2009     nullptr, /* system variables */
2010     nullptr, /* config options */
2011     0,       /* flags */
2012 };
2013 
2014 struct st_mysql_plugin rdb_i_s_sst_props = {
2015     MYSQL_INFORMATION_SCHEMA_PLUGIN,
2016     &rdb_i_s_info,
2017     "ROCKSDB_SST_PROPS",
2018     "Facebook",
2019     "RocksDB SST Properties",
2020     PLUGIN_LICENSE_GPL,
2021     rdb_i_s_sst_props_init,
2022     rdb_i_s_deinit,
2023     0x0001,  /* version number (0.1) */
2024     nullptr, /* status variables */
2025     nullptr, /* system variables */
2026     nullptr, /* config options */
2027     0,       /* flags */
2028 };
2029 
2030 struct st_mysql_plugin rdb_i_s_index_file_map = {
2031     MYSQL_INFORMATION_SCHEMA_PLUGIN,
2032     &rdb_i_s_info,
2033     "ROCKSDB_INDEX_FILE_MAP",
2034     "Facebook",
2035     "RocksDB index file map",
2036     PLUGIN_LICENSE_GPL,
2037     rdb_i_s_index_file_map_init,
2038     rdb_i_s_deinit,
2039     0x0001,  /* version number (0.1) */
2040     nullptr, /* status variables */
2041     nullptr, /* system variables */
2042     nullptr, /* config options */
2043     0,       /* flags */
2044 };
2045 
2046 struct st_mysql_plugin rdb_i_s_lock_info = {
2047     MYSQL_INFORMATION_SCHEMA_PLUGIN,
2048     &rdb_i_s_info,
2049     "ROCKSDB_LOCKS",
2050     "Facebook",
2051     "RocksDB lock information",
2052     PLUGIN_LICENSE_GPL,
2053     rdb_i_s_lock_info_init,
2054     nullptr,
2055     0x0001,  /* version number (0.1) */
2056     nullptr, /* status variables */
2057     nullptr, /* system variables */
2058     nullptr, /* config options */
2059     0,       /* flags */
2060 };
2061 
2062 struct st_mysql_plugin rdb_i_s_trx_info = {
2063     MYSQL_INFORMATION_SCHEMA_PLUGIN,
2064     &rdb_i_s_info,
2065     "ROCKSDB_TRX",
2066     "Facebook",
2067     "RocksDB transaction information",
2068     PLUGIN_LICENSE_GPL,
2069     rdb_i_s_trx_info_init,
2070     nullptr,
2071     0x0001,  /* version number (0.1) */
2072     nullptr, /* status variables */
2073     nullptr, /* system variables */
2074     nullptr, /* config options */
2075     0,       /* flags */
2076 };
2077 
2078 struct st_mysql_plugin rdb_i_s_deadlock_info = {
2079     MYSQL_INFORMATION_SCHEMA_PLUGIN,
2080     &rdb_i_s_info,
2081     "ROCKSDB_DEADLOCK",
2082     "Facebook",
2083     "RocksDB transaction information",
2084     PLUGIN_LICENSE_GPL,
2085     rdb_i_s_deadlock_info_init,
2086     nullptr,
2087     0x0001,  /* version number (0.1) */
2088     nullptr, /* status variables */
2089     nullptr, /* system variables */
2090     nullptr, /* config options */
2091     0,       /* flags */
2092 };
2093 }  // namespace myrocks
2094