summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorRich Prohaska <prohaska@tokutek.com>2013-09-15 09:58:19 -0400
committerRich Prohaska <prohaska@tokutek.com>2013-09-15 09:58:19 -0400
commit53c7335563756e8c24b01ae478459e633b4df8cb (patch)
treea2c060beba20fc0b617bc946c105c6eb98d346bc /storage
parent60a4370f9a3d20e49054bb1fb2ee9205d368e44c (diff)
downloadmariadb-git-53c7335563756e8c24b01ae478459e633b4df8cb.tar.gz
refs #71 basic lock tree visualization
Diffstat (limited to 'storage')
-rw-r--r--storage/tokudb/hatoku_defines.h9
-rw-r--r--storage/tokudb/hatoku_hton.cc433
2 files changed, 396 insertions, 46 deletions
diff --git a/storage/tokudb/hatoku_defines.h b/storage/tokudb/hatoku_defines.h
index f1c49b4cbe4..84073af639b 100644
--- a/storage/tokudb/hatoku_defines.h
+++ b/storage/tokudb/hatoku_defines.h
@@ -330,9 +330,14 @@ static inline void make_name(char *newname, const char *tablename, const char *d
}
static inline int txn_begin(DB_ENV *env, DB_TXN *parent, DB_TXN **txn, uint32_t flags, THD *thd) {
+ *txn = NULL;
int r = env->txn_begin(env, parent, txn, flags);
- if ((tokudb_debug & TOKUDB_DEBUG_TXN) && r == 0) {
- TOKUDB_TRACE("begin txn %p %p %u\n", parent, *txn, flags);
+ if (r == 0 && thd) {
+ DB_TXN *this_txn = *txn;
+ this_txn->set_client_id(this_txn, thd_get_thread_id(thd));
+ }
+ if ((tokudb_debug & TOKUDB_DEBUG_TXN)) {
+ TOKUDB_TRACE("begin txn %p %p %u r=%d\n", parent, *txn, flags, r);
}
return r;
}
diff --git a/storage/tokudb/hatoku_hton.cc b/storage/tokudb/hatoku_hton.cc
index 88596b1650d..250935cf009 100644
--- a/storage/tokudb/hatoku_hton.cc
+++ b/storage/tokudb/hatoku_hton.cc
@@ -311,6 +311,10 @@ srv_row_format_t get_row_format(THD *thd)
return (srv_row_format_t) THDVAR(thd, row_format);
}
+static MYSQL_THDVAR_UINT(lock_timeout_debug, 0, "TokuDB lock timeout debug", NULL, NULL, 0, 0, ~0U, 1);
+
+static MYSQL_THDVAR_STR(last_lock_timeout, PLUGIN_VAR_MEMALLOC, "last TokuDB lock timeout", NULL, NULL, NULL);
+
static void tokudb_print_error(const DB_ENV * db_env, const char *db_errpfx, const char *buffer);
static void tokudb_cleanup_log_files(void);
static int tokudb_end(handlerton * hton, ha_panic_function type);
@@ -354,6 +358,7 @@ void toku_hton_update_primary_key_bytes_inserted(uint64_t row_size) {
}
static ulonglong tokudb_lock_timeout;
+static void tokudb_lock_timeout_callback(DB *db, uint64_t requesting_txnid, const DBT *left_key, const DBT *right_key, uint64_t blocking_txnid);
static ulong tokudb_cleaner_period;
static ulong tokudb_cleaner_iterations;
@@ -438,6 +443,7 @@ static SHOW_VAR *toku_global_status_variables = NULL;
static uint64_t toku_global_status_max_rows;
static TOKU_ENGINE_STATUS_ROW_S* toku_global_status_rows = NULL;
+
static int tokudb_init_func(void *p) {
TOKUDB_DBUG_ENTER("tokudb_init_func");
int r;
@@ -624,6 +630,8 @@ static int tokudb_init_func(void *p) {
db_env->set_update(db_env, tokudb_update_fun);
db_env_set_direct_io(tokudb_directio == TRUE);
db_env->change_fsync_log_period(db_env, tokudb_fsync_log_period);
+ db_env->set_lock_timeout_callback(db_env, tokudb_lock_timeout_callback);
+
r = db_env->open(db_env, tokudb_home, tokudb_init_flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH);
if (tokudb_debug & TOKUDB_DEBUG_INIT) TOKUDB_TRACE("%s:env opened:return=%d\n", __FUNCTION__, r);
@@ -856,54 +864,19 @@ typedef struct txn_progress_info {
THD* thd;
} *TXN_PROGRESS_INFO;
-
-void txn_progress_func(TOKU_TXN_PROGRESS progress, void* extra) {
+static void txn_progress_func(TOKU_TXN_PROGRESS progress, void* extra) {
TXN_PROGRESS_INFO progress_info = (TXN_PROGRESS_INFO)extra;
- int r;
- if (progress->stalled_on_checkpoint) {
- if (progress->is_commit) {
- r = sprintf(
- progress_info->status,
- "Writing committed changes to disk, processing commit of transaction, %"PRId64" out of %"PRId64,
- progress->entries_processed,
- progress->entries_total
- );
- assert(r >= 0);
- }
- else {
- r = sprintf(
- progress_info->status,
- "Writing committed changes to disk, processing abort of transaction, %"PRId64" out of %"PRId64,
- progress->entries_processed,
- progress->entries_total
- );
- assert(r >= 0);
- }
- }
- else {
- if (progress->is_commit) {
- r = sprintf(
- progress_info->status,
- "processing commit of transaction, %"PRId64" out of %"PRId64,
- progress->entries_processed,
- progress->entries_total
- );
- assert(r >= 0);
- }
- else {
- r = sprintf(
- progress_info->status,
- "processing abort of transaction, %"PRId64" out of %"PRId64,
- progress->entries_processed,
- progress->entries_total
- );
- assert(r >= 0);
- }
- }
+ int r = sprintf(progress_info->status,
+ "%sprocessing %s of transaction, %" PRId64 " out of %" PRId64,
+ progress->stalled_on_checkpoint ? "Writing committed changes to disk, " : "",
+ progress->is_commit ? "commit" : "abort",
+ progress->entries_processed,
+ progress->entries_total
+ );
+ assert(r >= 0);
thd_proc_info(progress_info->thd, progress_info->status);
}
-
static void commit_txn_with_progress(DB_TXN* txn, uint32_t flags, THD* thd) {
int r;
struct txn_progress_info info;
@@ -1551,6 +1524,8 @@ static struct st_mysql_sys_var *tokudb_system_variables[] = {
MYSQL_SYSVAR(fsync_log_period),
MYSQL_SYSVAR(gdb_path),
MYSQL_SYSVAR(gdb_on_fatal),
+ MYSQL_SYSVAR(last_lock_timeout),
+ MYSQL_SYSVAR(lock_timeout_debug),
NULL
};
@@ -2290,6 +2265,280 @@ static int tokudb_fractal_tree_block_map_done(void *p) {
return 0;
}
+static void tokudb_pretty_key(const DB *db, const DBT *key, const char *default_key, String *out) {
+ if (key->data == NULL) {
+ out->append(default_key);
+ } else {
+ bool do_hexdump = true;
+ if (do_hexdump) {
+ // hexdump the key
+ const unsigned char *data = reinterpret_cast<const unsigned char *>(key->data);
+ for (size_t i = 0; i < key->size; i++) {
+ char str[3];
+ snprintf(str, sizeof str, "%2.2x", data[i]);
+ out->append(str);
+ }
+ }
+ }
+}
+
+static void tokudb_pretty_left_key(const DB *db, const DBT *key, String *out) {
+ tokudb_pretty_key(db, key, "-infinity", out);
+}
+
+static void tokudb_pretty_right_key(const DB *db, const DBT *key, String *out) {
+ tokudb_pretty_key(db, key, "+infinity", out);
+}
+
+static const char *tokudb_get_index_name(DB *db) {
+ if (db != NULL) {
+ return db->get_dname(db);
+ } else {
+ return "$ydb_internal";
+ }
+}
+
+static void tokudb_lock_timeout_callback(DB *db, uint64_t requesting_txnid, const DBT *left_key, const DBT *right_key, uint64_t blocking_txnid) {
+ THD *thd = current_thd;
+ if (!thd)
+ return;
+ ulong lock_timeout_debug = THDVAR(thd, lock_timeout_debug);
+ if (lock_timeout_debug != 0) {
+ // generate a JSON document with the lock timeout info
+ String log_str;
+ log_str.append("{");
+ log_str.append("\"mysql_thread_id\":");
+ log_str.append_ulonglong(thd->thread_id);
+ log_str.append(", \"dbname\":\"");
+ log_str.append(tokudb_get_index_name(db));
+ log_str.append("\", \"requesting_txnid\":");
+ log_str.append_ulonglong(requesting_txnid);
+ log_str.append(", \"blocking_txnid\":");
+ log_str.append_ulonglong(blocking_txnid);
+ String left_str;
+ tokudb_pretty_left_key(db, left_key, &left_str);
+ log_str.append(", \"left\":\"");
+ log_str.append(left_str);
+ String right_str;
+ tokudb_pretty_right_key(db, right_key, &right_str);
+ log_str.append("\", \"right\":\"");
+ log_str.append(right_str);
+ log_str.append("\"}");
+ // set last_lock_timeout
+ if (lock_timeout_debug & 1) {
+ char *old_lock_timeout = THDVAR(thd, last_lock_timeout);
+ char *new_lock_timeout = my_strdup(log_str.c_ptr(), MY_FAE);
+ THDVAR(thd, last_lock_timeout) = new_lock_timeout;
+ my_free(old_lock_timeout);
+ }
+ // dump to stderr
+ if (lock_timeout_debug & 2) {
+ fprintf(stderr, "tokudb_lock_timeout: %s\n", log_str.c_ptr());
+ }
+ }
+}
+
+static struct st_mysql_information_schema tokudb_trx_information_schema = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+static ST_FIELD_INFO tokudb_trx_field_info[] = {
+ {"trx_id", 0, MYSQL_TYPE_LONGLONG, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"trx_mysql_thread_id", 0, MYSQL_TYPE_LONGLONG, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {NULL, 0, MYSQL_TYPE_NULL, 0, 0, NULL, SKIP_OPEN_TABLE}
+};
+
+struct tokudb_trx_extra {
+ THD *thd;
+ TABLE *table;
+};
+
+static int tokudb_trx_callback(uint64_t txn_id, uint64_t client_id, iterate_row_locks_callback iterate_locks, void *locks_extra, void *extra) {
+ struct tokudb_trx_extra *e = reinterpret_cast<struct tokudb_trx_extra *>(extra);
+ THD *thd = e->thd;
+ TABLE *table = e->table;
+ table->field[0]->store(txn_id, false);
+ table->field[1]->store(client_id, false);
+ int error = schema_table_store_record(thd, table);
+ return error;
+}
+
+#if MYSQL_VERSION_ID >= 50600
+static int tokudb_trx_fill_table(THD *thd, TABLE_LIST *tables, Item *cond) {
+#else
+static int tokudb_trx_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) {
+#endif
+ int error;
+
+ rw_rdlock(&tokudb_hton_initialized_lock);
+
+ if (!tokudb_hton_initialized) {
+ my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), "TokuDB");
+ error = -1;
+ } else {
+ struct tokudb_trx_extra e = { thd, tables->table };
+ error = db_env->iterate_live_transactions(db_env, tokudb_trx_callback, &e);
+ }
+
+ rw_unlock(&tokudb_hton_initialized_lock);
+ return error;
+}
+
+static int tokudb_trx_init(void *p) {
+ ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p;
+ schema->fields_info = tokudb_trx_field_info;
+ schema->fill_table = tokudb_trx_fill_table;
+ return 0;
+}
+
+static int tokudb_trx_done(void *p) {
+ return 0;
+}
+
+static struct st_mysql_information_schema tokudb_lock_waits_information_schema = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+static ST_FIELD_INFO tokudb_lock_waits_field_info[] = {
+ {"requesting_trx_id", 0, MYSQL_TYPE_LONGLONG, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"blocking_trx_id", 0, MYSQL_TYPE_LONGLONG, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"lock_waits_dname", 256, MYSQL_TYPE_STRING, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"lock_waits_left", 256, MYSQL_TYPE_STRING, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"lock_waits_right", 256, MYSQL_TYPE_STRING, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"lock_waits_start_time", 0, MYSQL_TYPE_LONGLONG, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {NULL, 0, MYSQL_TYPE_NULL, 0, 0, NULL, SKIP_OPEN_TABLE}
+};
+
+struct tokudb_lock_waits_extra {
+ THD *thd;
+ TABLE *table;
+};
+
+static int tokudb_lock_waits_callback(DB *db, uint64_t requesting_txnid, const DBT *left_key, const DBT *right_key,
+ uint64_t blocking_txnid, uint64_t start_time, void *extra) {
+ struct tokudb_lock_waits_extra *e = reinterpret_cast<struct tokudb_lock_waits_extra *>(extra);
+ THD *thd = e->thd;
+ TABLE *table = e->table;
+ table->field[0]->store(requesting_txnid, false);
+ table->field[1]->store(blocking_txnid, false);
+ const char *dname = tokudb_get_index_name(db);
+ size_t dname_length = strlen(dname);
+ table->field[2]->store(dname, dname_length, system_charset_info);
+ String left_str;
+ tokudb_pretty_left_key(db, left_key, &left_str);
+ table->field[3]->store(left_str.ptr(), left_str.length(), system_charset_info);
+ String right_str;
+ tokudb_pretty_right_key(db, right_key, &right_str);
+ table->field[4]->store(right_str.ptr(), right_str.length(), system_charset_info);
+ table->field[5]->store(start_time, false);
+ int error = schema_table_store_record(thd, table);
+ return error;
+}
+
+#if MYSQL_VERSION_ID >= 50600
+static int tokudb_lock_waits_fill_table(THD *thd, TABLE_LIST *tables, Item *cond) {
+#else
+static int tokudb_lock_waits_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) {
+#endif
+ int error;
+
+ rw_rdlock(&tokudb_hton_initialized_lock);
+
+ if (!tokudb_hton_initialized) {
+ my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), "TokuDB");
+ error = -1;
+ } else {
+ struct tokudb_lock_waits_extra e = { thd, tables->table };
+ error = db_env->iterate_pending_lock_requests(db_env, tokudb_lock_waits_callback, &e);
+ }
+
+ rw_unlock(&tokudb_hton_initialized_lock);
+ return error;
+}
+
+static int tokudb_lock_waits_init(void *p) {
+ ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p;
+ schema->fields_info = tokudb_lock_waits_field_info;
+ schema->fill_table = tokudb_lock_waits_fill_table;
+ return 0;
+}
+
+static int tokudb_lock_waits_done(void *p) {
+ return 0;
+}
+
+static struct st_mysql_information_schema tokudb_locks_information_schema = { MYSQL_INFORMATION_SCHEMA_INTERFACE_VERSION };
+
+static ST_FIELD_INFO tokudb_locks_field_info[] = {
+ {"locks_trx_id", 0, MYSQL_TYPE_LONGLONG, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"locks_mysql_thread_id", 0, MYSQL_TYPE_LONGLONG, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"locks_dname", 256, MYSQL_TYPE_STRING, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"locks_left", 256, MYSQL_TYPE_STRING, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {"locks_right", 256, MYSQL_TYPE_STRING, 0, 0, NULL, SKIP_OPEN_TABLE },
+ {NULL, 0, MYSQL_TYPE_NULL, 0, 0, NULL, SKIP_OPEN_TABLE}
+};
+
+struct tokudb_locks_extra {
+ THD *thd;
+ TABLE *table;
+};
+
+static int tokudb_locks_callback(uint64_t txn_id, uint64_t client_id, iterate_row_locks_callback iterate_locks, void *locks_extra, void *extra) {
+ struct tokudb_locks_extra *e = reinterpret_cast<struct tokudb_locks_extra *>(extra);
+ THD *thd = e->thd;
+ TABLE *table = e->table;
+ int error = 0;
+ DB *db;
+ DBT left_key, right_key;
+ while (error == 0 && iterate_locks(&db, &left_key, &right_key, locks_extra) == 0) {
+ table->field[0]->store(txn_id, false);
+ table->field[1]->store(client_id, false);
+
+ const char *dname = tokudb_get_index_name(db);
+ size_t dname_length = strlen(dname);
+ table->field[2]->store(dname, dname_length, system_charset_info);
+
+ String left_str;
+ tokudb_pretty_left_key(db, &left_key, &left_str);
+ table->field[3]->store(left_str.ptr(), left_str.length(), system_charset_info);
+
+ String right_str;
+ tokudb_pretty_right_key(db, &right_key, &right_str);
+ table->field[4]->store(right_str.ptr(), right_str.length(), system_charset_info);
+
+ error = schema_table_store_record(thd, table);
+ }
+ return error;
+}
+
+#if MYSQL_VERSION_ID >= 50600
+static int tokudb_locks_fill_table(THD *thd, TABLE_LIST *tables, Item *cond) {
+#else
+static int tokudb_locks_fill_table(THD *thd, TABLE_LIST *tables, COND *cond) {
+#endif
+ int error;
+
+ rw_rdlock(&tokudb_hton_initialized_lock);
+
+ if (!tokudb_hton_initialized) {
+ my_error(ER_PLUGIN_IS_NOT_LOADED, MYF(0), "TokuDB");
+ error = -1;
+ } else {
+ struct tokudb_locks_extra e = { thd, tables->table };
+ error = db_env->iterate_live_transactions(db_env, tokudb_locks_callback, &e);
+ }
+
+ rw_unlock(&tokudb_hton_initialized_lock);
+ return error;
+}
+
+static int tokudb_locks_init(void *p) {
+ ST_SCHEMA_TABLE *schema = (ST_SCHEMA_TABLE *) p;
+ schema->fields_info = tokudb_locks_field_info;
+ schema->fill_table = tokudb_locks_fill_table;
+ return 0;
+}
+
+static int tokudb_locks_done(void *p) {
+ return 0;
+}
+
enum { TOKUDB_PLUGIN_VERSION = 0x0400 };
#define TOKUDB_PLUGIN_VERSION_STR "1024"
@@ -2434,6 +2683,57 @@ mysql_declare_plugin(tokudb)
},
{
MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &tokudb_trx_information_schema,
+ "TokuDB_trx",
+ "Tokutek Inc",
+ "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
+ PLUGIN_LICENSE_GPL,
+ tokudb_trx_init, /* plugin init */
+ tokudb_trx_done, /* plugin deinit */
+ TOKUDB_PLUGIN_VERSION, /* 4.0.0 */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ NULL, /* config options */
+#if MYSQL_VERSION_ID >= 50521
+ 0, /* flags */
+#endif
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &tokudb_lock_waits_information_schema,
+ "TokuDB_lock_waits",
+ "Tokutek Inc",
+ "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
+ PLUGIN_LICENSE_GPL,
+ tokudb_lock_waits_init, /* plugin init */
+ tokudb_lock_waits_done, /* plugin deinit */
+ TOKUDB_PLUGIN_VERSION, /* 4.0.0 */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ NULL, /* config options */
+#if MYSQL_VERSION_ID >= 50521
+ 0, /* flags */
+#endif
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &tokudb_locks_information_schema,
+ "TokuDB_locks",
+ "Tokutek Inc",
+ "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
+ PLUGIN_LICENSE_GPL,
+ tokudb_locks_init, /* plugin init */
+ tokudb_locks_done, /* plugin deinit */
+ TOKUDB_PLUGIN_VERSION, /* 4.0.0 */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ NULL, /* config options */
+#if MYSQL_VERSION_ID >= 50521
+ 0, /* flags */
+#endif
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
&tokudb_user_data_information_schema,
"TokuDB_user_data",
"Tokutek Inc",
@@ -2539,6 +2839,51 @@ maria_declare_plugin(tokudb)
},
{
MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &tokudb_trx_information_schema,
+ "TokuDB_trx",
+ "Tokutek Inc",
+ "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
+ PLUGIN_LICENSE_GPL,
+ tokudb_trx_init, /* plugin init */
+ tokudb_trx_done, /* plugin deinit */
+ TOKUDB_PLUGIN_VERSION, /* 4.0.0 */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ TOKUDB_PLUGIN_VERSION_STR, /* string version */
+ MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &tokudb_lock_waits_information_schema,
+ "TokuDB_lock_waits",
+ "Tokutek Inc",
+ "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
+ PLUGIN_LICENSE_GPL,
+ tokudb_lock_waits_init, /* plugin init */
+ tokudb_lock_waits_done, /* plugin deinit */
+ TOKUDB_PLUGIN_VERSION, /* 4.0.0 */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ TOKUDB_PLUGIN_VERSION_STR, /* string version */
+ MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
+ &tokudb_locks_information_schema,
+ "TokuDB_locks",
+ "Tokutek Inc",
+ "Tokutek TokuDB Storage Engine with Fractal Tree(tm) Technology",
+ PLUGIN_LICENSE_GPL,
+ tokudb_locks_init, /* plugin init */
+ tokudb_locks_done, /* plugin deinit */
+ TOKUDB_PLUGIN_VERSION, /* 4.0.0 */
+ NULL, /* status variables */
+ NULL, /* system variables */
+ TOKUDB_PLUGIN_VERSION_STR, /* string version */
+ MariaDB_PLUGIN_MATURITY_STABLE /* maturity */
+},
+{
+ MYSQL_INFORMATION_SCHEMA_PLUGIN,
&tokudb_user_data_information_schema,
"TokuDB_user_data",
"Tokutek Inc",