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