diff --git a/storage/tokudb/ha_tokudb.cc b/storage/tokudb/ha_tokudb.cc index 5825f7844eb..26a2e7489af 100644 --- a/storage/tokudb/ha_tokudb.cc +++ b/storage/tokudb/ha_tokudb.cc @@ -1379,6 +1379,13 @@ int ha_tokudb::initialize_share( init_auto_increment(); } + if (may_table_be_empty()) { + share->try_table_lock = true; + } + else { + share->try_table_lock = false; + } + error = 0; exit: my_free(newname, MYF(MY_ALLOW_ZERO_PTR)); @@ -2547,6 +2554,47 @@ bool ha_tokudb::check_if_incompatible_data(HA_CREATE_INFO * info, uint table_cha // "insert into foo select * from bar), then rows // will be 0 // +// +// This function returns true if the table MAY be empty. +// It is NOT meant to be a 100% check for emptiness. +// This is used for a bulk load optimization. +// +bool ha_tokudb::may_table_be_empty() { + int error; + bool ret_val = false; + DBC* tmp_cursor = NULL; + DB_TXN* txn = NULL; + + error = db_env->txn_begin(db_env, 0, &txn, 0); + if (error) { + goto cleanup; + } + + error = share->file->cursor(share->file, txn, &tmp_cursor, 0); + if (error) { + goto cleanup; + } + error = tmp_cursor->c_getf_next(tmp_cursor, 0, smart_dbt_do_nothing, NULL); + if (error == DB_NOTFOUND) { + ret_val = true; + } + else { + ret_val = false; + } + error = 0; +cleanup: + if (tmp_cursor) { + tmp_cursor->c_close(tmp_cursor); + tmp_cursor = NULL; + } + if (txn) { + int r = txn->commit(txn, 0); + assert(r == 0); + txn = NULL; + } + return ret_val; +} + void ha_tokudb::start_bulk_insert(ha_rows rows) { // // make sure delay_updating_ai_metadata is true, iff the auto inc column @@ -2554,6 +2602,14 @@ void ha_tokudb::start_bulk_insert(ha_rows rows) { // delay_updating_ai_metadata = share->ai_first_col; ai_metadata_update_required = false; + if (share->try_table_lock) { + if (may_table_be_empty() && tokudb_prelock_empty) { + acquire_table_lock(transaction, lock_write); + } + pthread_mutex_lock(&share->mutex); + share->try_table_lock = false; + pthread_mutex_unlock(&share->mutex); + } } // diff --git a/storage/tokudb/ha_tokudb.h b/storage/tokudb/ha_tokudb.h index 233f18b6fde..442a4b7bdc9 100644 --- a/storage/tokudb/ha_tokudb.h +++ b/storage/tokudb/ha_tokudb.h @@ -70,6 +70,13 @@ typedef struct st_tokudb_share { MULTI_COL_PACK_INFO mcp_info[MAX_KEY+1]; COL_PACK_INFO* cp_info[MAX_KEY+1]; u_int32_t num_offset_bytes; //number of bytes needed to encode the offset + // + // we want the following optimization for bulk loads, if the table is empty, + // attempt to grab a table lock. emptiness check can be expensive, + // so we try it once for a table. After that, we keep this variable around + // to tell us to not try it again. + // + bool try_table_lock; } TOKUDB_SHARE; #define HA_TOKU_VERSION 2 @@ -277,6 +284,7 @@ private: void set_query_columns(uint keynr); int prelock_range ( const key_range *start_key, const key_range *end_key); int create_txn(THD* thd, tokudb_trx_data* trx); + bool may_table_be_empty(); diff --git a/storage/tokudb/hatoku_hton.cc b/storage/tokudb/hatoku_hton.cc index e809b4ac90c..fc8333b3e98 100644 --- a/storage/tokudb/hatoku_hton.cc +++ b/storage/tokudb/hatoku_hton.cc @@ -107,6 +107,7 @@ static ulong tokudb_max_lock; static const char tokudb_hton_name[] = "TokuDB"; static const int tokudb_hton_name_length = sizeof(tokudb_hton_name) - 1; static u_int32_t tokudb_checkpointing_period; +my_bool tokudb_prelock_empty; #ifdef TOKUDB_VERSION char *tokudb_version = TOKUDB_VERSION; #else @@ -766,6 +767,7 @@ static MYSQL_SYSVAR_STR(version, tokudb_version, PLUGIN_VAR_READONLY, "TokuDB Ve static MYSQL_SYSVAR_UINT(init_flags, tokudb_init_flags, PLUGIN_VAR_READONLY, "Sets TokuDB DB_ENV->open flags", NULL, NULL, tokudb_init_flags, 0, ~0, 0); static MYSQL_SYSVAR_UINT(checkpointing_period, tokudb_checkpointing_period, 0, "TokuDB Checkpointing period", NULL, NULL, 60, 0, ~0L, 0); +static MYSQL_SYSVAR_BOOL(prelock_empty, tokudb_prelock_empty, 0, "Tokudb Shared Data", NULL, NULL, TRUE); #if 0 static MYSQL_SYSVAR_ULONG(cache_parts, tokudb_cache_parts, PLUGIN_VAR_READONLY, "Sets TokuDB set_cache_parts", NULL, NULL, 0, 0, ~0L, 0); @@ -805,6 +807,7 @@ static struct st_mysql_sys_var *tokudb_system_variables[] = { MYSQL_SYSVAR(version), MYSQL_SYSVAR(init_flags), MYSQL_SYSVAR(checkpointing_period), + MYSQL_SYSVAR(prelock_empty), #if 0 MYSQL_SYSVAR(cache_parts), MYSQL_SYSVAR(env_flags), diff --git a/storage/tokudb/hatoku_hton.h b/storage/tokudb/hatoku_hton.h index 5301896f2e5..f79cdc19fe6 100644 --- a/storage/tokudb/hatoku_hton.h +++ b/storage/tokudb/hatoku_hton.h @@ -16,9 +16,6 @@ extern DB *metadata_db; extern HASH tokudb_open_tables; extern pthread_mutex_t tokudb_mutex; extern pthread_mutex_t tokudb_meta_mutex; - - - - +extern my_bool tokudb_prelock_empty; #endif //#ifdef _HATOKU_HTON