mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 12:02:42 +01:00
b5d65fc105
MDEV-33502 Slowdown when running nested statement with many partitions This change was triggered to help some MariaDB users with close to 10000 bits in their bitmaps. - Change underlaying storage to be 64 bit instead of 32bit. - This reduses number of loops to scan bitmaps. - This can cause some bitmaps to be 4 byte large. - Ensure that all not used top-bits are always 0 (simplifes code as the last 64 bit storage is not a special case anymore). - Use my_find_first_bit() to find the first set bit which is much faster than scanning trough things byte by byte and then bit by bit. Other things: - Added a bool to remember if my_bitmap_init() did allocate the bitmap array. my_bitmap_free() will only free arrays it did allocate. This allowed me to remove setting 'bitmap=0' before calling my_bitmap_free() for cases where the bitmap's where allocated externally. - my_bitmap_init() sets bitmap to 0 in case of failure. - Added 'universal' asserts to most bitmap functions. - Change all remaining calls to bitmap_init() to my_bitmap_init(). - To finish the change from 2014. - Changed all usage of uint32 in my_bitmap.h to my_bitmap_map. - Updated bitmap_copy() to handle bitmaps of different size. - Removed const from bitmap_exists_intersection() as this caused casts on all usage. - Removed not used function bitmap_set_above(). - Renamed create_last_word_mask() to create_last_bit_mask() (to match name changes in my_bitmap.cc) - Extended bitmap-t with test for more bitmap functions.
1072 lines
38 KiB
C++
1072 lines
38 KiB
C++
/*
|
|
Copyright (c) 2012,2013 Monty Program Ab
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA */
|
|
#pragma once
|
|
|
|
#ifdef USE_PRAGMA_INTERFACE
|
|
#pragma interface /* gcc class implementation */
|
|
#endif
|
|
|
|
/* C++ standard header files */
|
|
#include <set>
|
|
#include <string>
|
|
#include <unordered_map>
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
/* MySQL header files */
|
|
#include "./handler.h" /* handler */
|
|
#include "./my_global.h" /* ulonglong */
|
|
#include "./sql_string.h"
|
|
|
|
#ifdef _WIN32
|
|
#undef pthread_key_create
|
|
#undef pthread_key_delete
|
|
#undef pthread_setspecific
|
|
#undef pthread_getspecific
|
|
#endif
|
|
|
|
|
|
/* RocksDB header files */
|
|
#include "rocksdb/cache.h"
|
|
#include "rocksdb/merge_operator.h"
|
|
#include "rocksdb/perf_context.h"
|
|
#include "rocksdb/sst_file_manager.h"
|
|
#include "rocksdb/statistics.h"
|
|
#include "rocksdb/utilities/options_util.h"
|
|
#include "rocksdb/utilities/transaction_db.h"
|
|
#include "rocksdb/utilities/write_batch_with_index.h"
|
|
|
|
/* MyRocks header files */
|
|
#include "./rdb_buff.h"
|
|
#include "./rdb_comparator.h"
|
|
#include "./rdb_global.h"
|
|
#include "./rdb_index_merge.h"
|
|
#include "./rdb_io_watchdog.h"
|
|
#include "./rdb_perf_context.h"
|
|
#include "./rdb_sst_info.h"
|
|
#include "./rdb_utils.h"
|
|
#include "./ut0counter.h"
|
|
|
|
#include "rdb_mariadb_server_port.h"
|
|
|
|
class Field_blob;
|
|
class Field_varstring;
|
|
/**
|
|
@note MyRocks Coding Conventions:
|
|
MyRocks code follows the baseline MySQL coding conventions, available at
|
|
http://dev.mysql.com/doc/internals/en/coding-guidelines.html, with several
|
|
refinements (@see /storage/rocksdb/README file).
|
|
*/
|
|
|
|
namespace myrocks {
|
|
|
|
class Rdb_converter;
|
|
class Rdb_key_def;
|
|
class Rdb_tbl_def;
|
|
class Rdb_transaction;
|
|
class Rdb_transaction_impl;
|
|
class Rdb_writebatch_impl;
|
|
class Rdb_field_encoder;
|
|
/* collations, used in MariaRocks */
|
|
enum collations_used {
|
|
COLLATION_UTF8MB4_BIN = 46,
|
|
COLLATION_LATIN1_BIN = 47,
|
|
COLLATION_UTF16LE_BIN = 55,
|
|
COLLATION_UTF32_BIN = 61,
|
|
COLLATION_UTF16_BIN = 62,
|
|
COLLATION_BINARY = 63,
|
|
COLLATION_UTF8_BIN = 83
|
|
};
|
|
|
|
#if 0 // MARIAROCKS_NOT_YET : read-free replication is not supported
|
|
extern char *rocksdb_read_free_rpl_tables;
|
|
#if defined(HAVE_PSI_INTERFACE)
|
|
extern PSI_rwlock_key key_rwlock_read_free_rpl_tables;
|
|
#endif
|
|
extern Regex_list_handler rdb_read_free_regex_handler;
|
|
#endif
|
|
|
|
/**
|
|
@brief
|
|
Rdb_table_handler is a reference-counted structure storing information for
|
|
each open table. All the objects are stored in a global hash map.
|
|
|
|
//TODO: join this with Rdb_tbl_def ?
|
|
*/
|
|
struct Rdb_table_handler {
|
|
char *m_table_name;
|
|
uint m_table_name_length;
|
|
int m_ref_count;
|
|
atomic_stat<int> m_lock_wait_timeout_counter;
|
|
atomic_stat<int> m_deadlock_counter;
|
|
|
|
my_core::THR_LOCK m_thr_lock; ///< MySQL latch needed by m_db_lock
|
|
|
|
/* Stores cumulative table statistics */
|
|
my_io_perf_atomic_t m_io_perf_read;
|
|
my_io_perf_atomic_t m_io_perf_write;
|
|
Rdb_atomic_perf_counters m_table_perf_context;
|
|
|
|
/* Stores cached memtable estimate statistics */
|
|
std::atomic_uint m_mtcache_lock;
|
|
uint64_t m_mtcache_count;
|
|
uint64_t m_mtcache_size;
|
|
uint64_t m_mtcache_last_update;
|
|
};
|
|
|
|
} // namespace myrocks
|
|
|
|
/* Provide hash function for GL_INDEX_ID so we can include it in sets */
|
|
namespace std {
|
|
template <>
|
|
struct hash<myrocks::GL_INDEX_ID> {
|
|
std::size_t operator()(const myrocks::GL_INDEX_ID &gl_index_id) const {
|
|
const uint64_t val =
|
|
((uint64_t)gl_index_id.cf_id << 32 | (uint64_t)gl_index_id.index_id);
|
|
return std::hash<uint64_t>()(val);
|
|
}
|
|
};
|
|
} // namespace std
|
|
|
|
namespace myrocks {
|
|
|
|
/**
|
|
@brief
|
|
Class definition for ROCKSDB storage engine plugin handler
|
|
*/
|
|
|
|
class ha_rocksdb : public my_core::handler {
|
|
my_core::THR_LOCK_DATA m_db_lock; ///< MySQL database lock
|
|
|
|
Rdb_table_handler *m_table_handler; ///< Open table handler
|
|
|
|
/* Iterator used for range scans and for full table/index scans */
|
|
rocksdb::Iterator *m_scan_it;
|
|
|
|
/* Same as handler::end_key but for start. Reverse-ordered scans need it */
|
|
key_range m_save_start_range;
|
|
const key_range *m_start_range;
|
|
|
|
/* Whether m_scan_it was created with skip_bloom=true */
|
|
bool m_scan_it_skips_bloom;
|
|
|
|
const rocksdb::Snapshot *m_scan_it_snapshot;
|
|
|
|
/* Buffers used for upper/lower bounds for m_scan_it. */
|
|
uchar *m_scan_it_lower_bound;
|
|
uchar *m_scan_it_upper_bound;
|
|
rocksdb::Slice m_scan_it_lower_bound_slice;
|
|
rocksdb::Slice m_scan_it_upper_bound_slice;
|
|
|
|
Rdb_tbl_def *m_tbl_def;
|
|
|
|
/* Primary Key encoder from KeyTupleFormat to StorageFormat */
|
|
std::shared_ptr<Rdb_key_def> m_pk_descr;
|
|
|
|
/* Array of index descriptors */
|
|
std::shared_ptr<Rdb_key_def> *m_key_descr_arr;
|
|
|
|
bool check_keyread_allowed(uint inx, uint part, bool all_parts) const;
|
|
|
|
/*
|
|
Number of key parts in PK. This is the same as
|
|
table->key_info[table->s->primary_key].keyparts
|
|
*/
|
|
uint m_pk_key_parts;
|
|
|
|
/*
|
|
TRUE <=> Primary Key columns can be decoded from the index
|
|
*/
|
|
mutable bool m_pk_can_be_decoded;
|
|
|
|
uchar *m_pk_tuple; /* Buffer for storing PK in KeyTupleFormat */
|
|
uchar *m_pk_packed_tuple; /* Buffer for storing PK in StorageFormat */
|
|
// ^^ todo: change it to 'char*'? TODO: ^ can we join this with last_rowkey?
|
|
|
|
/*
|
|
Temporary buffers for storing the key part of the Key/Value pair
|
|
for secondary indexes.
|
|
*/
|
|
uchar *m_sk_packed_tuple;
|
|
|
|
/*
|
|
Temporary buffers for storing end key part of the Key/Value pair.
|
|
This is used for range scan only.
|
|
*/
|
|
uchar *m_end_key_packed_tuple;
|
|
|
|
Rdb_string_writer m_sk_tails;
|
|
Rdb_string_writer m_pk_unpack_info;
|
|
|
|
/*
|
|
ha_rockdb->index_read_map(.. HA_READ_KEY_EXACT or similar) will save here
|
|
mem-comparable form of the index lookup tuple.
|
|
*/
|
|
uchar *m_sk_match_prefix;
|
|
uint m_sk_match_length;
|
|
|
|
/* Buffer space for the above */
|
|
uchar *m_sk_match_prefix_buf;
|
|
|
|
/* Second buffers, used by UPDATE. */
|
|
uchar *m_sk_packed_tuple_old;
|
|
Rdb_string_writer m_sk_tails_old;
|
|
|
|
/* Buffers used for duplicate checking during unique_index_creation */
|
|
uchar *m_dup_sk_packed_tuple;
|
|
uchar *m_dup_sk_packed_tuple_old;
|
|
|
|
/*
|
|
Temporary space for packing VARCHARs (we provide it to
|
|
pack_record()/pack_index_tuple() calls).
|
|
*/
|
|
uchar *m_pack_buffer;
|
|
|
|
/*
|
|
A buffer long enough to store table record
|
|
*/
|
|
uchar *m_record_buffer;
|
|
|
|
/* class to convert between Mysql format and RocksDB format*/
|
|
std::shared_ptr<Rdb_converter> m_converter;
|
|
|
|
/*
|
|
Pointer to the original TTL timestamp value (8 bytes) during UPDATE.
|
|
*/
|
|
char *m_ttl_bytes;
|
|
/*
|
|
The TTL timestamp value can change if the explicit TTL column is
|
|
updated. If we detect this when updating the PK, we indicate it here so
|
|
we know we must always update any SK's.
|
|
*/
|
|
bool m_ttl_bytes_updated;
|
|
|
|
/* rowkey of the last record we've read, in StorageFormat. */
|
|
String m_last_rowkey;
|
|
|
|
/*
|
|
Last retrieved record, in table->record[0] data format.
|
|
|
|
This is used only when we get the record with rocksdb's Get() call (The
|
|
other option is when we get a rocksdb::Slice from an iterator)
|
|
*/
|
|
rocksdb::PinnableSlice m_retrieved_record;
|
|
|
|
/* Type of locking to apply to rows */
|
|
enum { RDB_LOCK_NONE, RDB_LOCK_READ, RDB_LOCK_WRITE } m_lock_rows;
|
|
|
|
/* TRUE means we're doing an index-only read. FALSE means otherwise. */
|
|
bool m_keyread_only;
|
|
|
|
bool m_skip_scan_it_next_call;
|
|
|
|
/* TRUE means we are accessing the first row after a snapshot was created */
|
|
bool m_rnd_scan_is_new_snapshot;
|
|
|
|
/*
|
|
TRUE means we should skip unique key checks for this table if the
|
|
replication lag gets too large
|
|
*/
|
|
bool m_skip_unique_check;
|
|
|
|
/*
|
|
TRUE means INSERT ON DUPLICATE KEY UPDATE. In such case we can optimize by
|
|
remember the failed attempt (if there is one that violates uniqueness check)
|
|
in write_row and in the following index_read to skip the lock check and read
|
|
entirely
|
|
*/
|
|
bool m_insert_with_update;
|
|
|
|
/* TRUE if last time the insertion failed due to duplicated PK */
|
|
bool m_dup_pk_found;
|
|
|
|
#ifndef DBUG_OFF
|
|
/* Last retreived record for sanity checking */
|
|
String m_dup_pk_retrieved_record;
|
|
#endif
|
|
|
|
/**
|
|
@brief
|
|
This is a bitmap of indexes (i.e. a set) whose keys (in future, values) may
|
|
be changed by this statement. Indexes that are not in the bitmap do not need
|
|
to be updated.
|
|
@note Valid inside UPDATE statements, IIF(m_update_scope_is_valid == true).
|
|
*/
|
|
my_core::key_map m_update_scope;
|
|
bool m_update_scope_is_valid;
|
|
|
|
/* SST information used for bulk loading the primary key */
|
|
std::shared_ptr<Rdb_sst_info> m_sst_info;
|
|
|
|
/*
|
|
MySQL index number for duplicate key error
|
|
*/
|
|
uint m_dupp_errkey;
|
|
|
|
int create_key_defs(const TABLE *const table_arg,
|
|
Rdb_tbl_def *const tbl_def_arg,
|
|
const TABLE *const old_table_arg = nullptr,
|
|
const Rdb_tbl_def *const old_tbl_def_arg = nullptr) const
|
|
MY_ATTRIBUTE((__nonnull__(2, 3), __warn_unused_result__));
|
|
int secondary_index_read(const int keyno, uchar *const buf)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
void setup_iterator_for_rnd_scan();
|
|
bool is_ascending(const Rdb_key_def &keydef,
|
|
enum ha_rkey_function find_flag) const
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
void setup_iterator_bounds(const Rdb_key_def &kd,
|
|
const rocksdb::Slice &eq_cond, size_t bound_len,
|
|
uchar *const lower_bound, uchar *const upper_bound,
|
|
rocksdb::Slice *lower_bound_slice,
|
|
rocksdb::Slice *upper_bound_slice);
|
|
bool can_use_bloom_filter(THD *thd, const Rdb_key_def &kd,
|
|
const rocksdb::Slice &eq_cond,
|
|
const bool use_all_keys);
|
|
bool check_bloom_and_set_bounds(THD *thd, const Rdb_key_def &kd,
|
|
const rocksdb::Slice &eq_cond,
|
|
const bool use_all_keys, size_t bound_len,
|
|
uchar *const lower_bound,
|
|
uchar *const upper_bound,
|
|
rocksdb::Slice *lower_bound_slice,
|
|
rocksdb::Slice *upper_bound_slice);
|
|
void setup_scan_iterator(const Rdb_key_def &kd, rocksdb::Slice *slice,
|
|
const bool use_all_keys, const uint eq_cond_len)
|
|
MY_ATTRIBUTE((__nonnull__));
|
|
void release_scan_iterator(void);
|
|
|
|
rocksdb::Status get_for_update(
|
|
Rdb_transaction *const tx,
|
|
rocksdb::ColumnFamilyHandle *const column_family,
|
|
const rocksdb::Slice &key, rocksdb::PinnableSlice *value) const;
|
|
|
|
int get_row_by_rowid(uchar *const buf, const char *const rowid,
|
|
const uint rowid_size, const bool skip_lookup = false,
|
|
const bool skip_ttl_check = true)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
int get_row_by_rowid(uchar *const buf, const uchar *const rowid,
|
|
const uint rowid_size, const bool skip_lookup = false,
|
|
const bool skip_ttl_check = true)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__)) {
|
|
return get_row_by_rowid(buf, reinterpret_cast<const char *>(rowid),
|
|
rowid_size, skip_lookup, skip_ttl_check);
|
|
}
|
|
|
|
void load_auto_incr_value();
|
|
ulonglong load_auto_incr_value_from_index();
|
|
void update_auto_incr_val(ulonglong val);
|
|
void update_auto_incr_val_from_field();
|
|
rocksdb::Status get_datadic_auto_incr(Rdb_transaction *const tx,
|
|
const GL_INDEX_ID &gl_index_id,
|
|
ulonglong *new_val) const;
|
|
longlong update_hidden_pk_val();
|
|
int load_hidden_pk_value() MY_ATTRIBUTE((__warn_unused_result__));
|
|
int read_hidden_pk_id_from_rowkey(longlong *const hidden_pk_id)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
bool can_use_single_delete(const uint index) const
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
bool is_blind_delete_enabled();
|
|
bool skip_unique_check() const MY_ATTRIBUTE((__warn_unused_result__));
|
|
#ifdef MARIAROCKS_NOT_YET // MDEV-10975
|
|
void set_force_skip_unique_check(bool skip) override;
|
|
#endif
|
|
bool commit_in_the_middle() MY_ATTRIBUTE((__warn_unused_result__));
|
|
bool do_bulk_commit(Rdb_transaction *const tx)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
bool has_hidden_pk(const TABLE *const table) const
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
void update_row_stats(const operation_type &type);
|
|
|
|
void set_last_rowkey(const uchar *const old_data);
|
|
|
|
/*
|
|
For the active index, indicates which columns must be covered for the
|
|
current lookup to be covered. If the bitmap field is null, that means this
|
|
index does not cover the current lookup for any record.
|
|
*/
|
|
MY_BITMAP m_lookup_bitmap = {nullptr, nullptr, nullptr, 0, 0, 0};
|
|
|
|
int alloc_key_buffers(const TABLE *const table_arg,
|
|
const Rdb_tbl_def *const tbl_def_arg,
|
|
bool alloc_alter_buffers = false)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
void free_key_buffers();
|
|
|
|
// the buffer size should be at least 2*Rdb_key_def::INDEX_NUMBER_SIZE
|
|
rocksdb::Range get_range(const int i, uchar buf[2 * 4]) const;
|
|
|
|
/*
|
|
Perf timers for data reads
|
|
*/
|
|
Rdb_io_perf m_io_perf;
|
|
|
|
/*
|
|
Update stats
|
|
*/
|
|
void update_stats(void);
|
|
|
|
public:
|
|
/*
|
|
The following two are currently only used for getting the range bounds
|
|
from QUICK_SELECT_DESC.
|
|
We don't need to implement prepare_index_key_scan[_map] because it is
|
|
only used with HA_READ_KEY_EXACT and HA_READ_PREFIX_LAST where one
|
|
can infer the bounds of the range being scanned, anyway.
|
|
*/
|
|
int prepare_index_scan() override;
|
|
int prepare_range_scan(const key_range *start_key,
|
|
const key_range *end_key) override;
|
|
|
|
/*
|
|
Controls whether writes include checksums. This is updated from the session
|
|
variable
|
|
at the start of each query.
|
|
*/
|
|
bool m_store_row_debug_checksums;
|
|
|
|
int m_checksums_pct;
|
|
|
|
ha_rocksdb(my_core::handlerton *const hton,
|
|
my_core::TABLE_SHARE *const table_arg);
|
|
virtual ~ha_rocksdb() override {
|
|
int err MY_ATTRIBUTE((__unused__));
|
|
err = finalize_bulk_load(false);
|
|
if (err != 0) {
|
|
// NO_LINT_DEBUG
|
|
sql_print_error(
|
|
"RocksDB: Error %d finalizing bulk load while closing "
|
|
"handler.",
|
|
err);
|
|
}
|
|
}
|
|
|
|
/*
|
|
MariaDB: this function:
|
|
|
|
const char *table_type() const
|
|
|
|
is non-virtual in class handler, so there's no point to override it.
|
|
*/
|
|
|
|
/* The following is only used by SHOW KEYS: */
|
|
const char *index_type(uint inx) override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
DBUG_RETURN("LSMTREE");
|
|
}
|
|
|
|
/*
|
|
Not present in MariaDB:
|
|
const char **bas_ext() const override;
|
|
*/
|
|
|
|
/*
|
|
Returns the name of the table's base name
|
|
*/
|
|
const std::string &get_table_basename() const;
|
|
|
|
/** @brief
|
|
This is a list of flags that indicate what functionality the storage engine
|
|
implements. The current table flags are documented in handler.h
|
|
*/
|
|
ulonglong table_flags() const override ;
|
|
private:
|
|
bool init_with_fields(); /* no 'override' in MariaDB */
|
|
public:
|
|
/** @brief
|
|
This is a bitmap of flags that indicates how the storage engine
|
|
implements indexes. The current index flags are documented in
|
|
handler.h. If you do not implement indexes, just return zero here.
|
|
|
|
@details
|
|
part is the key part to check. First key part is 0.
|
|
If all_parts is set, MySQL wants to know the flags for the combined
|
|
index, up to and including 'part'.
|
|
*/
|
|
ulong index_flags(uint inx, uint part, bool all_parts) const override;
|
|
|
|
const key_map *keys_to_use_for_scanning() override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
DBUG_RETURN(&key_map_full);
|
|
}
|
|
|
|
bool should_store_row_debug_checksums() const {
|
|
return m_store_row_debug_checksums && (rand() % 100 < m_checksums_pct);
|
|
}
|
|
|
|
int rename_table(const char *const from, const char *const to) override
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int convert_record_from_storage_format(const rocksdb::Slice *const key,
|
|
const rocksdb::Slice *const value,
|
|
uchar *const buf)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int convert_record_from_storage_format(const rocksdb::Slice *const key,
|
|
uchar *const buf)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
static const std::vector<std::string> parse_into_tokens(const std::string &s,
|
|
const char delim);
|
|
|
|
static const std::string generate_cf_name(
|
|
const uint index, const TABLE *const table_arg,
|
|
const Rdb_tbl_def *const tbl_def_arg, bool *per_part_match_found);
|
|
|
|
static const char *get_key_name(const uint index,
|
|
const TABLE *const table_arg,
|
|
const Rdb_tbl_def *const tbl_def_arg)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
static const char *get_key_comment(const uint index,
|
|
const TABLE *const table_arg,
|
|
const Rdb_tbl_def *const tbl_def_arg)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
static const std::string get_table_comment(const TABLE *const table_arg)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
static bool is_hidden_pk(const uint index, const TABLE *const table_arg,
|
|
const Rdb_tbl_def *const tbl_def_arg)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
static uint pk_index(const TABLE *const table_arg,
|
|
const Rdb_tbl_def *const tbl_def_arg)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
static bool is_pk(const uint index, const TABLE *table_arg,
|
|
const Rdb_tbl_def *tbl_def_arg)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
/** @brief
|
|
unireg.cc will call max_supported_record_length(), max_supported_keys(),
|
|
max_supported_key_parts(), uint max_supported_key_length()
|
|
to make sure that the storage engine can handle the data it is about to
|
|
send. Return *real* limits of your storage engine here; MySQL will do
|
|
min(your_limits, MySQL_limits) automatically.
|
|
*/
|
|
uint max_supported_record_length() const override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
DBUG_RETURN(HA_MAX_REC_LENGTH);
|
|
}
|
|
|
|
uint max_supported_keys() const override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
DBUG_RETURN(MAX_INDEXES);
|
|
}
|
|
|
|
uint max_supported_key_parts() const override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
DBUG_RETURN(MAX_REF_PARTS);
|
|
}
|
|
|
|
uint max_supported_key_part_length() const override;
|
|
|
|
/** @brief
|
|
unireg.cc will call this to make sure that the storage engine can handle
|
|
the data it is about to send. Return *real* limits of your storage engine
|
|
here; MySQL will do min(your_limits, MySQL_limits) automatically.
|
|
|
|
@details
|
|
There is no need to implement ..._key_... methods if your engine doesn't
|
|
support indexes.
|
|
*/
|
|
uint max_supported_key_length() const override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
DBUG_RETURN(16 * 1024); /* just to return something*/
|
|
}
|
|
|
|
/**
|
|
TODO: return actual upper bound of number of records in the table.
|
|
(e.g. save number of records seen on full table scan and/or use file size
|
|
as upper bound)
|
|
*/
|
|
ha_rows estimate_rows_upper_bound() override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
DBUG_RETURN(HA_POS_ERROR);
|
|
}
|
|
|
|
/* At the moment, we're ok with default handler::index_init() implementation.
|
|
*/
|
|
int index_read_map(uchar *const buf, const uchar *const key,
|
|
key_part_map keypart_map,
|
|
enum ha_rkey_function find_flag) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int index_read_map_impl(uchar *const buf, const uchar *const key,
|
|
key_part_map keypart_map,
|
|
enum ha_rkey_function find_flag,
|
|
const key_range *end_key)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
bool is_using_full_key(key_part_map keypart_map, uint actual_key_parts);
|
|
int read_range_first(const key_range *const start_key,
|
|
const key_range *const end_key, bool eq_range,
|
|
bool sorted) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
virtual double scan_time() override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
DBUG_RETURN(
|
|
static_cast<double>((stats.records + stats.deleted) / 20.0 + 10));
|
|
}
|
|
|
|
virtual double read_time(uint, uint, ha_rows rows) override;
|
|
virtual void print_error(int error, myf errflag) override;
|
|
|
|
int open(const char *const name, int mode, uint test_if_locked) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int close(void) override MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int write_row(const uchar *const buf) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int update_row(const uchar *const old_data, const uchar *const new_data) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int delete_row(const uchar *const buf) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
rocksdb::Status delete_or_singledelete(uint index, Rdb_transaction *const tx,
|
|
rocksdb::ColumnFamilyHandle *const cf,
|
|
const rocksdb::Slice &key)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int index_next(uchar *const buf) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int index_next_with_direction(uchar *const buf, bool move_forward)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int index_prev(uchar *const buf) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int index_first(uchar *const buf) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int index_last(uchar *const buf) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
class Item *idx_cond_push(uint keyno, class Item *const idx_cond) override;
|
|
/*
|
|
Default implementation from cancel_pushed_idx_cond() suits us
|
|
*/
|
|
private:
|
|
struct key_def_cf_info {
|
|
rocksdb::ColumnFamilyHandle *cf_handle;
|
|
bool is_reverse_cf;
|
|
bool is_per_partition_cf;
|
|
};
|
|
|
|
struct update_row_info {
|
|
Rdb_transaction *tx;
|
|
const uchar *new_data;
|
|
const uchar *old_data;
|
|
rocksdb::Slice new_pk_slice;
|
|
rocksdb::Slice old_pk_slice;
|
|
rocksdb::Slice old_pk_rec;
|
|
|
|
// "unpack_info" data for the new PK value
|
|
Rdb_string_writer *new_pk_unpack_info;
|
|
|
|
longlong hidden_pk_id;
|
|
bool skip_unique_check;
|
|
};
|
|
|
|
/*
|
|
Used to check for duplicate entries during fast unique secondary index
|
|
creation.
|
|
*/
|
|
struct unique_sk_buf_info {
|
|
bool sk_buf_switch = false;
|
|
rocksdb::Slice sk_memcmp_key;
|
|
rocksdb::Slice sk_memcmp_key_old;
|
|
uchar *dup_sk_buf;
|
|
uchar *dup_sk_buf_old;
|
|
|
|
/*
|
|
This method is meant to be called back to back during inplace creation
|
|
of unique indexes. It will switch between two buffers, which
|
|
will each store the memcmp form of secondary keys, which are then
|
|
converted to slices in sk_memcmp_key or sk_memcmp_key_old.
|
|
|
|
Switching buffers on each iteration allows us to retain the
|
|
sk_memcmp_key_old value for duplicate comparison.
|
|
*/
|
|
inline uchar *swap_and_get_sk_buf() {
|
|
sk_buf_switch = !sk_buf_switch;
|
|
return sk_buf_switch ? dup_sk_buf : dup_sk_buf_old;
|
|
}
|
|
};
|
|
|
|
int create_cfs(const TABLE *const table_arg, Rdb_tbl_def *const tbl_def_arg,
|
|
std::array<struct key_def_cf_info, MAX_INDEXES + 1> *const cfs)
|
|
const MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int create_key_def(const TABLE *const table_arg, const uint i,
|
|
const Rdb_tbl_def *const tbl_def_arg,
|
|
std::shared_ptr<Rdb_key_def> *const new_key_def,
|
|
const struct key_def_cf_info &cf_info, uint64 ttl_duration,
|
|
const std::string &ttl_column) const
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int create_inplace_key_defs(
|
|
const TABLE *const table_arg, Rdb_tbl_def *vtbl_def_arg,
|
|
const TABLE *const old_table_arg,
|
|
const Rdb_tbl_def *const old_tbl_def_arg,
|
|
const std::array<key_def_cf_info, MAX_INDEXES + 1> &cf,
|
|
uint64 ttl_duration, const std::string &ttl_column) const
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
std::unordered_map<std::string, uint> get_old_key_positions(
|
|
const TABLE *table_arg, const Rdb_tbl_def *tbl_def_arg,
|
|
const TABLE *old_table_arg, const Rdb_tbl_def *old_tbl_def_arg) const
|
|
MY_ATTRIBUTE((__nonnull__));
|
|
|
|
using handler::compare_key_parts;
|
|
int compare_key_parts(const KEY *const old_key,
|
|
const KEY *const new_key) const
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int compare_keys(const KEY *const old_key, const KEY *const new_key) const
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
bool should_hide_ttl_rec(const Rdb_key_def &kd,
|
|
const rocksdb::Slice &ttl_rec_val,
|
|
const int64_t curr_ts)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int rocksdb_skip_expired_records(const Rdb_key_def &kd,
|
|
rocksdb::Iterator *const iter,
|
|
bool seek_backward);
|
|
|
|
int index_first_intern(uchar *buf)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
int index_last_intern(uchar *buf)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int find_icp_matching_index_rec(const bool move_forward, uchar *const buf)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
void calc_updated_indexes();
|
|
int update_write_row(const uchar *const old_data, const uchar *const new_data,
|
|
const bool skip_unique_check)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int get_pk_for_update(struct update_row_info *const row_info);
|
|
int check_and_lock_unique_pk(const uint key_id,
|
|
const struct update_row_info &row_info,
|
|
bool *const found)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int check_and_lock_sk(const uint key_id,
|
|
const struct update_row_info &row_info,
|
|
bool *const found)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int check_uniqueness_and_lock(const struct update_row_info &row_info,
|
|
bool pk_changed)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
bool over_bulk_load_threshold(int *err)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int check_duplicate_sk(const TABLE *table_arg, const Rdb_key_def &key_def,
|
|
const rocksdb::Slice *key,
|
|
struct unique_sk_buf_info *sk_info)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
int bulk_load_key(Rdb_transaction *const tx, const Rdb_key_def &kd,
|
|
const rocksdb::Slice &key, const rocksdb::Slice &value,
|
|
bool sort)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
void update_bytes_written(ulonglong bytes_written);
|
|
int update_write_pk(const Rdb_key_def &kd,
|
|
const struct update_row_info &row_info,
|
|
const bool pk_changed)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int update_write_sk(const TABLE *const table_arg, const Rdb_key_def &kd,
|
|
const struct update_row_info &row_info,
|
|
const bool bulk_load_sk)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int update_write_indexes(const struct update_row_info &row_info,
|
|
const bool pk_changed)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int read_key_exact(const Rdb_key_def &kd, rocksdb::Iterator *const iter,
|
|
const bool using_full_key, const rocksdb::Slice &key_slice,
|
|
const int64_t ttl_filter_ts)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
int read_before_key(const Rdb_key_def &kd, const bool using_full_key,
|
|
const rocksdb::Slice &key_slice,
|
|
const int64_t ttl_filter_ts)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
int read_after_key(const Rdb_key_def &kd, const rocksdb::Slice &key_slice,
|
|
const int64_t ttl_filter_ts)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
int position_to_correct_key(const Rdb_key_def &kd,
|
|
const enum ha_rkey_function &find_flag,
|
|
const bool full_key_match, const uchar *const key,
|
|
const key_part_map &keypart_map,
|
|
const rocksdb::Slice &key_slice,
|
|
bool *const move_forward,
|
|
const int64_t ttl_filter_ts)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int read_row_from_primary_key(uchar *const buf)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
int read_row_from_secondary_key(uchar *const buf, const Rdb_key_def &kd,
|
|
bool move_forward)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int calc_eq_cond_len(const Rdb_key_def &kd,
|
|
const enum ha_rkey_function &find_flag,
|
|
const rocksdb::Slice &slice,
|
|
const int bytes_changed_by_succ,
|
|
const key_range *const end_key,
|
|
uint *const end_key_packed_size)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
Rdb_tbl_def *get_table_if_exists(const char *const tablename)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
void read_thd_vars(THD *const thd) MY_ATTRIBUTE((__nonnull__));
|
|
|
|
bool contains_foreign_key(THD *const thd)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int inplace_populate_sk(
|
|
TABLE *const table_arg,
|
|
const std::unordered_set<std::shared_ptr<Rdb_key_def>> &indexes)
|
|
MY_ATTRIBUTE((__nonnull__, __warn_unused_result__));
|
|
|
|
int finalize_bulk_load(bool print_client_error = true)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int calculate_stats_for_table() MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
bool should_skip_invalidated_record(const int rc);
|
|
bool should_recreate_snapshot(const int rc, const bool is_new_snapshot);
|
|
bool can_assume_tracked(THD *thd);
|
|
|
|
public:
|
|
int index_init(uint idx, bool sorted) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int index_end() override MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
void unlock_row() override;
|
|
|
|
/** @brief
|
|
Unlike index_init(), rnd_init() can be called two consecutive times
|
|
without rnd_end() in between (it only makes sense if scan=1). In this
|
|
case, the second call should prepare for the new table scan (e.g if
|
|
rnd_init() allocates the cursor, the second call should position the
|
|
cursor to the start of the table; no need to deallocate and allocate
|
|
it again. This is a required method.
|
|
*/
|
|
int rnd_init(bool scan) override MY_ATTRIBUTE((__warn_unused_result__));
|
|
int rnd_end() override MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int rnd_next(uchar *const buf) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int rnd_next_with_direction(uchar *const buf, bool move_forward)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int rnd_pos(uchar *const buf, uchar *const pos) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
void position(const uchar *const record) override;
|
|
int info(uint) override;
|
|
|
|
/* This function will always return success, therefore no annotation related
|
|
* to checking the return value. Can't change the signature because it's
|
|
* required by the interface. */
|
|
int extra(enum ha_extra_function operation) override;
|
|
|
|
int start_stmt(THD *const thd, thr_lock_type lock_type) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int external_lock(THD *const thd, int lock_type) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int truncate() override MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int reset() override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
/* Free blob data */
|
|
m_retrieved_record.Reset();
|
|
|
|
DBUG_RETURN(HA_EXIT_SUCCESS);
|
|
}
|
|
|
|
int check(THD *const thd, HA_CHECK_OPT *const check_opt) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int remove_rows(Rdb_tbl_def *const tbl);
|
|
ha_rows records_in_range(uint inx,
|
|
const key_range *const min_key,
|
|
const key_range *const max_key,
|
|
page_range *pages) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
int delete_table(Rdb_tbl_def *const tbl);
|
|
int delete_table(const char *const from) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int create(const char *const name, TABLE *const form,
|
|
HA_CREATE_INFO *const create_info) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int create_table(const std::string &table_name, const TABLE *table_arg,
|
|
ulonglong auto_increment_value);
|
|
bool check_if_incompatible_data(HA_CREATE_INFO *const info,
|
|
uint table_changes) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
THR_LOCK_DATA **store_lock(THD *const thd, THR_LOCK_DATA **to,
|
|
enum thr_lock_type lock_type) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
my_bool register_query_cache_table(THD *const thd, const char *table_key,
|
|
uint key_length,
|
|
qc_engine_callback *const engine_callback,
|
|
ulonglong *const engine_data) override {
|
|
DBUG_ENTER_FUNC();
|
|
|
|
/* Currently, we don't support query cache */
|
|
DBUG_RETURN(FALSE);
|
|
}
|
|
|
|
bool get_error_message(const int error, String *const buf) override
|
|
MY_ATTRIBUTE((__nonnull__));
|
|
|
|
static int rdb_error_to_mysql(const rocksdb::Status &s,
|
|
const char *msg = nullptr)
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
void get_auto_increment(ulonglong offset, ulonglong increment,
|
|
ulonglong nb_desired_values,
|
|
ulonglong *const first_value,
|
|
ulonglong *const nb_reserved_values) override;
|
|
void update_create_info(HA_CREATE_INFO *const create_info) override;
|
|
int optimize(THD *const thd, HA_CHECK_OPT *const check_opt) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
int analyze(THD *const thd, HA_CHECK_OPT *const check_opt) override
|
|
MY_ATTRIBUTE((__warn_unused_result__));
|
|
|
|
enum_alter_inplace_result check_if_supported_inplace_alter(
|
|
TABLE *altered_table,
|
|
my_core::Alter_inplace_info *const ha_alter_info) override;
|
|
|
|
bool prepare_inplace_alter_table(
|
|
TABLE *const altered_table,
|
|
my_core::Alter_inplace_info *const ha_alter_info) override;
|
|
|
|
bool inplace_alter_table(
|
|
TABLE *const altered_table,
|
|
my_core::Alter_inplace_info *const ha_alter_info) override;
|
|
|
|
bool commit_inplace_alter_table(
|
|
TABLE *const altered_table,
|
|
my_core::Alter_inplace_info *const ha_alter_info, bool commit) override;
|
|
|
|
void set_skip_unique_check_tables(const char *const whitelist);
|
|
|
|
virtual ulonglong table_version() const override;
|
|
|
|
#ifdef MARIAROCKS_NOT_YET // MDEV-10976
|
|
bool is_read_free_rpl_table() const;
|
|
#endif
|
|
|
|
#ifdef MARIAROCKS_NOT_YET // MDEV-10976
|
|
public:
|
|
virtual void rpl_before_delete_rows() override;
|
|
virtual void rpl_after_delete_rows() override;
|
|
virtual void rpl_before_update_rows() override;
|
|
virtual void rpl_after_update_rows() override;
|
|
virtual bool use_read_free_rpl() const override;
|
|
#endif // MARIAROCKS_NOT_YET
|
|
|
|
private:
|
|
/* Flags tracking if we are inside different replication operation */
|
|
bool m_in_rpl_delete_rows;
|
|
bool m_in_rpl_update_rows;
|
|
|
|
bool m_force_skip_unique_check;
|
|
};
|
|
|
|
/*
|
|
Helper class for in-place alter, for storing handler context between inplace
|
|
alter calls
|
|
*/
|
|
struct Rdb_inplace_alter_ctx : public my_core::inplace_alter_handler_ctx {
|
|
/* The new table definition */
|
|
Rdb_tbl_def *const m_new_tdef;
|
|
|
|
/* Stores the original key definitions */
|
|
std::shared_ptr<Rdb_key_def> *const m_old_key_descr;
|
|
|
|
/* Stores the new key definitions */
|
|
std::shared_ptr<Rdb_key_def> *m_new_key_descr;
|
|
|
|
/* Stores the old number of key definitions */
|
|
const uint m_old_n_keys;
|
|
|
|
/* Stores the new number of key definitions */
|
|
const uint m_new_n_keys;
|
|
|
|
/* Stores the added key glids */
|
|
const std::unordered_set<std::shared_ptr<Rdb_key_def>> m_added_indexes;
|
|
|
|
/* Stores the dropped key glids */
|
|
const std::unordered_set<GL_INDEX_ID> m_dropped_index_ids;
|
|
|
|
/* Stores number of keys to add */
|
|
const uint m_n_added_keys;
|
|
|
|
/* Stores number of keys to drop */
|
|
const uint m_n_dropped_keys;
|
|
|
|
/* Stores the largest current auto increment value in the index */
|
|
const ulonglong m_max_auto_incr;
|
|
|
|
Rdb_inplace_alter_ctx(
|
|
Rdb_tbl_def *new_tdef, std::shared_ptr<Rdb_key_def> *old_key_descr,
|
|
std::shared_ptr<Rdb_key_def> *new_key_descr, uint old_n_keys,
|
|
uint new_n_keys,
|
|
std::unordered_set<std::shared_ptr<Rdb_key_def>> added_indexes,
|
|
std::unordered_set<GL_INDEX_ID> dropped_index_ids, uint n_added_keys,
|
|
uint n_dropped_keys, ulonglong max_auto_incr)
|
|
: my_core::inplace_alter_handler_ctx(),
|
|
m_new_tdef(new_tdef),
|
|
m_old_key_descr(old_key_descr),
|
|
m_new_key_descr(new_key_descr),
|
|
m_old_n_keys(old_n_keys),
|
|
m_new_n_keys(new_n_keys),
|
|
m_added_indexes(added_indexes),
|
|
m_dropped_index_ids(dropped_index_ids),
|
|
m_n_added_keys(n_added_keys),
|
|
m_n_dropped_keys(n_dropped_keys),
|
|
m_max_auto_incr(max_auto_incr) {}
|
|
|
|
~Rdb_inplace_alter_ctx() = default;
|
|
|
|
private:
|
|
/* Disable Copying */
|
|
Rdb_inplace_alter_ctx(const Rdb_inplace_alter_ctx &);
|
|
Rdb_inplace_alter_ctx &operator=(const Rdb_inplace_alter_ctx &);
|
|
};
|
|
|
|
// file name indicating RocksDB data corruption
|
|
std::string rdb_corruption_marker_file_name();
|
|
|
|
const int MYROCKS_MARIADB_PLUGIN_MATURITY_LEVEL= MariaDB_PLUGIN_MATURITY_STABLE;
|
|
|
|
extern bool prevent_myrocks_loading;
|
|
|
|
extern uint32_t rocksdb_ignore_datadic_errors;
|
|
|
|
void sql_print_verbose_info(const char *format, ...);
|
|
|
|
} // namespace myrocks
|
|
|