diff --git a/storage/tokudb/ha_tokudb.cc b/storage/tokudb/ha_tokudb.cc index 9ca7d8d439a..52eeb8f016c 100644 --- a/storage/tokudb/ha_tokudb.cc +++ b/storage/tokudb/ha_tokudb.cc @@ -1218,6 +1218,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)); @@ -2352,12 +2359,61 @@ bool ha_tokudb::check_if_incompatible_data(HA_CREATE_INFO * info, uint table_cha } +// +// 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_opt_callback, 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_auto_inc_update is true // delay_auto_inc_update = true; auto_inc_update_req = false; + if (share->try_table_lock) { + if (may_table_be_empty()) { + acquire_table_lock(transaction, lock_write); + } + pthread_mutex_lock(&share->mutex); + share->try_table_lock = false; + pthread_mutex_unlock(&share->mutex); + } } int ha_tokudb::end_bulk_insert() { diff --git a/storage/tokudb/ha_tokudb.h b/storage/tokudb/ha_tokudb.h index 98a028b88f2..2ecdb1d8c67 100644 --- a/storage/tokudb/ha_tokudb.h +++ b/storage/tokudb/ha_tokudb.h @@ -62,6 +62,14 @@ 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 @@ -273,7 +281,7 @@ private: void set_query_columns(uint keynr); int prelock_range ( const key_range *start_key, const key_range *end_key); - + bool may_table_be_empty(); public: ha_tokudb(handlerton * hton, TABLE_SHARE * table_arg);