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