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