summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_monitor_disable_basic.result8
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_monitor_enable_basic.result8
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_monitor_reset_all_basic.result8
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_monitor_reset_basic.result8
-rw-r--r--storage/innobase/api/api0api.cc64
-rw-r--r--storage/innobase/btr/btr0btr.cc11
-rw-r--r--storage/innobase/btr/btr0cur.cc31
-rw-r--r--storage/innobase/btr/btr0pcur.cc44
-rw-r--r--storage/innobase/dict/dict0crea.cc14
-rw-r--r--storage/innobase/dict/dict0load.cc2
-rw-r--r--storage/innobase/dict/dict0mem.cc6
-rw-r--r--storage/innobase/dict/dict0stats.cc27
-rw-r--r--storage/innobase/fts/fts0config.cc4
-rw-r--r--storage/innobase/fts/fts0fts.cc61
-rw-r--r--storage/innobase/fts/fts0opt.cc30
-rw-r--r--storage/innobase/fts/fts0que.cc17
-rw-r--r--storage/innobase/handler/ha_innodb.cc184
-rw-r--r--storage/innobase/handler/handler0alter.cc12
-rw-r--r--storage/innobase/handler/i_s.cc225
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc28
-rw-r--r--storage/innobase/include/api0api.h16
-rw-r--r--storage/innobase/include/btr0cur.h14
-rw-r--r--storage/innobase/include/btr0pcur.h44
-rw-r--r--storage/innobase/include/btr0pcur.ic4
-rw-r--r--storage/innobase/include/btr0sea.h2
-rw-r--r--storage/innobase/include/db0err.h1
-rw-r--r--storage/innobase/include/dict0stats.ic2
-rw-r--r--storage/innobase/include/dict0types.h5
-rw-r--r--storage/innobase/include/fts0fts.h10
-rw-r--r--storage/innobase/include/fts0types.h1
-rw-r--r--storage/innobase/include/ibuf0ibuf.h5
-rw-r--r--storage/innobase/include/log0log.h2
-rw-r--r--storage/innobase/include/mtr0mtr.h2
-rw-r--r--storage/innobase/include/mtr0mtr.ic39
-rw-r--r--storage/innobase/include/row0ftsort.h6
-rw-r--r--storage/innobase/include/srv0conc.h2
-rw-r--r--storage/innobase/include/srv0mon.h6
-rw-r--r--storage/innobase/include/srv0mon.ic2
-rw-r--r--storage/innobase/include/sync0arr.h23
-rw-r--r--storage/innobase/include/sync0arr.ic40
-rw-r--r--storage/innobase/include/sync0sync.h2
-rw-r--r--storage/innobase/include/trx0trx.h4
-rw-r--r--storage/innobase/include/ut0bh.h2
-rw-r--r--storage/innobase/include/ut0bh.ic2
-rw-r--r--storage/innobase/log/log0log.cc109
-rw-r--r--storage/innobase/mtr/mtr0mtr.cc29
-rw-r--r--storage/innobase/os/os0file.cc36
-rw-r--r--storage/innobase/os/os0thread.cc5
-rw-r--r--storage/innobase/row/row0ftsort.cc142
-rw-r--r--storage/innobase/row/row0log.cc140
-rw-r--r--storage/innobase/row/row0merge.cc110
-rw-r--r--storage/innobase/row/row0mysql.cc2
-rw-r--r--storage/innobase/row/row0quiesce.cc2
-rw-r--r--storage/innobase/row/row0sel.cc103
-rw-r--r--storage/innobase/srv/srv0mon.cc28
-rw-r--r--storage/innobase/srv/srv0start.cc55
-rw-r--r--storage/innobase/sync/sync0arr.cc14
-rw-r--r--storage/innobase/sync/sync0rw.cc27
-rw-r--r--storage/innobase/sync/sync0sync.cc9
-rw-r--r--storage/innobase/trx/trx0purge.cc2
-rw-r--r--storage/innobase/trx/trx0sys.cc4
-rw-r--r--storage/innobase/trx/trx0trx.cc31
-rw-r--r--storage/innobase/ut/ut0ut.cc2
63 files changed, 1280 insertions, 598 deletions
diff --git a/mysql-test/suite/sys_vars/r/innodb_monitor_disable_basic.result b/mysql-test/suite/sys_vars/r/innodb_monitor_disable_basic.result
index ce57dbb2fdc..6f1c4c21d17 100644
--- a/mysql-test/suite/sys_vars/r/innodb_monitor_disable_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_monitor_disable_basic.result
@@ -160,8 +160,12 @@ compress_pages_compressed disabled
compress_pages_decompressed disabled
compression_pad_increments disabled
compression_pad_decrements disabled
-index_splits disabled
-index_merges disabled
+index_page_splits disabled
+index_page_merge_attempts disabled
+index_page_merge_successful disabled
+index_page_reorg_attempts disabled
+index_page_reorg_successful disabled
+index_page_discards disabled
adaptive_hash_searches disabled
adaptive_hash_searches_btree disabled
adaptive_hash_pages_added disabled
diff --git a/mysql-test/suite/sys_vars/r/innodb_monitor_enable_basic.result b/mysql-test/suite/sys_vars/r/innodb_monitor_enable_basic.result
index ce57dbb2fdc..6f1c4c21d17 100644
--- a/mysql-test/suite/sys_vars/r/innodb_monitor_enable_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_monitor_enable_basic.result
@@ -160,8 +160,12 @@ compress_pages_compressed disabled
compress_pages_decompressed disabled
compression_pad_increments disabled
compression_pad_decrements disabled
-index_splits disabled
-index_merges disabled
+index_page_splits disabled
+index_page_merge_attempts disabled
+index_page_merge_successful disabled
+index_page_reorg_attempts disabled
+index_page_reorg_successful disabled
+index_page_discards disabled
adaptive_hash_searches disabled
adaptive_hash_searches_btree disabled
adaptive_hash_pages_added disabled
diff --git a/mysql-test/suite/sys_vars/r/innodb_monitor_reset_all_basic.result b/mysql-test/suite/sys_vars/r/innodb_monitor_reset_all_basic.result
index ce57dbb2fdc..6f1c4c21d17 100644
--- a/mysql-test/suite/sys_vars/r/innodb_monitor_reset_all_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_monitor_reset_all_basic.result
@@ -160,8 +160,12 @@ compress_pages_compressed disabled
compress_pages_decompressed disabled
compression_pad_increments disabled
compression_pad_decrements disabled
-index_splits disabled
-index_merges disabled
+index_page_splits disabled
+index_page_merge_attempts disabled
+index_page_merge_successful disabled
+index_page_reorg_attempts disabled
+index_page_reorg_successful disabled
+index_page_discards disabled
adaptive_hash_searches disabled
adaptive_hash_searches_btree disabled
adaptive_hash_pages_added disabled
diff --git a/mysql-test/suite/sys_vars/r/innodb_monitor_reset_basic.result b/mysql-test/suite/sys_vars/r/innodb_monitor_reset_basic.result
index ce57dbb2fdc..6f1c4c21d17 100644
--- a/mysql-test/suite/sys_vars/r/innodb_monitor_reset_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_monitor_reset_basic.result
@@ -160,8 +160,12 @@ compress_pages_compressed disabled
compress_pages_decompressed disabled
compression_pad_increments disabled
compression_pad_decrements disabled
-index_splits disabled
-index_merges disabled
+index_page_splits disabled
+index_page_merge_attempts disabled
+index_page_merge_successful disabled
+index_page_reorg_attempts disabled
+index_page_reorg_successful disabled
+index_page_discards disabled
adaptive_hash_searches disabled
adaptive_hash_searches_btree disabled
adaptive_hash_pages_added disabled
diff --git a/storage/innobase/api/api0api.cc b/storage/innobase/api/api0api.cc
index 647ebcde6f0..d2f1a468f25 100644
--- a/storage/innobase/api/api0api.cc
+++ b/storage/innobase/api/api0api.cc
@@ -355,7 +355,9 @@ ib_read_tuple(
/*==========*/
const rec_t* rec, /*!< in: Record to read */
ib_bool_t page_format, /*!< in: IB_TRUE if compressed format */
- ib_tuple_t* tuple) /*!< in: tuple to read into */
+ ib_tuple_t* tuple, /*!< in: tuple to read into */
+ void** rec_buf, /*!< in/out: row buffer */
+ ulint* len) /*!< in/out: buffer len */
{
ulint i;
void* ptr;
@@ -366,6 +368,7 @@ ib_read_tuple(
ulint* offsets = offsets_;
dtuple_t* dtuple = tuple->ptr;
const dict_index_t* index = tuple->index;
+ ulint offset_size;
rec_offs_init(offsets_);
@@ -375,8 +378,20 @@ ib_read_tuple(
rec_meta_data = rec_get_info_bits(rec, page_format);
dtuple_set_info_bits(dtuple, rec_meta_data);
- /* Make a copy of the rec. */
- ptr = mem_heap_alloc(tuple->heap, rec_offs_size(offsets));
+ offset_size = rec_offs_size(offsets);
+
+ if (rec_buf && *rec_buf) {
+ if (*len < offset_size) {
+ free(*rec_buf);
+ *rec_buf = malloc(offset_size);
+ *len = offset_size;
+ }
+ ptr = *rec_buf;
+ } else {
+ /* Make a copy of the rec. */
+ ptr = mem_heap_alloc(tuple->heap, offset_size);
+ }
+
copy = rec_copy(ptr, rec, offsets);
n_index_fields = ut_min(
@@ -557,6 +572,10 @@ ib_trx_start(
/*=========*/
ib_trx_t ib_trx, /*!< in: transaction to restart */
ib_trx_level_t ib_trx_level, /*!< in: trx isolation level */
+ ib_bool_t read_write, /*!< in: true if read write
+ transaction */
+ ib_bool_t auto_commit, /*!< in: auto commit after each
+ single DML */
void* thd) /*!< in: THD */
{
ib_err_t err = DB_SUCCESS;
@@ -564,6 +583,10 @@ ib_trx_start(
ut_a(ib_trx_level <= IB_TRX_SERIALIZABLE);
+ trx->api_trx = true;
+ trx->api_auto_commit = auto_commit;
+ trx->read_write = read_write;
+
trx_start_if_not_started(trx);
trx->isolation_level = ib_trx_level;
@@ -583,16 +606,22 @@ UNIV_INTERN
ib_trx_t
ib_trx_begin(
/*=========*/
- ib_trx_level_t ib_trx_level) /*!< in: trx isolation level */
+ ib_trx_level_t ib_trx_level, /*!< in: trx isolation level */
+ ib_bool_t read_write, /*!< in: true if read write
+ transaction */
+ ib_bool_t auto_commit) /*!< in: auto commit after each
+ single DML */
{
trx_t* trx;
ib_bool_t started;
trx = trx_allocate_for_mysql();
- started = ib_trx_start((ib_trx_t) trx, ib_trx_level, NULL);
+
+ started = ib_trx_start(static_cast<ib_trx_t>(trx), ib_trx_level,
+ read_write, auto_commit, NULL);
ut_a(started);
- return((ib_trx_t) trx);
+ return(static_cast<ib_trx_t>(trx));
}
/*****************************************************************//**
@@ -652,15 +681,11 @@ ib_trx_commit(
trx_t* trx = (trx_t*) ib_trx;
if (trx->state == TRX_STATE_NOT_STARTED) {
- err = ib_trx_release(ib_trx);
return(err);
}
trx_commit(trx);
- err = ib_trx_release(ib_trx);
- ut_a(err == DB_SUCCESS);
-
return(DB_SUCCESS);
}
@@ -682,9 +707,6 @@ ib_trx_rollback(
/* It should always succeed */
ut_a(err == DB_SUCCESS);
- err = ib_trx_release(ib_trx);
- ut_a(err == DB_SUCCESS);
-
ib_wake_master_thread();
return(err);
@@ -1371,11 +1393,12 @@ ib_cursor_commit_trx(
{
ib_err_t err = DB_SUCCESS;
ib_cursor_t* cursor = (ib_cursor_t*) ib_crsr;
+#ifdef UNIV_DEBUG
row_prebuilt_t* prebuilt = cursor->prebuilt;
ut_ad(prebuilt->trx == (trx_t*) ib_trx);
- err = ib_trx_commit(ib_trx);
- prebuilt->trx = NULL;
+#endif /* UNIV_DEBUG */
+ ib_trx_commit(ib_trx);
cursor->valid_trx = FALSE;
return(err);
}
@@ -1955,7 +1978,7 @@ ib_delete_row(
upd = ib_update_vector_create(cursor);
page_format = dict_table_is_comp(index->table);
- ib_read_tuple(rec, page_format, tuple);
+ ib_read_tuple(rec, page_format, tuple, NULL, NULL);
upd->n_fields = ib_tuple_get_n_cols(ib_tpl);
@@ -2056,7 +2079,9 @@ ib_err_t
ib_cursor_read_row(
/*===============*/
ib_crsr_t ib_crsr, /*!< in: InnoDB cursor instance */
- ib_tpl_t ib_tpl) /*!< out: read cols into this tuple */
+ ib_tpl_t ib_tpl, /*!< out: read cols into this tuple */
+ void** row_buf, /*!< in/out: row buffer */
+ ib_ulint_t* row_len) /*!< in/out: row buffer len */
{
ib_err_t err;
ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl;
@@ -2100,7 +2125,8 @@ ib_cursor_read_row(
}
if (!rec_get_deleted_flag(rec, page_format)) {
- ib_read_tuple(rec, page_format, tuple);
+ ib_read_tuple(rec, page_format, tuple,
+ row_buf, (ulint*) row_len);
err = DB_SUCCESS;
} else{
err = DB_RECORD_NOT_FOUND;
@@ -3845,7 +3871,7 @@ ib_table_truncate(
ib_trx_t ib_trx = NULL;
ib_crsr_t ib_crsr = NULL;
- ib_trx = ib_trx_begin(IB_TRX_SERIALIZABLE);
+ ib_trx = ib_trx_begin(IB_TRX_SERIALIZABLE, true, false);
dict_mutex_enter_for_mysql();
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 63b01f65f4b..0136c9c43a3 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -1802,6 +1802,8 @@ btr_page_reorganize_low(
#endif /* !UNIV_HOTBACKUP */
temp_page = temp_block->frame;
+ MONITOR_INC(MONITOR_INDEX_REORG_ATTEMPTS);
+
/* Copy the old page to temporary space */
buf_frame_copy(temp_page, page);
@@ -1950,6 +1952,8 @@ func_exit:
mach_write_to_1(log_ptr, z_level);
mlog_close(mtr, log_ptr + 1);
}
+
+ MONITOR_INC(MONITOR_INDEX_REORG_SUCCESSFUL);
}
#endif /* !UNIV_HOTBACKUP */
@@ -3573,6 +3577,8 @@ btr_compress(
space = dict_index_get_space(index);
zip_size = dict_table_zip_size(index->table);
+ MONITOR_INC(MONITOR_INDEX_MERGE_ATTEMPTS);
+
left_page_no = btr_page_get_prev(page, mtr);
right_page_no = btr_page_get_next(page, mtr);
@@ -3806,6 +3812,9 @@ func_exit:
page_rec_get_nth(merge_block->frame, nth_rec),
merge_block, cursor);
}
+
+ MONITOR_INC(MONITOR_INDEX_MERGE_SUCCESSFUL);
+
DBUG_RETURN(TRUE);
err_exit:
@@ -3926,6 +3935,8 @@ btr_discard_page(
space = dict_index_get_space(index);
zip_size = dict_table_zip_size(index->table);
+ MONITOR_INC(MONITOR_INDEX_DISCARD);
+
/* Decide the page which will inherit the locks */
left_page_no = btr_page_get_prev(buf_block_get_frame(block), mtr);
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index bbc189d1d39..7e1483cfe85 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -1696,7 +1696,7 @@ btr_cur_upd_lock_and_undo(
/***********************************************************//**
Writes a redo log record of updating a record in-place. */
-UNIV_INLINE __attribute__((nonnull))
+UNIV_INTERN
void
btr_cur_update_in_place_log(
/*========================*/
@@ -1724,18 +1724,29 @@ btr_cur_update_in_place_log(
return;
}
- /* The code below assumes index is a clustered index: change index to
- the clustered index if we are updating a secondary index record (or we
- could as well skip writing the sys col values to the log in this case
- because they are not needed for a secondary index record update) */
-
- index = dict_table_get_first_index(index->table);
-
+ /* For secondary indexes, we could skip writing the dummy system fields
+ to the redo log but we have to change redo log parsing of
+ MLOG_REC_UPDATE_IN_PLACE/MLOG_COMP_REC_UPDATE_IN_PLACE or we have to add
+ new redo log record. For now, just write dummy sys fields to the redo
+ log if we are updating a secondary index record.
+ */
mach_write_to_1(log_ptr, flags);
log_ptr++;
- log_ptr = row_upd_write_sys_vals_to_log(
- index, trx_id, roll_ptr, log_ptr, mtr);
+ if (dict_index_is_clust(index)) {
+ log_ptr = row_upd_write_sys_vals_to_log(
+ index, trx_id, roll_ptr, log_ptr, mtr);
+ } else {
+ /* Dummy system fields for a secondary index */
+ /* TRX_ID Position */
+ log_ptr += mach_write_compressed(log_ptr, 0);
+ /* ROLL_PTR */
+ trx_write_roll_ptr(log_ptr, 0);
+ log_ptr += DATA_ROLL_PTR_LEN;
+ /* TRX_ID */
+ log_ptr += mach_ull_write_compressed(log_ptr, 0);
+ }
+
mach_write_to_2(log_ptr, page_offset(rec));
log_ptr += 2;
diff --git a/storage/innobase/btr/btr0pcur.cc b/storage/innobase/btr/btr0pcur.cc
index 54ef2a243ba..82a2b6dbf6b 100644
--- a/storage/innobase/btr/btr0pcur.cc
+++ b/storage/innobase/btr/btr0pcur.cc
@@ -110,7 +110,7 @@ btr_pcur_store_position(
page_t* page;
ulint offs;
- ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
+ ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
block = btr_pcur_get_block(cursor);
@@ -124,7 +124,6 @@ btr_pcur_store_position(
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX)
|| mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
- ut_a(cursor->latch_mode != BTR_NO_LATCHES);
if (page_is_empty(page)) {
/* It must be an empty index tree; NOTE that in this case
@@ -236,21 +235,12 @@ btr_pcur_restore_position_func(
ut_ad(mtr);
ut_ad(mtr->state == MTR_ACTIVE);
+ ut_ad(cursor->old_stored == BTR_PCUR_OLD_STORED);
+ ut_ad(cursor->pos_state == BTR_PCUR_WAS_POSITIONED
+ || cursor->pos_state == BTR_PCUR_IS_POSITIONED);
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
- if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
- || UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
- && cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
- ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
- putc('\n', stderr);
- if (cursor->trx_if_known) {
- trx_print(stderr, cursor->trx_if_known, 0);
- }
-
- ut_error;
- }
-
if (UNIV_UNLIKELY
(cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
@@ -275,14 +265,14 @@ btr_pcur_restore_position_func(
if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
|| UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
- /* Try optimistic restoration */
+ /* Try optimistic restoration. */
- if (UNIV_LIKELY(buf_page_optimistic_get(
- latch_mode,
- cursor->block_when_stored,
- cursor->modify_clock,
- file, line, mtr))) {
+ if (buf_page_optimistic_get(latch_mode,
+ cursor->block_when_stored,
+ cursor->modify_clock,
+ file, line, mtr)) {
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
+ cursor->latch_mode = latch_mode;
buf_block_dbg_add_level(
btr_pcur_get_block(cursor),
@@ -294,9 +284,6 @@ btr_pcur_restore_position_func(
const rec_t* rec;
const ulint* offsets1;
const ulint* offsets2;
-#endif /* UNIV_DEBUG */
- cursor->latch_mode = latch_mode;
-#ifdef UNIV_DEBUG
rec = btr_pcur_get_rec(cursor);
heap = mem_heap_create(256);
@@ -314,7 +301,13 @@ btr_pcur_restore_position_func(
#endif /* UNIV_DEBUG */
return(TRUE);
}
-
+ /* This is the same record as stored,
+ may need to be adjusted for BTR_PCUR_BEFORE/AFTER,
+ depending on search mode and direction. */
+ if (btr_pcur_is_on_user_rec(cursor)) {
+ cursor->pos_state
+ = BTR_PCUR_IS_POSITIONED_OPTIMISTIC;
+ }
return(FALSE);
}
}
@@ -416,7 +409,7 @@ btr_pcur_move_to_next_page(
buf_block_t* next_block;
page_t* next_page;
- ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
+ ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
ut_ad(btr_pcur_is_after_last_on_page(cursor));
@@ -471,7 +464,6 @@ btr_pcur_move_backward_from_page(
ulint latch_mode;
ulint latch_mode2;
- ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
ut_ad(btr_pcur_is_before_first_on_page(cursor));
ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index c7cb3aa21bb..eba5417dc76 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -803,6 +803,7 @@ dict_truncate_index_tree(
const byte* ptr;
ulint len;
dict_index_t* index;
+ bool has_been_dropped = false;
ut_ad(mutex_own(&(dict_sys->mutex)));
ut_a(!dict_table_is_comp(dict_sys->sys_indexes));
@@ -815,11 +816,7 @@ dict_truncate_index_tree(
root_page_no = mtr_read_ulint(ptr, MLOG_4BYTES, mtr);
if (drop && root_page_no == FIL_NULL) {
- /* The tree has been freed. */
-
- ut_print_timestamp(stderr);
- fprintf(stderr, " InnoDB: Trying to TRUNCATE"
- " a missing index of table %s!\n", table->name);
+ has_been_dropped = true;
drop = FALSE;
}
@@ -896,6 +893,13 @@ create:
if (index->type & DICT_FTS) {
return(FIL_NULL);
} else {
+ if (has_been_dropped) {
+ fprintf(stderr, " InnoDB: Trying to"
+ " TRUNCATE a missing index of"
+ " table %s!\n",
+ index->table->name);
+ }
+
root_page_no = btr_create(type, space, zip_size,
index_id, index, mtr);
index->page = (unsigned int) root_page_no;
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index 6ffb6924402..81ab765b524 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -1358,7 +1358,7 @@ dict_load_columns(
BTR_SEARCH_LEAF, &pcur, &mtr);
for (i = 0; i + DATA_N_SYS_COLS < (ulint) table->n_cols; i++) {
const char* err_msg;
- const char* name;
+ const char* name = NULL;
rec = btr_pcur_get_rec(&pcur);
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index b060a79e75a..565a46b1832 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -139,10 +139,12 @@ dict_mem_table_free(
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_ADD_DOC_ID)) {
if (table->fts) {
+ if (table->cached) {
+ fts_optimize_remove_table(table);
+ }
+
fts_free(table);
}
-
- fts_optimize_remove_table(table);
}
#ifndef UNIV_HOTBACKUP
mutex_free(&(table->autoinc_mutex));
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index bfd0542b8e2..8bf02f9785c 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -780,10 +780,21 @@ dict_stats_update_transient_for_index(
/*==================================*/
dict_index_t* index) /*!< in/out: index */
{
- if (UNIV_LIKELY
- (srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
- || (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
- && dict_index_is_clust(index)))) {
+ if (srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
+ && (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO
+ || !dict_index_is_clust(index))) {
+ /* If we have set a high innodb_force_recovery
+ level, do not calculate statistics, as a badly
+ corrupted index can cause a crash in it.
+ Initialize some bogus index cardinality
+ statistics, so that the data can be queried in
+ various means, also via secondary indexes. */
+ dict_stats_empty_index(index);
+#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
+ } else if (ibuf_debug && !dict_index_is_clust(index)) {
+ dict_stats_empty_index(index);
+#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
+ } else {
mtr_t mtr;
ulint size;
mtr_start(&mtr);
@@ -812,14 +823,6 @@ dict_stats_update_transient_for_index(
index->stat_n_leaf_pages = size;
btr_estimate_number_of_different_key_vals(index);
- } else {
- /* If we have set a high innodb_force_recovery
- level, do not calculate statistics, as a badly
- corrupted index can cause a crash in it.
- Initialize some bogus index cardinality
- statistics, so that the data can be queried in
- various means, also via secondary indexes. */
- dict_stats_empty_index(index);
}
}
diff --git a/storage/innobase/fts/fts0config.cc b/storage/innobase/fts/fts0config.cc
index 29d6771f9e7..c5cf38ca7f9 100644
--- a/storage/innobase/fts/fts0config.cc
+++ b/storage/innobase/fts/fts0config.cc
@@ -105,7 +105,7 @@ fts_config_get_value(
fts_table,
info,
"DECLARE FUNCTION my_func;\n"
- "DECLARE CURSOR c IS SELECT value FROM %s"
+ "DECLARE CURSOR c IS SELECT value FROM \"%s\""
" WHERE key = :name;\n"
"BEGIN\n"
""
@@ -481,7 +481,7 @@ fts_config_increment_value(
graph = fts_parse_sql(
fts_table, info,
"DECLARE FUNCTION my_func;\n"
- "DECLARE CURSOR c IS SELECT value FROM %s"
+ "DECLARE CURSOR c IS SELECT value FROM \"%s\""
" WHERE key = :name FOR UPDATE;\n"
"BEGIN\n"
""
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 9b06497c8ae..41f20c1dbb9 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -92,6 +92,7 @@ UNIV_INTERN mysql_pfs_key_t fts_delete_mutex_key;
UNIV_INTERN mysql_pfs_key_t fts_optimize_mutex_key;
UNIV_INTERN mysql_pfs_key_t fts_bg_threads_mutex_key;
UNIV_INTERN mysql_pfs_key_t fts_doc_id_mutex_key;
+UNIV_INTERN mysql_pfs_key_t fts_pll_tokenize_mutex_key;
#endif /* UNIV_PFS_MUTEX */
/** variable to record innodb_fts_internal_tbl_name for information
@@ -876,7 +877,7 @@ fts_drop_index(
current_doc_id = table->fts->cache->next_doc_id;
first_doc_id = table->fts->cache->first_doc_id;
- fts_cache_clear(table->fts->cache, TRUE);
+ fts_cache_clear(table->fts->cache);
fts_cache_destroy(table->fts->cache);
table->fts->cache = fts_cache_create(table);
table->fts->cache->next_doc_id = current_doc_id;
@@ -1079,16 +1080,12 @@ fts_words_free(
}
/*********************************************************************//**
-Clear cache. If the shutdown flag is TRUE then the cache can contain
-data that needs to be freed. For regular clear as part of normal
-working we assume the caller has freed all resources. */
+Clear cache. */
UNIV_INTERN
void
fts_cache_clear(
/*============*/
- fts_cache_t* cache, /*!< in: cache */
- ibool free_words) /*!< in: TRUE if free in memory
- word cache. */
+ fts_cache_t* cache) /*!< in: cache */
{
ulint i;
@@ -1099,11 +1096,7 @@ fts_cache_clear(
index_cache = static_cast<fts_index_cache_t*>(
ib_vector_get(cache->indexes, i));
- if (free_words) {
- fts_words_free(index_cache->words);
- }
-
- ut_a(rbt_empty(index_cache->words));
+ fts_words_free(index_cache->words);
rbt_free(index_cache->words);
@@ -2322,7 +2315,7 @@ fts_trx_table_clone(
ftt->rows = rbt_create(sizeof(fts_trx_row_t), fts_trx_row_doc_id_cmp);
/* Copy the rb tree values to the new savepoint. */
- rbt_merge_uniq(ftt_src->rows, ftt->rows);
+ rbt_merge_uniq(ftt->rows, ftt_src->rows);
/* These are only added on commit. At this stage we only have
the updated row state. */
@@ -2814,7 +2807,7 @@ fts_update_sync_doc_id(
graph = fts_parse_sql(
&fts_table, info,
"BEGIN "
- "UPDATE %s SET value = :doc_id"
+ "UPDATE \"%s\" SET value = :doc_id"
" WHERE key = 'synced_doc_id';");
error = fts_eval_sql(trx, graph);
@@ -4221,7 +4214,7 @@ fts_is_word_in_index(
"DECLARE FUNCTION my_func;\n"
"DECLARE CURSOR c IS"
" SELECT doc_count\n"
- " FROM %s\n"
+ " FROM \"%s\"\n"
" WHERE word = :word "
" ORDER BY first_doc_id;\n"
"BEGIN\n"
@@ -4363,10 +4356,8 @@ fts_sync_commit(
}
/* We need to do this within the deleted lock since fts_delete() can
- attempt to add a deleted doc id to the cache deleted id array. Set
- the shutdown flag to FALSE, signifying that we don't want to release
- all resources. */
- fts_cache_clear(cache, FALSE);
+ attempt to add a deleted doc id to the cache deleted id array. */
+ fts_cache_clear(cache);
fts_cache_init(cache);
rw_lock_x_unlock(&cache->lock);
@@ -4438,6 +4429,10 @@ fts_sync(
index_cache = static_cast<fts_index_cache_t*>(
ib_vector_get(cache->indexes, i));
+ if (index_cache->index->to_be_dropped) {
+ continue;
+ }
+
error = fts_sync_index(sync, index_cache);
if (error != DB_SUCCESS && !sync->interrupted) {
@@ -4447,7 +4442,8 @@ fts_sync(
}
DBUG_EXECUTE_IF("fts_instrument_sync_interrupted",
- sync->interrupted = true;
+ sync->interrupted = true;
+ error = DB_INTERRUPTED;
);
if (error == DB_SUCCESS && !sync->interrupted) {
@@ -4474,16 +4470,20 @@ fts_sync(
Run SYNC on the table, i.e., write out data from the cache to the
FTS auxiliary INDEX table and clear the cache at the end. */
UNIV_INTERN
-void
+dberr_t
fts_sync_table(
/*===========*/
dict_table_t* table) /*!< in: table */
{
+ dberr_t err = DB_SUCCESS;
+
ut_ad(table->fts);
if (table->fts->cache) {
- fts_sync(table->fts->cache->sync);
+ err = fts_sync(table->fts->cache->sync);
}
+
+ return(err);
}
/********************************************************************
@@ -5367,7 +5367,7 @@ fts_free(
ut_ad(!fts->add_wq);
if (fts->cache) {
- fts_cache_clear(fts->cache, TRUE);
+ fts_cache_clear(fts->cache);
fts_cache_destroy(fts->cache);
fts->cache = NULL;
}
@@ -5546,9 +5546,21 @@ fts_savepoint_release(
/* Only if we found and element to release. */
if (i < ib_vector_size(savepoints)) {
+ fts_savepoint_t* last_savepoint;
+ fts_savepoint_t* top_savepoint;
+ ib_rbt_t* tables;
ut_a(top_of_stack < ib_vector_size(savepoints));
+ /* Exchange tables between last savepoint and top savepoint */
+ last_savepoint = static_cast<fts_savepoint_t*>(
+ ib_vector_last(trx->fts_trx->savepoints));
+ top_savepoint = static_cast<fts_savepoint_t*>(
+ ib_vector_get(savepoints, top_of_stack));
+ tables = top_savepoint->tables;
+ top_savepoint->tables = last_savepoint->tables;
+ last_savepoint->tables = tables;
+
/* Skip the implied savepoint. */
for (i = ib_vector_size(savepoints) - 1;
i > top_of_stack;
@@ -5759,6 +5771,9 @@ fts_savepoint_rollback(
/* Make sure we don't delete the implied savepoint. */
ut_a(ib_vector_size(savepoints) > 0);
+
+ /* Restore the savepoint. */
+ fts_savepoint_take(trx, name);
}
}
diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc
index 0fd577c5767..7cdad522564 100644
--- a/storage/innobase/fts/fts0opt.cc
+++ b/storage/innobase/fts/fts0opt.cc
@@ -54,6 +54,9 @@ static const ulint FTS_OPTIMIZE_INTERVAL_IN_SECS = 300;
/** Server is shutting down, so does we exiting the optimize thread */
static bool fts_opt_start_shutdown = false;
+/** Initial size of nodes in fts_word_t. */
+static const ulint FTS_WORD_NODES_INIT_SIZE = 64;
+
/** Last time we did check whether system need a sync */
static ib_time_t last_check_sync_time;
@@ -244,10 +247,10 @@ static ib_time_t fts_optimize_time_limit = 0;
static const char* fts_init_delete_sql =
"BEGIN\n"
"\n"
- "INSERT INTO %s_BEING_DELETED\n"
+ "INSERT INTO \"%s_BEING_DELETED\"\n"
"SELECT doc_id FROM \"%s_DELETED\";\n"
"\n"
- "INSERT INTO %s_BEING_DELETED_CACHE\n"
+ "INSERT INTO \"%s_BEING_DELETED_CACHE\"\n"
"SELECT doc_id FROM \"%s_DELETED_CACHE\";\n";
static const char* fts_delete_doc_ids_sql =
@@ -357,7 +360,7 @@ fts_word_init(
word->heap_alloc = ib_heap_allocator_create(heap);
word->nodes = ib_vector_create(
- word->heap_alloc, sizeof(fts_node_t), 64);
+ word->heap_alloc, sizeof(fts_node_t), FTS_WORD_NODES_INIT_SIZE);
return(word);
}
@@ -435,6 +438,8 @@ fts_optimize_index_fetch_node(
dfield_t* dfield = que_node_get_val(exp);
void* data = dfield_get_data(dfield);
ulint dfield_len = dfield_get_len(dfield);
+ fts_node_t* node;
+ bool is_word_init = false;
ut_a(dfield_len <= FTS_MAX_WORD_LEN);
@@ -442,6 +447,7 @@ fts_optimize_index_fetch_node(
word = static_cast<fts_word_t*>(ib_vector_push(words, NULL));
fts_word_init(word, (byte*) data, dfield_len);
+ is_word_init = true;
}
word = static_cast<fts_word_t*>(ib_vector_last(words));
@@ -451,9 +457,23 @@ fts_optimize_index_fetch_node(
word = static_cast<fts_word_t*>(ib_vector_push(words, NULL));
fts_word_init(word, (byte*) data, dfield_len);
+ is_word_init = true;
}
- fts_optimize_read_node(word, que_node_get_next(exp));
+ node = fts_optimize_read_node(word, que_node_get_next(exp));
+
+ fetch->total_memory += node->ilist_size;
+ if (is_word_init) {
+ fetch->total_memory += sizeof(fts_word_t)
+ + sizeof(ib_alloc_t) + sizeof(ib_vector_t) + dfield_len
+ + sizeof(fts_node_t) * FTS_WORD_NODES_INIT_SIZE;
+ } else if (ib_vector_size(words) > FTS_WORD_NODES_INIT_SIZE) {
+ fetch->total_memory += sizeof(fts_node_t);
+ }
+
+ if (fetch->total_memory >= fts_result_cache_limit) {
+ return(FALSE);
+ }
return(TRUE);
}
@@ -1791,9 +1811,11 @@ fts_optimize_words(
selected = fts_select_index(charset, word->f_str, word->f_len);
/* Read the index records to optimize. */
+ fetch.total_memory = 0;
error = fts_index_fetch_nodes(
trx, &graph, &optim->fts_index_table, word,
&fetch);
+ ut_ad(fetch.total_memory < fts_result_cache_limit);
if (error == DB_SUCCESS) {
/* There must be some nodes to read. */
diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc
index 72901d193eb..a70c742da0c 100644
--- a/storage/innobase/fts/fts0que.cc
+++ b/storage/innobase/fts/fts0que.cc
@@ -784,7 +784,7 @@ fts_query_remove_doc_id(
&& rbt_search(query->doc_ids, &parent, &doc_id) == 0) {
ut_free(rbt_remove_node(query->doc_ids, parent.last));
- ut_ad(query->total_size >
+ ut_ad(query->total_size >=
SIZEOF_RBT_NODE_ADD + sizeof(fts_ranking_t));
query->total_size -= SIZEOF_RBT_NODE_ADD
+ sizeof(fts_ranking_t);
@@ -935,7 +935,7 @@ fts_query_free_doc_ids(
ut_free(rbt_remove_node(doc_ids, node));
- ut_ad(query->total_size >
+ ut_ad(query->total_size >=
SIZEOF_RBT_NODE_ADD + sizeof(fts_ranking_t));
query->total_size -= SIZEOF_RBT_NODE_ADD
+ sizeof(fts_ranking_t);
@@ -943,7 +943,7 @@ fts_query_free_doc_ids(
rbt_free(doc_ids);
- ut_ad(query->total_size > SIZEOF_RBT_CREATE);
+ ut_ad(query->total_size >= SIZEOF_RBT_CREATE);
query->total_size -= SIZEOF_RBT_CREATE;
}
@@ -2056,7 +2056,7 @@ fts_query_find_term(
"DECLARE FUNCTION my_func;\n"
"DECLARE CURSOR c IS"
" SELECT doc_count, ilist\n"
- " FROM %s\n"
+ " FROM \"%s\"\n"
" WHERE word LIKE :word AND "
" first_doc_id <= :min_doc_id AND "
" last_doc_id >= :max_doc_id\n"
@@ -2255,7 +2255,7 @@ fts_query_terms_in_document(
"DECLARE FUNCTION my_func;\n"
"DECLARE CURSOR c IS"
" SELECT count\n"
- " FROM %s\n"
+ " FROM \"%s\"\n"
" WHERE doc_id = :doc_id "
"BEGIN\n"
"\n"
@@ -3747,9 +3747,10 @@ fts_query_str_preprocess(
charset, str_ptr + cur_pos, str_ptr + *result_len,
&str, &offset);
- if (cur_len == 0) {
- break;
- }
+ if (cur_len == 0 || str.f_str == NULL) {
+ /* No valid word found */
+ break;
+ }
/* Check if we are in a phrase, if so, no need to do
replacement of '-/+'. */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 7febafb2324..fb481a17d55 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -41,6 +41,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include <mysys_err.h>
#include <innodb_priv.h>
#include <table_cache.h>
+#include <my_check_opt.h>
#ifdef _WIN32
#include <io.h>
@@ -201,8 +202,6 @@ static char* internal_innobase_data_file_path = NULL;
static char* innodb_version_str = (char*) INNODB_VERSION_STR;
-static char* fts_server_stopword_table = NULL;
-
/** Possible values for system variable "innodb_stats_method". The values
are defined the same as its corresponding MyISAM system variable
"myisam_stats_method"(see "myisam_stats_method_names"), for better usability */
@@ -313,6 +312,7 @@ static PSI_mutex_info all_innodb_mutexes[] = {
{&fts_delete_mutex_key, "fts_delete_mutex", 0},
{&fts_optimize_mutex_key, "fts_optimize_mutex", 0},
{&fts_doc_id_mutex_key, "fts_doc_id_mutex", 0},
+ {&fts_pll_tokenize_mutex_key, "fts_pll_tokenize_mutex", 0},
{&log_flush_order_mutex_key, "log_flush_order_mutex", 0},
{&hash_table_mutex_key, "hash_table_mutex", 0},
{&ibuf_bitmap_mutex_key, "ibuf_bitmap_mutex", 0},
@@ -495,7 +495,8 @@ ib_cb_t innodb_api_cb[] = {
(ib_cb_t) ib_cursor_clear_trx,
(ib_cb_t) ib_get_idx_field_name,
(ib_cb_t) ib_trx_get_start_time,
- (ib_cb_t) ib_cfg_bk_commit_interval
+ (ib_cb_t) ib_cfg_bk_commit_interval,
+ (ib_cb_t) ib_cursor_stmt_begin
};
/*************************************************************//**
@@ -1470,6 +1471,13 @@ convert_error_code_to_mysql(
case DB_OUT_OF_FILE_SPACE:
return(HA_ERR_RECORD_FILE_FULL);
+ case DB_TEMP_FILE_WRITE_FAILURE:
+ my_error(ER_GET_ERRMSG, MYF(0),
+ DB_TEMP_FILE_WRITE_FAILURE,
+ ut_strerr(DB_TEMP_FILE_WRITE_FAILURE),
+ "InnoDB");
+ return(HA_ERR_INTERNAL_ERROR);
+
case DB_TABLE_IN_FK_CHECK:
return(HA_ERR_TABLE_IN_FK_CHECK);
@@ -3056,12 +3064,6 @@ mem_free_and_error:
goto mem_free_and_error;
}
- /* Remember stopword table name supplied at startup */
- if (innobase_server_stopword_table) {
- fts_server_stopword_table =
- my_strdup(innobase_server_stopword_table, MYF(0));
- }
-
if (innobase_change_buffering) {
ulint use;
@@ -3434,9 +3436,6 @@ innobase_end(
mysql_mutex_destroy(&pending_checkpoint_mutex);
}
- my_free(fts_server_stopword_table);
- fts_server_stopword_table= NULL;
-
DBUG_RETURN(err);
}
@@ -5760,6 +5759,7 @@ innobase_mysql_fts_get_token(
ut_a(cs);
token->f_n_char = token->f_len = 0;
+ token->f_str = NULL;
for (;;) {
@@ -8373,7 +8373,7 @@ ha_innobase::ft_init_ext(
String* key) /* in: */
{
trx_t* trx;
- dict_table_t* table;
+ dict_table_t* ft_table;
dberr_t error;
byte* query = (byte*) key->ptr();
ulint query_len = key->length();
@@ -8423,17 +8423,24 @@ ha_innobase::ft_init_ext(
++trx->will_lock;
}
- table = prebuilt->table;
+ ft_table = prebuilt->table;
/* Table does not have an FTS index */
- if (!table->fts || ib_vector_is_empty(table->fts->indexes)) {
+ if (!ft_table->fts || ib_vector_is_empty(ft_table->fts->indexes)) {
my_error(ER_TABLE_HAS_NO_FT, MYF(0));
return(NULL);
}
+ /* If tablespace is discarded, we should return here */
+ if (dict_table_is_discarded(ft_table)) {
+ my_error(ER_NO_SUCH_TABLE, MYF(0), table->s->db.str,
+ table->s->table_name.str);
+ return(NULL);
+ }
+
if (keynr == NO_SUCH_KEY) {
/* FIXME: Investigate the NO_SUCH_KEY usage */
- index = (dict_index_t*) ib_vector_getp(table->fts->indexes, 0);
+ index = (dict_index_t*) ib_vector_getp(ft_table->fts->indexes, 0);
} else {
index = innobase_get_index(keynr);
}
@@ -8443,10 +8450,10 @@ ha_innobase::ft_init_ext(
return(NULL);
}
- if (!(table->fts->fts_status & ADDED_TABLE_SYNCED)) {
- fts_init_index(table, FALSE);
+ if (!(ft_table->fts->fts_status & ADDED_TABLE_SYNCED)) {
+ fts_init_index(ft_table, FALSE);
- table->fts->fts_status |= ADDED_TABLE_SYNCED;
+ ft_table->fts->fts_status |= ADDED_TABLE_SYNCED;
}
error = fts_query(trx, index, flags, query, query_len, &result);
@@ -9428,7 +9435,7 @@ innobase_fts_load_stopword(
THD* thd) /*!< in: current thread */
{
return(fts_load_stopword(table, trx,
- fts_server_stopword_table,
+ innobase_server_stopword_table,
THDVAR(thd, ft_user_stopword_table),
THDVAR(thd, ft_enable_stopword), FALSE));
}
@@ -10703,6 +10710,10 @@ ha_innobase::records_in_range(
/* There exists possibility of not being able to find requested
index due to inconsistency between MySQL and InoDB dictionary info.
Necessary message should have been printed in innobase_get_index() */
+ if (dict_table_is_discarded(prebuilt->table)) {
+ n_rows = HA_POS_ERROR;
+ goto func_exit;
+ }
if (UNIV_UNLIKELY(!index)) {
n_rows = HA_POS_ERROR;
goto func_exit;
@@ -11538,13 +11549,12 @@ int
ha_innobase::check(
/*===============*/
THD* thd, /*!< in: user thread handle */
- HA_CHECK_OPT* check_opt) /*!< in: check options, currently
- ignored */
+ HA_CHECK_OPT* check_opt) /*!< in: check options */
{
dict_index_t* index;
ulint n_rows;
ulint n_rows_in_table = ULINT_UNDEFINED;
- ibool is_ok = TRUE;
+ bool is_ok = true;
ulint old_isolation_level;
ibool table_corrupted;
@@ -11600,35 +11610,49 @@ ha_innobase::check(
do additional check */
prebuilt->table->corrupted = FALSE;
- /* Enlarge the fatal lock wait timeout during CHECK TABLE. */
- os_increment_counter_by_amount(
- server_mutex,
- srv_fatal_semaphore_wait_threshold,
- SRV_SEMAPHORE_WAIT_EXTENSION);
-
for (index = dict_table_get_first_index(prebuilt->table);
index != NULL;
index = dict_table_get_next_index(index)) {
char index_name[MAX_FULL_NAME_LEN + 1];
- /* If this is an index being created or dropped, break */
+ /* If this is an index being created or dropped, skip */
if (*index->name == TEMP_INDEX_PREFIX) {
- break;
- } else if (!btr_validate_index(index, prebuilt->trx)) {
- is_ok = FALSE;
-
- innobase_format_name(
- index_name, sizeof index_name,
- index->name, TRUE);
-
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_NOT_KEYFILE,
- "InnoDB: The B-tree of"
- " index %s is corrupted.",
- index_name);
continue;
}
+ if (!(check_opt->flags & T_QUICK)) {
+ /* Enlarge the fatal lock wait timeout during
+ CHECK TABLE. */
+ os_increment_counter_by_amount(
+ server_mutex,
+ srv_fatal_semaphore_wait_threshold,
+ SRV_SEMAPHORE_WAIT_EXTENSION);
+ bool valid = btr_validate_index(index, prebuilt->trx);
+
+ /* Restore the fatal lock wait timeout after
+ CHECK TABLE. */
+ os_decrement_counter_by_amount(
+ server_mutex,
+ srv_fatal_semaphore_wait_threshold,
+ SRV_SEMAPHORE_WAIT_EXTENSION);
+
+ if (!valid) {
+ is_ok = false;
+
+ innobase_format_name(
+ index_name, sizeof index_name,
+ index->name, TRUE);
+ push_warning_printf(
+ thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ ER_NOT_KEYFILE,
+ "InnoDB: The B-tree of"
+ " index %s is corrupted.",
+ index_name);
+ continue;
+ }
+ }
+
/* Instead of invoking change_active_index(), set up
a dummy template for non-locking reads, disabling
access to the clustered index. */
@@ -11650,7 +11674,7 @@ ha_innobase::check(
"InnoDB: Index %s is marked as"
" corrupted",
index_name);
- is_ok = FALSE;
+ is_ok = false;
} else {
push_warning_printf(
thd,
@@ -11683,7 +11707,7 @@ ha_innobase::check(
"InnoDB: The B-tree of"
" index %s is corrupted.",
index_name);
- is_ok = FALSE;
+ is_ok = false;
dict_set_corrupted(
index, prebuilt->trx, "CHECK TABLE-check index");
}
@@ -11709,7 +11733,7 @@ ha_innobase::check(
index->name,
(ulong) n_rows,
(ulong) n_rows_in_table);
- is_ok = FALSE;
+ is_ok = false;
dict_set_corrupted(
index, prebuilt->trx,
"CHECK TABLE; Wrong count");
@@ -11732,21 +11756,17 @@ ha_innobase::check(
/* Restore the original isolation level */
prebuilt->trx->isolation_level = old_isolation_level;
- /* We validate also the whole adaptive hash index for all tables
- at every CHECK TABLE */
+ /* We validate the whole adaptive hash index for all tables
+ at every CHECK TABLE only when QUICK flag is not present. */
- if (!btr_search_validate()) {
+#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
+ if (!(check_opt->flags & T_QUICK) && !btr_search_validate()) {
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_NOT_KEYFILE,
"InnoDB: The adaptive hash index is corrupted.");
- is_ok = FALSE;
+ is_ok = false;
}
-
- /* Restore the fatal lock wait timeout after CHECK TABLE. */
- os_decrement_counter_by_amount(
- server_mutex,
- srv_fatal_semaphore_wait_threshold,
- SRV_SEMAPHORE_WAIT_EXTENSION);
+#endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
prebuilt->trx->op_info = "";
if (thd_kill_level(user_thd)) {
@@ -12709,7 +12729,7 @@ innodb_show_status(
const long MAX_STATUS_SIZE = 1048576;
ulint trx_list_start = ULINT_UNDEFINED;
ulint trx_list_end = ULINT_UNDEFINED;
- bool res;
+ bool ret_val;
DBUG_ENTER("innodb_show_status");
DBUG_ASSERT(hton == innodb_hton_ptr);
@@ -12786,13 +12806,13 @@ innodb_show_status(
mutex_exit(&srv_monitor_file_mutex);
- res= stat_print(thd, innobase_hton_name,
- (uint) strlen(innobase_hton_name),
- STRING_WITH_LEN(""), str, flen);
+ ret_val= stat_print(thd, innobase_hton_name,
+ (uint) strlen(innobase_hton_name),
+ STRING_WITH_LEN(""), str, flen);
my_free(str);
- DBUG_RETURN(res);
+ DBUG_RETURN(ret_val);
}
/************************************************************************//**
@@ -14470,44 +14490,6 @@ innodb_stopword_table_validate(
return(ret);
}
-/****************************************************************//**
-Update global variable fts_server_stopword_table with the "saved"
-stopword table name value. This function is registered as a callback
-with MySQL. */
-static
-void
-innodb_stopword_table_update(
-/*=========================*/
- THD* thd, /*!< in: thread handle */
- struct st_mysql_sys_var* var, /*!< in: pointer to
- system variable */
- void* var_ptr,/*!< out: where the
- formal string goes */
- const void* save) /*!< in: immediate result
- from check function */
-{
- const char* stopword_table_name;
- char* old;
-
- ut_a(save != NULL);
- ut_a(var_ptr != NULL);
-
- stopword_table_name = *static_cast<const char*const*>(save);
- old = *(char**) var_ptr;
-
- if (stopword_table_name) {
- *(char**) var_ptr = my_strdup(stopword_table_name, MYF(0));
- } else {
- *(char**) var_ptr = NULL;
- }
-
- if (old) {
- my_free(old);
- }
-
- fts_server_stopword_table = *(char**) var_ptr;
-}
-
/*************************************************************//**
Check whether valid argument given to "innodb_fts_internal_tbl_name"
This function is registered as a callback with MySQL.
@@ -15963,10 +15945,10 @@ static MYSQL_SYSVAR_STR(file_format_max, innobase_file_format_max,
innodb_file_format_max_update, "Antelope");
static MYSQL_SYSVAR_STR(ft_server_stopword_table, innobase_server_stopword_table,
- PLUGIN_VAR_OPCMDARG,
+ PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_MEMALLOC,
"The user supplied stopword table name.",
innodb_stopword_table_validate,
- innodb_stopword_table_update,
+ NULL,
NULL);
static MYSQL_SYSVAR_UINT(flush_log_at_timeout, srv_flush_log_at_timeout,
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 8cfd6928376..d7e16d93c6a 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -126,6 +126,12 @@ my_error_innodb(
case DB_OUT_OF_FILE_SPACE:
my_error(ER_RECORD_FILE_FULL, MYF(0), table);
break;
+ case DB_TEMP_FILE_WRITE_FAILURE:
+ my_error(ER_GET_ERRMSG, MYF(0),
+ DB_TEMP_FILE_WRITE_FAILURE,
+ ut_strerr(DB_TEMP_FILE_WRITE_FAILURE),
+ "InnoDB");
+ break;
case DB_TOO_BIG_INDEX_COL:
my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0),
DICT_MAX_FIELD_LEN_BY_FORMAT_FLAG(flags));
@@ -3962,7 +3968,8 @@ oom:
DEBUG_SYNC_C("inplace_after_index_build");
DBUG_EXECUTE_IF("create_index_fail",
- error = DB_DUPLICATE_KEY;);
+ error = DB_DUPLICATE_KEY;
+ prebuilt->trx->error_key_num = ULINT_UNDEFINED;);
/* After an error, remove all those index definitions
from the dictionary which were defined. */
@@ -5722,6 +5729,9 @@ foreign_fail:
if (index->type & DICT_FTS) {
DBUG_ASSERT(index->type == DICT_FTS);
+ /* We reset DICT_TF2_FTS here because the bit
+ is left unset when a drop proceeds the add. */
+ DICT_TF2_FLAG_SET(ctx->new_table, DICT_TF2_FTS);
fts_add_index(index, ctx->new_table);
add_fts = true;
}
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index cafa745129b..bd999177806 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -3231,12 +3231,22 @@ i_s_fts_index_cache_fill_one_index(
{
TABLE* table = (TABLE*) tables->table;
Field** fields;
+ CHARSET_INFO* index_charset;
const ib_rbt_node_t* rbt_node;
+ fts_string_t conv_str;
+ uint dummy_errors;
+ char* word_str;
DBUG_ENTER("i_s_fts_index_cache_fill_one_index");
fields = table->field;
+ index_charset = index_cache->charset;
+ conv_str.f_len = system_charset_info->mbmaxlen
+ * FTS_MAX_WORD_LEN_IN_CHAR;
+ conv_str.f_str = static_cast<byte*>(ut_malloc(conv_str.f_len));
+ conv_str.f_n_char = 0;
+
/* Go through each word in the index cache */
for (rbt_node = rbt_first(index_cache->words);
rbt_node;
@@ -3247,6 +3257,20 @@ i_s_fts_index_cache_fill_one_index(
word = rbt_value(fts_tokenizer_word_t, rbt_node);
+ /* Convert word from index charset to system_charset_info */
+ if (index_charset->cset != system_charset_info->cset) {
+ conv_str.f_n_char = my_convert(
+ reinterpret_cast<char*>(conv_str.f_str),
+ conv_str.f_len, system_charset_info,
+ reinterpret_cast<char*>(word->text.f_str),
+ word->text.f_len, index_charset, &dummy_errors);
+ ut_ad(conv_str.f_n_char <= conv_str.f_len);
+ conv_str.f_str[conv_str.f_n_char] = 0;
+ word_str = reinterpret_cast<char*>(conv_str.f_str);
+ } else {
+ word_str = reinterpret_cast<char*>(word->text.f_str);
+ }
+
/* Decrypt the ilist, and display Dod ID and word position */
for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
fts_node_t* node;
@@ -3269,8 +3293,7 @@ i_s_fts_index_cache_fill_one_index(
OK(field_store_string(
fields[I_S_FTS_WORD],
- reinterpret_cast<const char*>
- (word->text.f_str)));
+ word_str));
OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
(longlong) node->first_doc_id,
@@ -3300,6 +3323,8 @@ i_s_fts_index_cache_fill_one_index(
}
}
+ ut_free(conv_str.f_str);
+
DBUG_RETURN(0);
}
/*******************************************************************//**
@@ -3424,31 +3449,38 @@ Go through a FTS index auxiliary table, fetch its rows and fill
FTS word cache structure.
@return DB_SUCCESS on success, otherwise error code */
static
-ulint
+dberr_t
i_s_fts_index_table_fill_selected(
/*==============================*/
dict_index_t* index, /*!< in: FTS index */
ib_vector_t* words, /*!< in/out: vector to hold
fetched words */
- ulint selected) /*!< in: selected FTS index */
+ ulint selected, /*!< in: selected FTS index */
+ fts_string_t* word) /*!< in: word to select */
{
pars_info_t* info;
fts_table_t fts_table;
trx_t* trx;
que_t* graph;
- ulint error;
+ dberr_t error;
fts_fetch_t fetch;
info = pars_info_create();
fetch.read_arg = words;
fetch.read_record = fts_optimize_index_fetch_node;
+ fetch.total_memory = 0;
+
+ DBUG_EXECUTE_IF("fts_instrument_result_cache_limit",
+ fts_result_cache_limit = 8192;
+ );
trx = trx_allocate_for_background();
trx->op_info = "fetching FTS index nodes";
pars_info_bind_function(info, "my_func", fetch.read_record, &fetch);
+ pars_info_bind_varchar_literal(info, "word", word->f_str, word->f_len);
FTS_INIT_INDEX_TABLE(&fts_table, fts_get_suffix(selected),
FTS_INDEX_TABLE, index);
@@ -3459,7 +3491,7 @@ i_s_fts_index_table_fill_selected(
"DECLARE CURSOR c IS"
" SELECT word, doc_count, first_doc_id, last_doc_id, "
"ilist\n"
- " FROM %s;\n"
+ " FROM %s WHERE word >= :word;\n"
"BEGIN\n"
"\n"
"OPEN c;\n"
@@ -3490,7 +3522,7 @@ i_s_fts_index_table_fill_selected(
trx->error_state = DB_SUCCESS;
} else {
- fprintf(stderr, " InnoDB: Error: %lu "
+ fprintf(stderr, " InnoDB: Error: %d "
"while reading FTS index.\n", error);
break;
}
@@ -3503,54 +3535,94 @@ i_s_fts_index_table_fill_selected(
trx_free_for_background(trx);
+ if (fetch.total_memory >= fts_result_cache_limit) {
+ error = DB_FTS_EXCEED_RESULT_CACHE_LIMIT;
+ }
+
return(error);
}
/*******************************************************************//**
-Go through a FTS index and its auxiliary tables, fetch rows in each table
-and fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
+Free words. */
+static
+void
+i_s_fts_index_table_free_one_fetch(
+/*===============================*/
+ ib_vector_t* words) /*!< in: words fetched */
+{
+ for (ulint i = 0; i < ib_vector_size(words); i++) {
+ fts_word_t* word;
+
+ word = static_cast<fts_word_t*>(ib_vector_get(words, i));
+
+ for (ulint j = 0; j < ib_vector_size(word->nodes); j++) {
+ fts_node_t* node;
+
+ node = static_cast<fts_node_t*> (ib_vector_get(
+ word->nodes, j));
+ ut_free(node->ilist);
+ }
+
+ fts_word_free(word);
+ }
+
+ ib_vector_reset(words);
+}
+
+/*******************************************************************//**
+Go through words, fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
@return 0 on success, 1 on failure */
static
int
-i_s_fts_index_table_fill_one_index(
+i_s_fts_index_table_fill_one_fetch(
/*===============================*/
- dict_index_t* index, /*!< in: FTS index */
+ CHARSET_INFO* index_charset, /*!< in: FTS index charset */
THD* thd, /*!< in: thread */
- TABLE_LIST* tables) /*!< in/out: tables to fill */
+ TABLE_LIST* tables, /*!< in/out: tables to fill */
+ ib_vector_t* words, /*!< in: words fetched */
+ fts_string_t* conv_str, /*!< in: string for conversion*/
+ bool has_more) /*!< in: has more to fetch */
{
TABLE* table = (TABLE*) tables->table;
Field** fields;
- ib_vector_t* words;
- mem_heap_t* heap;
- ulint num_row_fill;
-
- DBUG_ENTER("i_s_fts_index_cache_fill_one_index");
- DBUG_ASSERT(!dict_index_is_online_ddl(index));
+ uint dummy_errors;
+ char* word_str;
+ ulint words_size;
+ int ret = 0;
- heap = mem_heap_create(1024);
-
- words = ib_vector_create(ib_heap_allocator_create(heap),
- sizeof(fts_word_t), 256);
+ DBUG_ENTER("i_s_fts_index_table_fill_one_fetch");
fields = table->field;
- /* Iterate through each auxiliary table as described in
- fts_index_selector */
- for (ulint selected = 0; fts_index_selector[selected].value;
- selected++) {
- i_s_fts_index_table_fill_selected(index, words, selected);
+ words_size = ib_vector_size(words);
+ if (has_more) {
+ /* the last word is not fetched completely. */
+ ut_ad(words_size > 1);
+ words_size -= 1;
}
- num_row_fill = ut_min(ib_vector_size(words), 500000);
-
/* Go through each word in the index cache */
- for (ulint i = 0; i < num_row_fill; i++) {
+ for (ulint i = 0; i < words_size; i++) {
fts_word_t* word;
- word = (fts_word_t*) ib_vector_get(words, i);
+ word = static_cast<fts_word_t*>(ib_vector_get(words, i));
word->text.f_str[word->text.f_len] = 0;
+ /* Convert word from index charset to system_charset_info */
+ if (index_charset->cset != system_charset_info->cset) {
+ conv_str->f_n_char = my_convert(
+ reinterpret_cast<char*>(conv_str->f_str),
+ conv_str->f_len, system_charset_info,
+ reinterpret_cast<char*>(word->text.f_str),
+ word->text.f_len, index_charset, &dummy_errors);
+ ut_ad(conv_str->f_n_char <= conv_str->f_len);
+ conv_str->f_str[conv_str->f_n_char] = 0;
+ word_str = reinterpret_cast<char*>(conv_str->f_str);
+ } else {
+ word_str = reinterpret_cast<char*>(word->text.f_str);
+ }
+
/* Decrypt the ilist, and display Dod ID and word position */
for (ulint i = 0; i < ib_vector_size(word->nodes); i++) {
fts_node_t* node;
@@ -3574,8 +3646,7 @@ i_s_fts_index_table_fill_one_index(
OK(field_store_string(
fields[I_S_FTS_WORD],
- reinterpret_cast<const char*>
- (word->text.f_str)));
+ word_str));
OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
(longlong) node->first_doc_id,
@@ -3605,9 +3676,95 @@ i_s_fts_index_table_fill_one_index(
}
}
+ i_s_fts_index_table_free_one_fetch(words);
+
+ DBUG_RETURN(ret);
+}
+
+/*******************************************************************//**
+Go through a FTS index and its auxiliary tables, fetch rows in each table
+and fill INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE.
+@return 0 on success, 1 on failure */
+static
+int
+i_s_fts_index_table_fill_one_index(
+/*===============================*/
+ dict_index_t* index, /*!< in: FTS index */
+ THD* thd, /*!< in: thread */
+ TABLE_LIST* tables) /*!< in/out: tables to fill */
+{
+ ib_vector_t* words;
+ mem_heap_t* heap;
+ fts_string_t word;
+ CHARSET_INFO* index_charset;
+ fts_string_t conv_str;
+ dberr_t error;
+ int ret = 0;
+
+ DBUG_ENTER("i_s_fts_index_table_fill_one_index");
+ DBUG_ASSERT(!dict_index_is_online_ddl(index));
+
+ heap = mem_heap_create(1024);
+
+ words = ib_vector_create(ib_heap_allocator_create(heap),
+ sizeof(fts_word_t), 256);
+
+ word.f_str = NULL;
+ word.f_len = 0;
+ word.f_n_char = 0;
+
+ index_charset = fts_index_get_charset(index);
+ conv_str.f_len = system_charset_info->mbmaxlen
+ * FTS_MAX_WORD_LEN_IN_CHAR;
+ conv_str.f_str = static_cast<byte*>(ut_malloc(conv_str.f_len));
+ conv_str.f_n_char = 0;
+
+ /* Iterate through each auxiliary table as described in
+ fts_index_selector */
+ for (ulint selected = 0; fts_index_selector[selected].value;
+ selected++) {
+ bool has_more = false;
+
+ do {
+ /* Fetch from index */
+ error = i_s_fts_index_table_fill_selected(
+ index, words, selected, &word);
+
+ if (error == DB_SUCCESS) {
+ has_more = false;
+ } else if (error == DB_FTS_EXCEED_RESULT_CACHE_LIMIT) {
+ has_more = true;
+ } else {
+ i_s_fts_index_table_free_one_fetch(words);
+ ret = 1;
+ goto func_exit;
+ }
+
+ if (has_more) {
+ fts_word_t* last_word;
+
+ /* Prepare start point for next fetch */
+ last_word = static_cast<fts_word_t*>(ib_vector_last(words));
+ ut_ad(last_word != NULL);
+ fts_utf8_string_dup(&word, &last_word->text, heap);
+ }
+
+ /* Fill into tables */
+ ret = i_s_fts_index_table_fill_one_fetch(
+ index_charset, thd, tables, words, &conv_str, has_more);
+
+ if (ret != 0) {
+ i_s_fts_index_table_free_one_fetch(words);
+ goto func_exit;
+ }
+ } while (has_more);
+ }
+
+func_exit:
+ ut_free(conv_str.f_str);
mem_heap_free(heap);
- DBUG_RETURN(0);
+ DBUG_RETURN(ret);
}
/*******************************************************************//**
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index fd3b13d2cd3..1ce5332885a 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -2751,6 +2751,10 @@ ibuf_merge(
if (ibuf->empty && !srv_shutdown_state) {
return(0);
+#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
+ } else if (ibuf_debug) {
+ return(0);
+#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
} else if (table_id == 0) {
return(ibuf_merge_pages(n_pages, sync));
} else if ((table = ibuf_get_table(table_id)) == 0) {
@@ -4136,6 +4140,22 @@ dump:
rec = page_cur_get_rec(&page_cur);
row_upd_rec_in_place(rec, index, offsets,
update, page_zip);
+
+ /* Log the update in place operation. During recovery
+ MLOG_COMP_REC_UPDATE_IN_PLACE/MLOG_REC_UPDATE_IN_PLACE
+ expects trx_id, roll_ptr for secondary indexes. So we
+ just write dummy trx_id(0), roll_ptr(0) */
+ btr_cur_update_in_place_log(BTR_KEEP_SYS_FLAG, rec,
+ index, update, 0, 0, mtr);
+ DBUG_EXECUTE_IF(
+ "crash_after_log_ibuf_upd_inplace",
+ log_buffer_flush_to_disk();
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Wrote log record for ibuf update in "
+ "place operation");
+ DBUG_SUICIDE();
+ );
+
goto updated_in_place;
}
@@ -4389,14 +4409,6 @@ ibuf_restore_pos(
fflush(stderr);
ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
-
- fputs("InnoDB: Validating insert buffer tree:\n", stderr);
- if (!btr_validate_index(ibuf->index, 0)) {
- ut_error;
- }
-
- fprintf(stderr, "InnoDB: ibuf tree ok\n");
- fflush(stderr);
ut_ad(0);
}
diff --git a/storage/innobase/include/api0api.h b/storage/innobase/include/api0api.h
index 1d6aaab60bc..c294e3f34d5 100644
--- a/storage/innobase/include/api0api.h
+++ b/storage/innobase/include/api0api.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -460,6 +460,10 @@ ib_trx_start(
/*=========*/
ib_trx_t ib_trx, /*!< in: transaction to restart */
ib_trx_level_t ib_trx_level, /*!< in: trx isolation level */
+ ib_bool_t read_write, /*!< in: true if read write
+ transaction */
+ ib_bool_t auto_commit, /*!< in: auto commit after each
+ single DML */
void* thd); /*!< in: THD */
/*****************************************************************//**
@@ -470,7 +474,11 @@ put the transaction in the active state.
ib_trx_t
ib_trx_begin(
/*=========*/
- ib_trx_level_t ib_trx_level); /*!< in: trx isolation level */
+ ib_trx_level_t ib_trx_level, /*!< in: trx isolation level */
+ ib_bool_t read_write, /*!< in: true if read write
+ transaction */
+ ib_bool_t auto_commit); /*!< in: auto commit after each
+ single DML */
/*****************************************************************//**
Query the transaction's state. This function can be used to check for
@@ -669,7 +677,9 @@ ib_err_t
ib_cursor_read_row(
/*===============*/
ib_crsr_t ib_crsr, /*!< in: InnoDB cursor instance */
- ib_tpl_t ib_tpl); /*!< out: read cols into this tuple */
+ ib_tpl_t ib_tpl, /*!< out: read cols into this tuple */
+ void** row_buf, /*!< in/out: row buffer */
+ ib_ulint_t* row_len); /*!< in/out: row buffer len */
/*****************************************************************//**
Move cursor to the first record in the table.
diff --git a/storage/innobase/include/btr0cur.h b/storage/innobase/include/btr0cur.h
index e2bc599d598..833166e783c 100644
--- a/storage/innobase/include/btr0cur.h
+++ b/storage/innobase/include/btr0cur.h
@@ -326,6 +326,20 @@ btr_cur_update_in_place(
mtr_commit(mtr) before latching any
further pages */
__attribute__((warn_unused_result, nonnull));
+/***********************************************************//**
+Writes a redo log record of updating a record in-place. */
+UNIV_INTERN
+void
+btr_cur_update_in_place_log(
+/*========================*/
+ ulint flags, /*!< in: flags */
+ const rec_t* rec, /*!< in: record */
+ dict_index_t* index, /*!< in: index of the record */
+ const upd_t* update, /*!< in: update vector */
+ trx_id_t trx_id, /*!< in: transaction id */
+ roll_ptr_t roll_ptr, /*!< in: roll ptr */
+ mtr_t* mtr) /*!< in: mtr */
+ __attribute__((nonnull));
/*************************************************************//**
Tries to update a record on a page in an index tree. It is assumed that mtr
holds an x-latch on the page. The operation does not succeed if there is too
diff --git a/storage/innobase/include/btr0pcur.h b/storage/innobase/include/btr0pcur.h
index 973fae382ab..fc008cdd185 100644
--- a/storage/innobase/include/btr0pcur.h
+++ b/storage/innobase/include/btr0pcur.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -460,6 +460,27 @@ btr_pcur_move_to_prev_on_page(
/*==========================*/
btr_pcur_t* cursor);/*!< in/out: persistent cursor */
+/** Position state of persistent B-tree cursor. */
+enum pcur_pos_t {
+ /** The persistent cursor is not positioned. */
+ BTR_PCUR_NOT_POSITIONED = 0,
+ /** The persistent cursor was previously positioned.
+ TODO: currently, the state can be BTR_PCUR_IS_POSITIONED,
+ though it really should be BTR_PCUR_WAS_POSITIONED,
+ because we have no obligation to commit the cursor with
+ mtr; similarly latch_mode may be out of date. This can
+ lead to problems if btr_pcur is not used the right way;
+ all current code should be ok. */
+ BTR_PCUR_WAS_POSITIONED,
+ /** The persistent cursor is positioned by optimistic get to the same
+ record as it was positioned at. Not used for rel_pos == BTR_PCUR_ON.
+ It may need adjustment depending on previous/current search direction
+ and rel_pos. */
+ BTR_PCUR_IS_POSITIONED_OPTIMISTIC,
+ /** The persistent cursor is positioned by index search.
+ Or optimistic get for rel_pos == BTR_PCUR_ON. */
+ BTR_PCUR_IS_POSITIONED
+};
/* The persistent B-tree cursor structure. This is used mainly for SQL
selects, updates, and deletes. */
@@ -493,10 +514,8 @@ struct btr_pcur_t{
ib_uint64_t modify_clock; /*!< the modify clock value of the
buffer block when the cursor position
was stored */
- ulint pos_state; /*!< see TODO note below!
- BTR_PCUR_IS_POSITIONED,
- BTR_PCUR_WAS_POSITIONED,
- BTR_PCUR_NOT_POSITIONED */
+ enum pcur_pos_t pos_state; /*!< btr_pcur_store_position() and
+ btr_pcur_restore_position() state. */
ulint search_mode; /*!< PAGE_CUR_G, ... */
trx_t* trx_if_known; /*!< the transaction, if we know it;
otherwise this field is not defined;
@@ -512,21 +531,6 @@ struct btr_pcur_t{
is not NULL */
};
-#define BTR_PCUR_IS_POSITIONED 1997660512 /* TODO: currently, the state
- can be BTR_PCUR_IS_POSITIONED,
- though it really should be
- BTR_PCUR_WAS_POSITIONED,
- because we have no obligation
- to commit the cursor with
- mtr; similarly latch_mode may
- be out of date. This can
- lead to problems if btr_pcur
- is not used the right way;
- all current code should be
- ok. */
-#define BTR_PCUR_WAS_POSITIONED 1187549791
-#define BTR_PCUR_NOT_POSITIONED 1328997689
-
#define BTR_PCUR_OLD_STORED 908467085
#define BTR_PCUR_OLD_NOT_STORED 122766467
diff --git a/storage/innobase/include/btr0pcur.ic b/storage/innobase/include/btr0pcur.ic
index 79afd7c322e..29f2fc722a2 100644
--- a/storage/innobase/include/btr0pcur.ic
+++ b/storage/innobase/include/btr0pcur.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -379,7 +379,7 @@ btr_pcur_commit_specify_mtr(
btr_pcur_t* pcur, /*!< in: persistent cursor */
mtr_t* mtr) /*!< in: mtr to commit */
{
- ut_a(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
+ ut_ad(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
pcur->latch_mode = BTR_NO_LATCHES;
diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
index fea117d0aaf..848bde451a0 100644
--- a/storage/innobase/include/btr0sea.h
+++ b/storage/innobase/include/btr0sea.h
@@ -189,8 +189,6 @@ UNIV_INTERN
ibool
btr_search_validate(void);
/*======================*/
-#else
-# define btr_search_validate() TRUE
#endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
/** The search info struct in an index */
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
index 1f5ab0d7923..982bf1943cf 100644
--- a/storage/innobase/include/db0err.h
+++ b/storage/innobase/include/db0err.h
@@ -127,6 +127,7 @@ enum dberr_t {
DB_IDENTIFIER_TOO_LONG, /*!< Identifier name too long */
DB_FTS_EXCEED_RESULT_CACHE_LIMIT, /*!< FTS query memory
exceeds result cache limit */
+ DB_TEMP_FILE_WRITE_FAILURE, /*!< Temp file write failure */
/* The following are partial failure codes */
DB_FAIL = 1000,
diff --git a/storage/innobase/include/dict0stats.ic b/storage/innobase/include/dict0stats.ic
index 8fb31678af9..ec9a9065470 100644
--- a/storage/innobase/include/dict0stats.ic
+++ b/storage/innobase/include/dict0stats.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2012, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h
index 6acb6a2dcbe..1299445a8ee 100644
--- a/storage/innobase/include/dict0types.h
+++ b/storage/innobase/include/dict0types.h
@@ -82,4 +82,9 @@ enum ib_quiesce_t {
#define TEMP_TABLE_PREFIX "#sql"
#define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX
+#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
+/** Flag to control insert buffer debugging. */
+extern uint ibuf_debug;
+#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
+
#endif
diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h
index f94112ef4d4..5bea5bc0e97 100644
--- a/storage/innobase/include/fts0fts.h
+++ b/storage/innobase/include/fts0fts.h
@@ -773,16 +773,12 @@ fts_cache_destroy(
fts_cache_t* cache); /*!< in: cache*/
/*********************************************************************//**
-Clear cache. If the shutdown flag is TRUE then the cache can contain
-data that needs to be freed. For regular clear as part of normal
-working we assume the caller has freed all resources. */
+Clear cache. */
UNIV_INTERN
void
fts_cache_clear(
/*============*/
- fts_cache_t* cache, /*!< in: cache */
- ibool free_words); /*!< in: TRUE if free
- in memory word cache. */
+ fts_cache_t* cache); /*!< in: cache */
/*********************************************************************//**
Initialize things in cache. */
@@ -833,7 +829,7 @@ fts_drop_index_split_tables(
Run SYNC on the table, i.e., write out data from the cache to the
FTS auxiliary INDEX table and clear the cache at the end. */
UNIV_INTERN
-void
+dberr_t
fts_sync_table(
/*===========*/
dict_table_t* table) /*!< in: table */
diff --git a/storage/innobase/include/fts0types.h b/storage/innobase/include/fts0types.h
index b714d326487..64677428331 100644
--- a/storage/innobase/include/fts0types.h
+++ b/storage/innobase/include/fts0types.h
@@ -237,6 +237,7 @@ struct fts_fetch_t {
fts_sql_callback
read_record; /*!< Callback for reading index
record */
+ ulint total_memory; /*!< Total memory used */
};
/** For horizontally splitting an FTS auxiliary index */
diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h
index 0c5a336a1f0..9c3b686c998 100644
--- a/storage/innobase/include/ibuf0ibuf.h
+++ b/storage/innobase/include/ibuf0ibuf.h
@@ -67,11 +67,6 @@ typedef enum {
/** Operations that can currently be buffered. */
extern ibuf_use_t ibuf_use;
-#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
-/** Flag to control insert buffer debugging. */
-extern uint ibuf_debug;
-#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
-
/** The insert buffer control structure */
extern ibuf_t* ibuf;
diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h
index 1e61ea54e7b..61318e34561 100644
--- a/storage/innobase/include/log0log.h
+++ b/storage/innobase/include/log0log.h
@@ -824,6 +824,8 @@ struct log_t{
later; this is advanced when a flush
operation is completed to all the log
groups */
+ volatile bool is_extending; /*!< this is set to true during extend
+ the log buffer size */
lsn_t written_to_some_lsn;
/*!< first log sequence number not yet
written to any log group; for this to
diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h
index 3257402d8aa..ed7fd76d425 100644
--- a/storage/innobase/include/mtr0mtr.h
+++ b/storage/innobase/include/mtr0mtr.h
@@ -315,7 +315,7 @@ mtr_memo_release(
Checks if memo contains the given item.
@return TRUE if contains */
UNIV_INLINE
-ibool
+bool
mtr_memo_contains(
/*==============*/
mtr_t* mtr, /*!< in: mtr */
diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic
index bb24734c9bb..a9f02430220 100644
--- a/storage/innobase/include/mtr0mtr.ic
+++ b/storage/innobase/include/mtr0mtr.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -158,37 +158,38 @@ mtr_release_s_latch_at_savepoint(
Checks if memo contains the given item.
@return TRUE if contains */
UNIV_INLINE
-ibool
+bool
mtr_memo_contains(
/*==============*/
mtr_t* mtr, /*!< in: mtr */
const void* object, /*!< in: object to search */
ulint type) /*!< in: type of object */
{
- mtr_memo_slot_t* slot;
- dyn_array_t* memo;
- ulint offset;
-
ut_ad(mtr);
ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_ACTIVE || mtr->state == MTR_COMMITTING);
- memo = &(mtr->memo);
-
- offset = dyn_array_get_data_size(memo);
-
- while (offset > 0) {
- offset -= sizeof(mtr_memo_slot_t);
-
- slot = (mtr_memo_slot_t*) dyn_array_get_element(memo, offset);
-
- if ((object == slot->object) && (type == slot->type)) {
-
- return(TRUE);
+ for (const dyn_block_t* block = dyn_array_get_last_block(&mtr->memo);
+ block;
+ block = dyn_array_get_prev_block(&mtr->memo, block)) {
+ const mtr_memo_slot_t* start
+ = reinterpret_cast<mtr_memo_slot_t*>(
+ dyn_block_get_data(block));
+ mtr_memo_slot_t* slot
+ = reinterpret_cast<mtr_memo_slot_t*>(
+ dyn_block_get_data(block)
+ + dyn_block_get_used(block));
+
+ ut_ad(!(dyn_block_get_used(block) % sizeof(mtr_memo_slot_t)));
+
+ while (slot-- != start) {
+ if (object == slot->object && type == slot->type) {
+ return(true);
+ }
}
}
- return(FALSE);
+ return(false);
}
# endif /* UNIV_DEBUG */
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/row0ftsort.h b/storage/innobase/include/row0ftsort.h
index 4a486450efc..4e04a099140 100644
--- a/storage/innobase/include/row0ftsort.h
+++ b/storage/innobase/include/row0ftsort.h
@@ -84,10 +84,13 @@ struct fts_psort_t {
row_merge_block_t* block_alloc[FTS_NUM_AUX_INDEX];
/*!< buffer to allocated */
ulint child_status; /*!< child thread status */
- ulint state; /*!< child thread state */
+ ulint state; /*!< parent thread state */
fts_doc_list_t fts_doc_list; /*!< doc list to process */
fts_psort_common_t* psort_common; /*!< ptr to all psort info */
os_thread_t thread_hdl; /*!< thread handler */
+ dberr_t error; /*!< db error during psort */
+ ulint memory_used; /*!< memory used by fts_doc_list */
+ ib_mutex_t mutex; /*!< mutex for fts_doc_list */
};
/** Structure stores information from string tokenization operation */
@@ -124,6 +127,7 @@ typedef struct fts_psort_insert fts_psort_insert_t;
/** status bit used for communication between parent and child thread */
#define FTS_PARENT_COMPLETE 1
+#define FTS_PARENT_EXITING 2
#define FTS_CHILD_COMPLETE 1
#define FTS_CHILD_EXITING 2
diff --git a/storage/innobase/include/srv0conc.h b/storage/innobase/include/srv0conc.h
index 9aee1b17bf0..cf61ef5528d 100644
--- a/storage/innobase/include/srv0conc.h
+++ b/storage/innobase/include/srv0conc.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2011, 2012, Oracle and/or its affiliates. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
diff --git a/storage/innobase/include/srv0mon.h b/storage/innobase/include/srv0mon.h
index 209894833a0..e2ab81bf53a 100644
--- a/storage/innobase/include/srv0mon.h
+++ b/storage/innobase/include/srv0mon.h
@@ -308,7 +308,11 @@ enum monitor_id_t {
/* Index related counters */
MONITOR_MODULE_INDEX,
MONITOR_INDEX_SPLIT,
- MONITOR_INDEX_MERGE,
+ MONITOR_INDEX_MERGE_ATTEMPTS,
+ MONITOR_INDEX_MERGE_SUCCESSFUL,
+ MONITOR_INDEX_REORG_ATTEMPTS,
+ MONITOR_INDEX_REORG_SUCCESSFUL,
+ MONITOR_INDEX_DISCARD,
/* Adaptive Hash Index related counters */
MONITOR_MODULE_ADAPTIVE_HASH,
diff --git a/storage/innobase/include/srv0mon.ic b/storage/innobase/include/srv0mon.ic
index 17411d77a8b..225390c6b6f 100644
--- a/storage/innobase/include/srv0mon.ic
+++ b/storage/innobase/include/srv0mon.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2010, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2010, 2012, Oracle and/or its affiliates. All Rights Reserved.
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
diff --git a/storage/innobase/include/sync0arr.h b/storage/innobase/include/sync0arr.h
index bb4d1037a62..15dbdcb540d 100644
--- a/storage/innobase/include/sync0arr.h
+++ b/storage/innobase/include/sync0arr.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2009, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -37,10 +37,27 @@ struct sync_cell_t;
struct sync_array_t;
/******************************************************************//**
+Get an instance of the sync wait array and reserve a wait array cell
+in the instance for waiting for an object. The event of the cell is
+reset to nonsignalled state.
+If reserving cell of the instance fails, try to get another new
+instance until we can reserve an empty cell of it.
+@return the instance found, never NULL. */
+UNIV_INLINE
+sync_array_t*
+sync_array_get_and_reserve_cell(
+/*============================*/
+ void* object, /*!< in: pointer to the object to wait for */
+ ulint type, /*!< in: lock request type */
+ const char* file, /*!< in: file where requested */
+ ulint line, /*!< in: line where requested */
+ ulint* index); /*!< out: index of the reserved cell */
+/******************************************************************//**
Reserves a wait array cell for waiting for an object.
-The event of the cell is reset to nonsignalled state. */
+The event of the cell is reset to nonsignalled state.
+@return true if free cell is found, otherwise false */
UNIV_INTERN
-void
+bool
sync_array_reserve_cell(
/*====================*/
sync_array_t* arr, /*!< in: wait array */
diff --git a/storage/innobase/include/sync0arr.ic b/storage/innobase/include/sync0arr.ic
index 0114a1ff5a2..18a46dd0a41 100644
--- a/storage/innobase/include/sync0arr.ic
+++ b/storage/innobase/include/sync0arr.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2009, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -24,3 +24,41 @@ Inline code
Created 9/5/1995 Heikki Tuuri
*******************************************************/
+
+/** User configured sync array size */
+extern ulong srv_sync_array_size;
+
+/******************************************************************//**
+Get an instance of the sync wait array and reserve a wait array cell
+in the instance for waiting for an object. The event of the cell is
+reset to nonsignalled state.
+If reserving cell of the instance fails, try to get another new
+instance until we can reserve an empty cell of it.
+@return the instance found, never NULL. */
+UNIV_INLINE
+sync_array_t*
+sync_array_get_and_reserve_cell(
+/*============================*/
+ void* object, /*!< in: pointer to the object to wait for */
+ ulint type, /*!< in: lock request type */
+ const char* file, /*!< in: file where requested */
+ ulint line, /*!< in: line where requested */
+ ulint* index) /*!< out: index of the reserved cell */
+{
+ sync_array_t* sync_arr;
+ bool reserved = false;
+
+ for (ulint i = 0; i < srv_sync_array_size && !reserved; ++i) {
+ sync_arr = sync_array_get();
+ reserved = sync_array_reserve_cell(sync_arr, object, type,
+ file, line, index);
+ }
+
+ /* This won't be true every time, for the loop above may execute
+ more than srv_sync_array_size times to reserve a cell.
+ But an assertion here makes the code more solid. */
+ ut_a(reserved);
+
+ return sync_arr;
+}
+
diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h
index 9950a6fbf6b..7b00e16476b 100644
--- a/storage/innobase/include/sync0sync.h
+++ b/storage/innobase/include/sync0sync.h
@@ -80,6 +80,7 @@ extern mysql_pfs_key_t fts_bg_threads_mutex_key;
extern mysql_pfs_key_t fts_delete_mutex_key;
extern mysql_pfs_key_t fts_optimize_mutex_key;
extern mysql_pfs_key_t fts_doc_id_mutex_key;
+extern mysql_pfs_key_t fts_pll_tokenize_mutex_key;
extern mysql_pfs_key_t hash_table_mutex_key;
extern mysql_pfs_key_t ibuf_bitmap_mutex_key;
extern mysql_pfs_key_t ibuf_mutex_key;
@@ -710,6 +711,7 @@ or row lock! */
#define SYNC_LOG 170
#define SYNC_LOG_FLUSH_ORDER 147
#define SYNC_RECV 168
+#define SYNC_FTS_TOKENIZE 167
#define SYNC_FTS_CACHE_INIT 166 /* Used for FTS cache initialization */
#define SYNC_FTS_BG_THREADS 165
#define SYNC_FTS_OPTIMIZE 164 // FIXME: is this correct number, test
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index a75d925d4eb..f580901237f 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -997,6 +997,10 @@ struct trx_t{
ulint start_line; /*!< Track where it was started from */
const char* start_file; /*!< Filename where it was started */
#endif /* UNIV_DEBUG */
+ /*------------------------------*/
+ bool api_trx; /*!< trx started by InnoDB API */
+ bool api_auto_commit;/*!< automatic commit */
+ bool read_write; /*!< if read and write operation */
/*------------------------------*/
char detailed_error[256]; /*!< detailed error message for last
diff --git a/storage/innobase/include/ut0bh.h b/storage/innobase/include/ut0bh.h
index 84ea6dd915a..1085736c7ab 100644
--- a/storage/innobase/include/ut0bh.h
+++ b/storage/innobase/include/ut0bh.h
@@ -1,6 +1,6 @@
/***************************************************************************//**
-Copyright (c) 2011, Oracle Corpn. All Rights Reserved.
+Copyright (c) 2011, 2013, Oracle Corpn. All Rights Reserved.
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
diff --git a/storage/innobase/include/ut0bh.ic b/storage/innobase/include/ut0bh.ic
index a604237665d..b11de5b8b3e 100644
--- a/storage/innobase/include/ut0bh.ic
+++ b/storage/innobase/include/ut0bh.ic
@@ -1,6 +1,6 @@
/***************************************************************************//**
-Copyright (c) 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc
index a90d49becdf..5282e45dddb 100644
--- a/storage/innobase/log/log0log.cc
+++ b/storage/innobase/log/log0log.cc
@@ -184,6 +184,86 @@ log_buf_pool_get_oldest_modification(void)
return(lsn);
}
+/** Extends the log buffer.
+@param[in] len requested minimum size in bytes */
+static
+void
+log_buffer_extend(
+ ulint len)
+{
+ ulint move_start;
+ ulint move_end;
+ byte tmp_buf[OS_FILE_LOG_BLOCK_SIZE];
+
+ mutex_enter(&(log_sys->mutex));
+
+ while (log_sys->is_extending) {
+ /* Another thread is trying to extend already.
+ Needs to wait for. */
+ mutex_exit(&(log_sys->mutex));
+
+ log_buffer_flush_to_disk();
+
+ mutex_enter(&(log_sys->mutex));
+
+ if (srv_log_buffer_size > len / UNIV_PAGE_SIZE) {
+ /* Already extended enough by the others */
+ mutex_exit(&(log_sys->mutex));
+ return;
+ }
+ }
+
+ log_sys->is_extending = true;
+
+ while (log_sys->n_pending_writes != 0
+ || ut_calc_align_down(log_sys->buf_free,
+ OS_FILE_LOG_BLOCK_SIZE)
+ != ut_calc_align_down(log_sys->buf_next_to_write,
+ OS_FILE_LOG_BLOCK_SIZE)) {
+ /* Buffer might have >1 blocks to write still. */
+ mutex_exit(&(log_sys->mutex));
+
+ log_buffer_flush_to_disk();
+
+ mutex_enter(&(log_sys->mutex));
+ }
+
+ move_start = ut_calc_align_down(
+ log_sys->buf_free,
+ OS_FILE_LOG_BLOCK_SIZE);
+ move_end = log_sys->buf_free;
+
+ /* store the last log block in buffer */
+ ut_memcpy(tmp_buf, log_sys->buf + move_start,
+ move_end - move_start);
+
+ log_sys->buf_free -= move_start;
+ log_sys->buf_next_to_write -= move_start;
+
+ /* reallocate log buffer */
+ srv_log_buffer_size = len / UNIV_PAGE_SIZE + 1;
+ mem_free(log_sys->buf_ptr);
+ log_sys->buf_ptr = static_cast<byte*>(
+ mem_zalloc(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE));
+ log_sys->buf = static_cast<byte*>(
+ ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE));
+ log_sys->buf_size = LOG_BUFFER_SIZE;
+ log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO
+ - LOG_BUF_FLUSH_MARGIN;
+
+ /* restore the last log block */
+ ut_memcpy(log_sys->buf, tmp_buf, move_end - move_start);
+
+ ut_ad(log_sys->is_extending);
+ log_sys->is_extending = false;
+
+ mutex_exit(&(log_sys->mutex));
+
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "innodb_log_buffer_size was extended to %lu.",
+ LOG_BUFFER_SIZE);
+}
+
/************************************************************//**
Opens the log for log_write_low. The log must be closed with log_close and
released with log_release.
@@ -204,11 +284,37 @@ log_reserve_and_open(
ulint count = 0;
#endif /* UNIV_DEBUG */
- ut_a(len < log->buf_size / 2);
+ if (len >= log->buf_size / 2) {
+ DBUG_EXECUTE_IF("ib_log_buffer_is_short_crash",
+ DBUG_SUICIDE(););
+
+ /* log_buffer is too small. try to extend instead of crash. */
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "The transaction log size is too large"
+ " for innodb_log_buffer_size (%lu >= %lu / 2). "
+ "Trying to extend it.",
+ len, LOG_BUFFER_SIZE);
+
+ log_buffer_extend((len + 1) * 2);
+ }
loop:
mutex_enter(&(log->mutex));
ut_ad(!recv_no_log_write);
+ if (log->is_extending) {
+
+ mutex_exit(&(log->mutex));
+
+ /* Log buffer size is extending. Writing up to the next block
+ should wait for the extending finished. */
+
+ os_thread_sleep(100000);
+
+ ut_ad(++count < 50);
+
+ goto loop;
+ }
+
/* Calculate an upper limit for the space the string may take in the
log buffer */
@@ -758,6 +864,7 @@ log_init(void)
ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE));
log_sys->buf_size = LOG_BUFFER_SIZE;
+ log_sys->is_extending = false;
log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO
- LOG_BUF_FLUSH_MARGIN;
diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc
index cb7fd244172..869586bcd90 100644
--- a/storage/innobase/mtr/mtr0mtr.cc
+++ b/storage/innobase/mtr/mtr0mtr.cc
@@ -170,26 +170,29 @@ mtr_memo_note_modifications(
/*========================*/
mtr_t* mtr) /*!< in: mtr */
{
- dyn_array_t* memo;
- ulint offset;
-
ut_ad(!srv_read_only_mode);
ut_ad(mtr->magic_n == MTR_MAGIC_N);
ut_ad(mtr->state == MTR_COMMITTING); /* Currently only used in
commit */
- memo = &mtr->memo;
-
- offset = dyn_array_get_data_size(memo);
-
- while (offset > 0) {
- mtr_memo_slot_t* slot;
- offset -= sizeof(mtr_memo_slot_t);
+ for (const dyn_block_t* block = dyn_array_get_last_block(&mtr->memo);
+ block;
+ block = dyn_array_get_prev_block(&mtr->memo, block)) {
+ const mtr_memo_slot_t* start
+ = reinterpret_cast<mtr_memo_slot_t*>(
+ dyn_block_get_data(block));
+ mtr_memo_slot_t* slot
+ = reinterpret_cast<mtr_memo_slot_t*>(
+ dyn_block_get_data(block)
+ + dyn_block_get_used(block));
- slot = static_cast<mtr_memo_slot_t*>(
- dyn_array_get_element(memo, offset));
+ ut_ad(!(dyn_block_get_used(block) % sizeof(mtr_memo_slot_t)));
- mtr_memo_slot_note_modification(mtr, slot);
+ while (slot-- != start) {
+ if (slot->object != NULL) {
+ mtr_memo_slot_note_modification(mtr, slot);
+ }
+ }
}
}
diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
index c76c3067d08..f473b168e8e 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -1464,18 +1464,32 @@ os_file_set_nocache(
}
#elif defined(O_DIRECT)
if (fcntl(fd, F_SETFL, O_DIRECT) == -1) {
- int errno_save = errno;
-
- ib_logf(IB_LOG_LEVEL_ERROR,
- "Failed to set O_DIRECT on file %s: %s: %s, "
- "continuing anyway",
- file_name, operation_name, strerror(errno_save));
-
+ int errno_save = errno;
+ static bool warning_message_printed = false;
if (errno_save == EINVAL) {
- ib_logf(IB_LOG_LEVEL_ERROR,
- "O_DIRECT is known to result in 'Invalid "
- "argument' on Linux on tmpfs, see MySQL "
- "Bug#26662");
+ if (!warning_message_printed) {
+ warning_message_printed = true;
+# ifdef UNIV_LINUX
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Failed to set O_DIRECT on file "
+ "%s: %s: %s, continuing anyway. "
+ "O_DIRECT is known to result "
+ "in 'Invalid argument' on Linux on "
+ "tmpfs, see MySQL Bug#26662.",
+ file_name, operation_name,
+ strerror(errno_save));
+# else /* UNIV_LINUX */
+ goto short_warning;
+# endif /* UNIV_LINUX */
+ }
+ } else {
+# ifndef UNIV_LINUX
+short_warning:
+# endif
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Failed to set O_DIRECT on file %s: %s: %s, "
+ "continuing anyway.",
+ file_name, operation_name, strerror(errno_save));
}
}
#endif /* defined(UNIV_SOLARIS) && defined(DIRECTIO_ON) */
diff --git a/storage/innobase/os/os0thread.cc b/storage/innobase/os/os0thread.cc
index 9cc09a847b1..6736df46a87 100644
--- a/storage/innobase/os/os0thread.cc
+++ b/storage/innobase/os/os0thread.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -179,6 +179,9 @@ os_thread_create_func(
#ifndef UNIV_HPUX10
pthread_attr_destroy(&attr);
#endif
+
+ ut_a(os_thread_count <= OS_THREAD_MAX_N);
+
if (thread_id) {
*thread_id = pthread;
}
diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc
index 275fedbfb5d..087d2152826 100644
--- a/storage/innobase/row/row0ftsort.cc
+++ b/storage/innobase/row/row0ftsort.cc
@@ -265,6 +265,9 @@ row_fts_psort_info_init(
psort_info[j].child_status = 0;
psort_info[j].state = 0;
psort_info[j].psort_common = common_info;
+ psort_info[j].error = DB_SUCCESS;
+ psort_info[j].memory_used = 0;
+ mutex_create(fts_pll_tokenize_mutex_key, &psort_info[j].mutex, SYNC_FTS_TOKENIZE);
}
/* Initialize merge_info structures parallel merge and insert
@@ -312,6 +315,8 @@ row_fts_psort_info_destroy(
}
mem_free(psort_info[j].merge_file[i]);
}
+
+ mutex_free(&psort_info[j].mutex);
}
os_event_free(merge_info[0].psort_common->sort_event);
@@ -545,6 +550,35 @@ row_merge_fts_doc_tokenize(
}
/*********************************************************************//**
+Get next doc item from fts_doc_list */
+UNIV_INLINE
+void
+row_merge_fts_get_next_doc_item(
+/*============================*/
+ fts_psort_t* psort_info, /*!< in: psort_info */
+ fts_doc_item_t** doc_item) /*!< in/out: doc item */
+{
+ if (*doc_item != NULL) {
+ ut_free(*doc_item);
+ }
+
+ mutex_enter(&psort_info->mutex);
+
+ *doc_item = UT_LIST_GET_FIRST(psort_info->fts_doc_list);
+ if (*doc_item != NULL) {
+ UT_LIST_REMOVE(doc_list, psort_info->fts_doc_list,
+ *doc_item);
+
+ ut_ad(psort_info->memory_used >= sizeof(fts_doc_item_t)
+ + (*doc_item)->field->len);
+ psort_info->memory_used -= sizeof(fts_doc_item_t)
+ + (*doc_item)->field->len;
+ }
+
+ mutex_exit(&psort_info->mutex);
+}
+
+/*********************************************************************//**
Function performs parallel tokenization of the incoming doc strings.
It also performs the initial in memory sort of the parsed records.
@return OS_THREAD_DUMMY_RETURN */
@@ -557,7 +591,6 @@ fts_parallel_tokenization(
fts_psort_t* psort_info = (fts_psort_t*) arg;
ulint i;
fts_doc_item_t* doc_item = NULL;
- fts_doc_item_t* prev_doc_item = NULL;
row_merge_buf_t** buf;
ibool processed = FALSE;
merge_file_t** merge_file;
@@ -575,7 +608,7 @@ fts_parallel_tokenization(
dict_field_t* idx_field;
fts_tokenize_ctx_t t_ctx;
ulint retried = 0;
- ut_ad(psort_info);
+ dberr_t error = DB_SUCCESS;
ut_ad(psort_info);
@@ -599,11 +632,7 @@ fts_parallel_tokenization(
block = psort_info->merge_block;
zip_size = dict_table_zip_size(table);
- doc_item = UT_LIST_GET_FIRST(psort_info->fts_doc_list);
-
- if (doc_item) {
- prev_doc_item = doc_item;
- }
+ row_merge_fts_get_next_doc_item(psort_info, &doc_item);
t_ctx.cached_stopword = table->fts->cache->stopword_info.cached_stopword;
processed = TRUE;
@@ -613,17 +642,8 @@ loop:
last_doc_id = doc_item->doc_id;
- if (!(dfield->data)
- || dfield_get_len(dfield) == UNIV_SQL_NULL) {
- num_doc_processed++;
- doc_item = UT_LIST_GET_NEXT(doc_list, doc_item);
-
- /* Always remember the last doc_item we processed */
- if (doc_item) {
- prev_doc_item = doc_item;
- }
- continue;
- }
+ ut_ad (dfield->data != NULL
+ && dfield_get_len(dfield) != UNIV_SQL_NULL);
/* If finish processing the last item, update "doc" with
strings in the doc_item, otherwise continue processing last
@@ -671,11 +691,13 @@ loop:
num_doc_processed++;
if (fts_enable_diag_print && num_doc_processed % 10000 == 1) {
- fprintf(stderr, "number of doc processed %d\n",
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "number of doc processed %d\n",
(int) num_doc_processed);
#ifdef FTS_INTERNAL_DIAG_PRINT
for (i = 0; i < FTS_NUM_AUX_INDEX; i++) {
- fprintf(stderr, "ID %d, partition %d, word "
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "ID %d, partition %d, word "
"%d\n",(int) psort_info->psort_id,
(int) i, (int) mycount[i]);
}
@@ -684,19 +706,10 @@ loop:
mem_heap_empty(blob_heap);
- if (doc_item->field->data) {
- ut_free(doc_item->field->data);
- doc_item->field->data = NULL;
- }
-
- doc_item = UT_LIST_GET_NEXT(doc_list, doc_item);
+ row_merge_fts_get_next_doc_item(psort_info, &doc_item);
- /* Always remember the last doc_item we processed */
- if (doc_item) {
- prev_doc_item = doc_item;
- if (last_doc_id != doc_item->doc_id) {
- t_ctx.init_pos = 0;
- }
+ if (doc_item && last_doc_id != doc_item->doc_id) {
+ t_ctx.init_pos = 0;
}
}
@@ -707,9 +720,14 @@ loop:
row_merge_buf_write(buf[t_ctx.buf_used],
merge_file[t_ctx.buf_used],
block[t_ctx.buf_used]);
- row_merge_write(merge_file[t_ctx.buf_used]->fd,
- merge_file[t_ctx.buf_used]->offset++,
- block[t_ctx.buf_used]);
+
+ if (!row_merge_write(merge_file[t_ctx.buf_used]->fd,
+ merge_file[t_ctx.buf_used]->offset++,
+ block[t_ctx.buf_used])) {
+ error = DB_TEMP_FILE_WRITE_FAILURE;
+ goto func_exit;
+ }
+
UNIV_MEM_INVALID(block[t_ctx.buf_used][0], srv_sort_buf_size);
buf[t_ctx.buf_used] = row_merge_buf_empty(buf[t_ctx.buf_used]);
mycount[t_ctx.buf_used] += t_ctx.rows_added[t_ctx.buf_used];
@@ -721,13 +739,13 @@ loop:
/* Parent done scanning, and if finish processing all the docs, exit */
if (psort_info->state == FTS_PARENT_COMPLETE) {
- if (num_doc_processed >= UT_LIST_GET_LEN(
- psort_info->fts_doc_list)) {
+ if (UT_LIST_GET_LEN(psort_info->fts_doc_list) == 0) {
goto exit;
} else if (retried > 10000) {
ut_ad(!doc_item);
/* retied too many times and cannot get new record */
- fprintf(stderr, "InnoDB: FTS parallel sort processed "
+ ib_logf(IB_LOG_LEVEL_ERROR,
+ "InnoDB: FTS parallel sort processed "
"%lu records, the sort queue has "
"%lu records. But sort cannot get "
"the next records", num_doc_processed,
@@ -735,21 +753,18 @@ loop:
psort_info->fts_doc_list));
goto exit;
}
+ } else if (psort_info->state == FTS_PARENT_EXITING) {
+ /* Parent abort */
+ goto func_exit;
}
- if (doc_item) {
- doc_item = UT_LIST_GET_NEXT(doc_list, doc_item);
- } else if (prev_doc_item) {
- os_thread_yield();
- doc_item = UT_LIST_GET_NEXT(doc_list, prev_doc_item);
- } else {
+ if (doc_item == NULL) {
os_thread_yield();
- doc_item = UT_LIST_GET_FIRST(psort_info->fts_doc_list);
}
- if (doc_item) {
- prev_doc_item = doc_item;
+ row_merge_fts_get_next_doc_item(psort_info, &doc_item);
+ if (doc_item != NULL) {
if (last_doc_id != doc_item->doc_id) {
t_ctx.init_pos = 0;
}
@@ -799,9 +814,12 @@ exit:
never flush to temp file, it can be held all in
memory */
if (merge_file[i]->offset != 0) {
- row_merge_write(merge_file[i]->fd,
+ if (!row_merge_write(merge_file[i]->fd,
merge_file[i]->offset++,
- block[i]);
+ block[i])) {
+ error = DB_TEMP_FILE_WRITE_FAILURE;
+ goto func_exit;
+ }
UNIV_MEM_INVALID(block[i][0],
srv_sort_buf_size);
@@ -817,19 +835,24 @@ exit:
}
for (i = 0; i < FTS_NUM_AUX_INDEX; i++) {
-
if (!merge_file[i]->offset) {
continue;
}
tmpfd[i] = row_merge_file_create_low();
if (tmpfd[i] < 0) {
+ error = DB_OUT_OF_MEMORY;
+ goto func_exit;
+ }
+
+ error = row_merge_sort(psort_info->psort_common->trx,
+ psort_info->psort_common->dup,
+ merge_file[i], block[i], &tmpfd[i]);
+ if (error != DB_SUCCESS) {
+ close(tmpfd[i]);
goto func_exit;
}
- row_merge_sort(psort_info->psort_common->trx,
- psort_info->psort_common->dup,
- merge_file[i], block[i], &tmpfd[i]);
total_rec += merge_file[i]->n_rec;
close(tmpfd[i]);
}
@@ -841,6 +864,19 @@ func_exit:
mem_heap_free(blob_heap);
+ mutex_enter(&psort_info->mutex);
+ psort_info->error = error;
+ mutex_exit(&psort_info->mutex);
+
+ if (UT_LIST_GET_LEN(psort_info->fts_doc_list) > 0) {
+ ut_ad(error != DB_SUCCESS);
+ }
+
+ /* Free fts doc list in case of error. */
+ do {
+ row_merge_fts_get_next_doc_item(psort_info, &doc_item);
+ } while (doc_item != NULL);
+
psort_info->child_status = FTS_CHILD_COMPLETE;
os_event_set(psort_info->psort_common->sort_event);
psort_info->child_status = FTS_CHILD_EXITING;
diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc
index 170358147b1..c18ef9ee250 100644
--- a/storage/innobase/row/row0log.cc
+++ b/storage/innobase/row/row0log.cc
@@ -1199,8 +1199,7 @@ row_log_table_blob_alloc(
/******************************************************//**
Converts a log record to a table row.
-@return converted row, or NULL if the conversion fails
-or the transaction has been rolled back */
+@return converted row, or NULL if the conversion fails */
static __attribute__((nonnull, warn_unused_result))
const dtuple_t*
row_log_table_apply_convert_mrec(
@@ -1653,9 +1652,6 @@ dberr_t
row_log_table_apply_update(
/*=======================*/
que_thr_t* thr, /*!< in: query graph */
- ulint trx_id_col, /*!< in: position of
- DB_TRX_ID in the
- old clustered index */
ulint new_trx_id_col, /*!< in: position of
DB_TRX_ID in the new
clustered index */
@@ -1716,14 +1712,14 @@ row_log_table_apply_update(
if (page_rec_is_infimum(btr_pcur_get_rec(&pcur))
|| btr_pcur_get_low_match(&pcur) < index->n_uniq) {
+ ut_ad(0);
+ error = DB_CORRUPTION;
+func_exit:
mtr_commit(&mtr);
-insert:
+func_exit_committed:
ut_ad(mtr.state == MTR_COMMITTED);
- /* The row was not found. Insert it. */
- error = row_log_table_apply_insert_low(
- thr, row, trx_id, offsets_heap, heap, dup);
+
if (error != DB_SUCCESS) {
-err_exit:
/* Report the erroneous row using the new
version of the table. */
innobase_row_to_mysql(dup->table, log->table, row);
@@ -1750,26 +1746,17 @@ err_exit:
goto func_exit;
}
- if (rec_offs_any_extern(cur_offsets)) {
+ const bool pk_updated
+ = upd_get_nth_field(update, 0)->field_no < new_trx_id_col;
+
+ if (pk_updated || rec_offs_any_extern(cur_offsets)) {
/* If the record contains any externally stored
columns, perform the update by delete and insert,
because we will not write any undo log that would
allow purge to free any orphaned externally stored
columns. */
-delete_insert:
- error = row_log_table_apply_delete_low(
- &pcur, cur_offsets, NULL, heap, &mtr);
- ut_ad(mtr.state == MTR_COMMITTED);
-
- if (error != DB_SUCCESS) {
- goto err_exit;
- }
- goto insert;
- }
-
- if (upd_get_nth_field(update, 0)->field_no < new_trx_id_col) {
- if (dup->index->online_log->same_pk) {
+ if (pk_updated && dup->index->online_log->same_pk) {
/* The ROW_T_UPDATE log record should only be
written when the PRIMARY KEY fields of the
record did not change in the old table. We
@@ -1781,40 +1768,16 @@ delete_insert:
goto func_exit;
}
- /* The PRIMARY KEY columns have changed.
- Delete the record with the old PRIMARY KEY value,
- provided that it carries the same
- DB_TRX_ID,DB_ROLL_PTR. Then, insert the new row. */
- ulint len;
- const byte* cur_trx_roll = rec_get_nth_field(
- mrec, offsets, trx_id_col, &len);
- ut_ad(len == DATA_TRX_ID_LEN);
- const dfield_t* new_trx_roll = dtuple_get_nth_field(
- old_pk, new_trx_id_col);
- /* We assume that DB_TRX_ID,DB_ROLL_PTR are stored
- in one contiguous block. */
- ut_ad(rec_get_nth_field(mrec, offsets, trx_id_col + 1, &len)
- == cur_trx_roll + DATA_TRX_ID_LEN);
- ut_ad(len == DATA_ROLL_PTR_LEN);
- ut_ad(new_trx_roll->len == DATA_TRX_ID_LEN);
- ut_ad(dtuple_get_nth_field(old_pk, new_trx_id_col + 1)
- -> len == DATA_ROLL_PTR_LEN);
- ut_ad(static_cast<const byte*>(
- dtuple_get_nth_field(old_pk, new_trx_id_col + 1)
- ->data)
- == static_cast<const byte*>(new_trx_roll->data)
- + DATA_TRX_ID_LEN);
-
- if (!memcmp(cur_trx_roll, new_trx_roll->data,
- DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)) {
- /* The old row exists. Remove it. */
- goto delete_insert;
- }
-
- /* Unless we called row_log_table_apply_delete_low(),
- this will likely cause a duplicate key error. */
- mtr_commit(&mtr);
- goto insert;
+ error = row_log_table_apply_delete_low(
+ &pcur, cur_offsets, NULL, heap, &mtr);
+ ut_ad(mtr.state == MTR_COMMITTED);
+
+ if (error == DB_SUCCESS) {
+ error = row_log_table_apply_insert_low(
+ thr, row, trx_id, offsets_heap, heap, dup);
+ }
+
+ goto func_exit_committed;
}
dtuple_t* old_row;
@@ -1913,13 +1876,7 @@ delete_insert:
mtr_start(&mtr);
}
-func_exit:
- mtr_commit(&mtr);
- if (error != DB_SUCCESS) {
- goto err_exit;
- }
-
- return(error);
+ goto func_exit;
}
/******************************************************//**
@@ -2200,7 +2157,7 @@ row_log_table_apply_op(
mrec, offsets, trx_id_col, &len);
ut_ad(len == DATA_TRX_ID_LEN);
*error = row_log_table_apply_update(
- thr, trx_id_col, new_trx_id_col,
+ thr, new_trx_id_col,
mrec, offsets, offsets_heap,
heap, dup, trx_read_trx_id(db_trx_id), old_pk);
}
@@ -2777,7 +2734,16 @@ row_log_apply_op_low(
switch (op) {
case ROW_OP_DELETE:
if (!exists) {
- /* The record was already deleted. */
+ /* The existing record matches the
+ unique secondary index key, but the
+ PRIMARY KEY columns differ. So, this
+ exact record does not exist. For
+ example, we could detect a duplicate
+ key error in some old index before
+ logging an ROW_OP_INSERT for our
+ index. This ROW_OP_DELETE could have
+ been logged for rolling back
+ TRX_UNDO_INSERT_REC. */
goto func_exit;
}
@@ -2817,7 +2783,24 @@ row_log_apply_op_low(
case ROW_OP_INSERT:
if (exists) {
/* The record already exists. There
- is nothing to be inserted. */
+ is nothing to be inserted.
+ This could happen when processing
+ TRX_UNDO_DEL_MARK_REC in statement
+ rollback:
+
+ UPDATE of PRIMARY KEY can lead to
+ statement rollback if the updated
+ value of the PRIMARY KEY already
+ exists. In this case, the UPDATE would
+ be mapped to DELETE;INSERT, and we
+ only wrote undo log for the DELETE
+ part. The duplicate key error would be
+ triggered before logging the INSERT
+ part.
+
+ Theoretically, we could also get a
+ similar situation when a DELETE operation
+ is blocked by a FOREIGN KEY constraint. */
goto func_exit;
}
@@ -2828,17 +2811,18 @@ row_log_apply_op_low(
goto insert_the_rec;
}
- /* Duplicate key error */
- ut_ad(dict_index_is_unique(index));
- row_merge_dup_report(dup, entry->fields);
- goto func_exit;
+ goto duplicate;
}
} else {
switch (op) {
rec_t* rec;
big_rec_t* big_rec;
case ROW_OP_DELETE:
- /* The record does not exist. */
+ /* The record does not exist. For example, we
+ could detect a duplicate key error in some old
+ index before logging an ROW_OP_INSERT for our
+ index. This ROW_OP_DELETE could be logged for
+ rolling back TRX_UNDO_INSERT_REC. */
goto func_exit;
case ROW_OP_INSERT:
if (dict_index_is_unique(index)
@@ -2848,8 +2832,11 @@ row_log_apply_op_low(
>= dict_index_get_n_unique(index))
&& (!index->n_nullable
|| !dtuple_contains_null(entry))) {
+duplicate:
/* Duplicate key */
+ ut_ad(dict_index_is_unique(index));
row_merge_dup_report(dup, entry->fields);
+ *error = DB_DUPLICATE_KEY;
goto func_exit;
}
insert_the_rec:
@@ -3378,7 +3365,7 @@ row_log_apply(
error = DB_SUCCESS;
}
- if (error != DB_SUCCESS || dup.n_dup) {
+ if (error != DB_SUCCESS) {
ut_a(!dict_table_is_discarded(index->table));
/* We set the flag directly instead of invoking
dict_set_corrupted_index_cache_only(index) here,
@@ -3386,12 +3373,9 @@ row_log_apply(
index->type |= DICT_CORRUPT;
index->table->drop_aborted = TRUE;
- if (error == DB_SUCCESS) {
- error = DB_DUPLICATE_KEY;
- }
-
dict_index_set_online_status(index, ONLINE_INDEX_ABORTED);
} else {
+ ut_ad(dup.n_dup == 0);
dict_index_set_online_status(index, ONLINE_INDEX_COMPLETE);
}
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index a0c0fd2c8c3..56cf9f1943c 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -64,6 +64,9 @@ static ibool row_merge_print_block_write;
/* Whether to disable file system cache */
UNIV_INTERN char srv_disable_sort_file_cache;
+/* Maximum pending doc memory limit in bytes for a fts tokenization thread */
+#define FTS_PENDING_DOC_MEMORY_LIMIT 1000000
+
#ifdef UNIV_DEBUG
/******************************************************//**
Display a merge tuple. */
@@ -325,6 +328,9 @@ row_merge_buf_add(
if (index->type & DICT_FTS) {
fts_doc_item_t* doc_item;
byte* value;
+ void* ptr;
+ const ulint max_trial_count = 10000;
+ ulint trial_count = 0;
/* fetch Doc ID if it already exists
in the row, and not supplied by the
@@ -354,13 +360,12 @@ row_merge_buf_add(
continue;
}
- doc_item = static_cast<fts_doc_item_t*>(
- mem_heap_alloc(
- buf->heap,
- sizeof(*doc_item)));
+ ptr = ut_malloc(sizeof(*doc_item)
+ + field->len);
- value = static_cast<byte*>(
- ut_malloc(field->len));
+ doc_item = static_cast<fts_doc_item_t*>(ptr);
+ value = static_cast<byte*>(ptr)
+ + sizeof(*doc_item);
memcpy(value, field->data, field->len);
field->data = value;
@@ -369,10 +374,29 @@ row_merge_buf_add(
bucket = *doc_id % fts_sort_pll_degree;
- UT_LIST_ADD_LAST(
- doc_list,
- psort_info[bucket].fts_doc_list,
- doc_item);
+ /* Add doc item to fts_doc_list */
+ mutex_enter(&psort_info[bucket].mutex);
+
+ if (psort_info[bucket].error == DB_SUCCESS) {
+ UT_LIST_ADD_LAST(
+ doc_list,
+ psort_info[bucket].fts_doc_list,
+ doc_item);
+ psort_info[bucket].memory_used +=
+ sizeof(*doc_item) + field->len;
+ } else {
+ ut_free(doc_item);
+ }
+
+ mutex_exit(&psort_info[bucket].mutex);
+
+ /* Sleep when memory used exceeds limit*/
+ while (psort_info[bucket].memory_used
+ > FTS_PENDING_DOC_MEMORY_LIMIT
+ && trial_count++ < max_trial_count) {
+ os_thread_sleep(1000);
+ }
+
n_row_added = 1;
continue;
}
@@ -1571,12 +1595,28 @@ write_buffers:
max_doc_id = doc_id;
}
+ if (buf->index->type & DICT_FTS) {
+ /* Check if error occurs in child thread */
+ for (ulint j = 0; j < fts_sort_pll_degree; j++) {
+ if (psort_info[j].error != DB_SUCCESS) {
+ err = psort_info[j].error;
+ trx->error_key_num = i;
+ break;
+ }
+ }
+
+ if (err != DB_SUCCESS) {
+ break;
+ }
+ }
+
continue;
}
- if ((buf->index->type & DICT_FTS)
- && (!row || !doc_id)) {
- continue;
+ if (buf->index->type & DICT_FTS) {
+ if (!row || !doc_id) {
+ continue;
+ }
}
/* The buffer must be sufficiently large
@@ -1634,7 +1674,7 @@ write_buffers:
if (!row_merge_write(file->fd, file->offset++,
block)) {
- err = DB_OUT_OF_FILE_SPACE;
+ err = DB_TEMP_FILE_WRITE_FAILURE;
trx->error_key_num = i;
break;
}
@@ -1689,11 +1729,25 @@ all_done:
ulint trial_count = 0;
const ulint max_trial_count = 10000;
+wait_again:
+ /* Check if error occurs in child thread */
+ for (ulint j = 0; j < fts_sort_pll_degree; j++) {
+ if (psort_info[j].error != DB_SUCCESS) {
+ err = psort_info[j].error;
+ trx->error_key_num = j;
+ break;
+ }
+ }
+
/* Tell all children that parent has done scanning */
for (ulint i = 0; i < fts_sort_pll_degree; i++) {
- psort_info[i].state = FTS_PARENT_COMPLETE;
+ if (err == DB_SUCCESS) {
+ psort_info[i].state = FTS_PARENT_COMPLETE;
+ } else {
+ psort_info[i].state = FTS_PARENT_EXITING;
+ }
}
-wait_again:
+
/* Now wait all children to report back to be completed */
os_event_wait_time_low(fts_parallel_sort_event,
1000000, sig_count);
@@ -1748,9 +1802,15 @@ wait_again:
/* Update the next Doc ID we used. Table should be locked, so
no concurrent DML */
- if (max_doc_id) {
- fts_update_next_doc_id(
- 0, new_table, old_table->name, max_doc_id);
+ if (max_doc_id && err == DB_SUCCESS) {
+ /* Sync fts cache for other fts indexes to keep all
+ fts indexes consistent in sync_doc_id. */
+ err = fts_sync_table(const_cast<dict_table_t*>(new_table));
+
+ if (err == DB_SUCCESS) {
+ fts_update_next_doc_id(
+ 0, new_table, old_table->name, max_doc_id);
+ }
}
trx->op_info = "";
@@ -3389,6 +3449,7 @@ row_merge_build_indexes(
fts_psort_t* psort_info = NULL;
fts_psort_t* merge_info = NULL;
ib_int64_t sig_count = 0;
+ bool fts_psort_initiated = false;
DBUG_ENTER("row_merge_build_indexes");
ut_ad(!srv_read_only_mode);
@@ -3445,6 +3506,10 @@ row_merge_build_indexes(
row_fts_psort_info_init(
trx, dup, new_table, opt_doc_id_size,
&psort_info, &merge_info);
+
+ /* "We need to ensure that we free the resources
+ allocated */
+ fts_psort_initiated = true;
}
}
@@ -3567,6 +3632,7 @@ wait_again:
if (indexes[i]->type & DICT_FTS) {
row_fts_psort_info_destroy(psort_info, merge_info);
+ fts_psort_initiated = false;
} else if (error != DB_SUCCESS || !online) {
/* Do not apply any online log. */
} else if (old_table != new_table) {
@@ -3603,6 +3669,12 @@ func_exit:
error = DB_TOO_MANY_CONCURRENT_TRXS;
trx->error_state = error;);
+ if (fts_psort_initiated) {
+ /* Clean up FTS psort related resource */
+ row_fts_psort_info_destroy(psort_info, merge_info);
+ fts_psort_initiated = false;
+ }
+
row_merge_file_destroy_low(tmpfd);
for (i = 0; i < n_indexes; i++) {
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 9aceb305493..2a60790f29c 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -3616,7 +3616,7 @@ next_rec:
if (has_internal_doc_id && table->fts->cache) {
table->fts->fts_status |= TABLE_DICT_LOCKED;
fts_update_next_doc_id(trx, table, NULL, 0);
- fts_cache_clear(table->fts->cache, TRUE);
+ fts_cache_clear(table->fts->cache);
fts_cache_init(table->fts->cache);
table->fts->fts_status &= ~TABLE_DICT_LOCKED;
}
diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc
index 79cced1c533..a59a6088ad6 100644
--- a/storage/innobase/row/row0quiesce.cc
+++ b/storage/innobase/row/row0quiesce.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2012, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 690c6e958fe..09cf75c1050 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -3219,48 +3219,78 @@ sel_restore_position_for_mysql(
mtr_t* mtr) /*!< in: mtr; CAUTION: may commit
mtr temporarily! */
{
- ibool success;
- ulint relative_position;
-
- relative_position = pcur->rel_pos;
+ ibool success;
success = btr_pcur_restore_position(latch_mode, pcur, mtr);
*same_user_rec = success;
- if (relative_position == BTR_PCUR_ON) {
- if (success) {
- return(FALSE);
- }
-
- if (moves_up) {
- btr_pcur_move_to_next(pcur, mtr);
- }
-
- return(TRUE);
+ ut_ad(!success || pcur->rel_pos == BTR_PCUR_ON);
+#ifdef UNIV_DEBUG
+ if (pcur->pos_state == BTR_PCUR_IS_POSITIONED_OPTIMISTIC) {
+ ut_ad(pcur->rel_pos == BTR_PCUR_BEFORE
+ || pcur->rel_pos == BTR_PCUR_AFTER);
+ } else {
+ ut_ad(pcur->pos_state == BTR_PCUR_IS_POSITIONED);
+ ut_ad((pcur->rel_pos == BTR_PCUR_ON)
+ == btr_pcur_is_on_user_rec(pcur));
}
+#endif
- if (relative_position == BTR_PCUR_AFTER
- || relative_position == BTR_PCUR_AFTER_LAST_IN_TREE) {
+ /* The position may need be adjusted for rel_pos and moves_up. */
- if (moves_up) {
+ switch (pcur->rel_pos) {
+ case BTR_PCUR_ON:
+ if (!success && moves_up) {
+next:
+ btr_pcur_move_to_next(pcur, mtr);
return(TRUE);
}
-
- if (btr_pcur_is_on_user_rec(pcur)) {
+ return(!success);
+ case BTR_PCUR_AFTER_LAST_IN_TREE:
+ case BTR_PCUR_BEFORE_FIRST_IN_TREE:
+ return(TRUE);
+ case BTR_PCUR_AFTER:
+ /* positioned to record after pcur->old_rec. */
+ pcur->pos_state = BTR_PCUR_IS_POSITIONED;
+prev:
+ if (btr_pcur_is_on_user_rec(pcur) && !moves_up) {
btr_pcur_move_to_prev(pcur, mtr);
}
-
return(TRUE);
+ case BTR_PCUR_BEFORE:
+ /* For non optimistic restoration:
+ The position is now set to the record before pcur->old_rec.
+
+ For optimistic restoration:
+ The position also needs to take the previous search_mode into
+ consideration. */
+
+ switch (pcur->pos_state) {
+ case BTR_PCUR_IS_POSITIONED_OPTIMISTIC:
+ pcur->pos_state = BTR_PCUR_IS_POSITIONED;
+ if (pcur->search_mode == PAGE_CUR_GE) {
+ /* Positioned during Greater or Equal search
+ with BTR_PCUR_BEFORE. Optimistic restore to
+ the same record. If scanning for lower then
+ we must move to previous record.
+ This can happen with:
+ HANDLER READ idx a = (const);
+ HANDLER READ idx PREV; */
+ goto prev;
+ }
+ return(TRUE);
+ case BTR_PCUR_IS_POSITIONED:
+ if (moves_up && btr_pcur_is_on_user_rec(pcur)) {
+ goto next;
+ }
+ return(TRUE);
+ case BTR_PCUR_WAS_POSITIONED:
+ case BTR_PCUR_NOT_POSITIONED:
+ break;
+ }
}
-
- ut_ad(relative_position == BTR_PCUR_BEFORE
- || relative_position == BTR_PCUR_BEFORE_FIRST_IN_TREE);
-
- if (moves_up && btr_pcur_is_on_user_rec(pcur)) {
- btr_pcur_move_to_next(pcur, mtr);
- }
-
+ ut_ad(0);
return(TRUE);
}
@@ -4358,6 +4388,14 @@ wrong_offs:
btr_pcur_store_position(pcur, &mtr);
+ /* The found record was not a match, but may be used
+ as NEXT record (index_next). Set the relative position
+ to BTR_PCUR_BEFORE, to reflect that the position of
+ the persistent cursor is before the found/stored row
+ (pcur->old_rec). */
+ ut_ad(pcur->rel_pos == BTR_PCUR_ON);
+ pcur->rel_pos = BTR_PCUR_BEFORE;
+
err = DB_RECORD_NOT_FOUND;
#if 0
ut_print_name(stderr, trx, FALSE, index->name);
@@ -4399,6 +4437,14 @@ wrong_offs:
btr_pcur_store_position(pcur, &mtr);
+ /* The found record was not a match, but may be used
+ as NEXT record (index_next). Set the relative position
+ to BTR_PCUR_BEFORE, to reflect that the position of
+ the persistent cursor is before the found/stored row
+ (pcur->old_rec). */
+ ut_ad(pcur->rel_pos == BTR_PCUR_ON);
+ pcur->rel_pos = BTR_PCUR_BEFORE;
+
err = DB_RECORD_NOT_FOUND;
#if 0
ut_print_name(stderr, trx, FALSE, index->name);
@@ -5101,6 +5147,7 @@ normal_return:
pre-fetch queue, but we definitely wrote to the record
buffer passed to use by MySQL. */
+ DEBUG_SYNC_C("row_search_cached_row");
err = DB_SUCCESS;
}
diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc
index d98315ae9a2..ea346566e57 100644
--- a/storage/innobase/srv/srv0mon.cc
+++ b/storage/innobase/srv/srv0mon.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2010, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2010, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
This program is free software; you can redistribute it and/or modify it under
@@ -884,13 +884,33 @@ static monitor_info_t innodb_counter_info[] =
MONITOR_MODULE,
MONITOR_DEFAULT_START, MONITOR_MODULE_INDEX},
- {"index_splits", "index", "Number of index splits",
+ {"index_page_splits", "index", "Number of index page splits",
MONITOR_NONE,
MONITOR_DEFAULT_START, MONITOR_INDEX_SPLIT},
- {"index_merges", "index", "Number of index merges",
+ {"index_page_merge_attempts", "index",
+ "Number of index page merge attempts",
MONITOR_NONE,
- MONITOR_DEFAULT_START, MONITOR_INDEX_MERGE},
+ MONITOR_DEFAULT_START, MONITOR_INDEX_MERGE_ATTEMPTS},
+
+ {"index_page_merge_successful", "index",
+ "Number of successful index page merges",
+ MONITOR_NONE,
+ MONITOR_DEFAULT_START, MONITOR_INDEX_MERGE_SUCCESSFUL},
+
+ {"index_page_reorg_attempts", "index",
+ "Number of index page reorganization attempts",
+ MONITOR_NONE,
+ MONITOR_DEFAULT_START, MONITOR_INDEX_REORG_ATTEMPTS},
+
+ {"index_page_reorg_successful", "index",
+ "Number of successful index page reorganizations",
+ MONITOR_NONE,
+ MONITOR_DEFAULT_START, MONITOR_INDEX_REORG_SUCCESSFUL},
+
+ {"index_page_discards", "index", "Number of index pages discarded",
+ MONITOR_NONE,
+ MONITOR_DEFAULT_START, MONITOR_INDEX_DISCARD},
/* ========== Counters for Adaptive Hash Index ========== */
{"module_adaptive_hash", "adaptive_hash_index", "Adpative Hash Index",
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index 065a6c94074..00604a896ca 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -38,6 +38,9 @@ Starts the InnoDB database server
Created 2/16/1996 Heikki Tuuri
*************************************************************************/
+#include "mysqld.h"
+#include "pars0pars.h"
+#include "row0ftsort.h"
#include "ut0mem.h"
#include "mem0mem.h"
#include "data0data.h"
@@ -1489,6 +1492,10 @@ innobase_start_or_create_for_mysql(void)
char* logfile0 = NULL;
size_t dirnamelen;
+ if (srv_force_recovery > SRV_FORCE_NO_TRX_UNDO) {
+ srv_read_only_mode = true;
+ }
+
if (srv_read_only_mode) {
ib_logf(IB_LOG_LEVEL_INFO, "Started in read only mode");
}
@@ -1728,23 +1735,34 @@ innobase_start_or_create_for_mysql(void)
maximum number of threads that can wait in the 'srv_conc array' for
their time to enter InnoDB. */
- if (srv_buf_pool_size >= 1000 * 1024 * 1024) {
- /* If buffer pool is less than 1000 MB,
- assume fewer threads. Also use only one
- buffer pool instance */
- srv_max_n_threads = 50000;
-
- } else if (srv_buf_pool_size >= 8 * 1024 * 1024) {
-
+#define BUF_POOL_SIZE_THRESHOLD (1024 * 1024 * 1024)
+ srv_max_n_threads = 1 /* io_ibuf_thread */
+ + 1 /* io_log_thread */
+ + 1 /* lock_wait_timeout_thread */
+ + 1 /* srv_error_monitor_thread */
+ + 1 /* srv_monitor_thread */
+ + 1 /* srv_master_thread */
+ + 1 /* srv_purge_coordinator_thread */
+ + 1 /* buf_dump_thread */
+ + 1 /* dict_stats_thread */
+ + 1 /* fts_optimize_thread */
+ + 1 /* recv_writer_thread */
+ + 1 /* buf_flush_page_cleaner_thread */
+ + 1 /* trx_rollback_or_clean_all_recovered */
+ + 128 /* added as margin, for use of
+ InnoDB Memcached etc. */
+ + max_connections
+ + srv_n_read_io_threads
+ + srv_n_write_io_threads
+ + srv_n_purge_threads
+ /* FTS Parallel Sort */
+ + fts_sort_pll_degree * FTS_NUM_AUX_INDEX
+ * max_connections;
+
+ if (srv_buf_pool_size < BUF_POOL_SIZE_THRESHOLD) {
+ /* If buffer pool is less than 1 GB,
+ use only one buffer pool instance */
srv_buf_pool_instances = 1;
- srv_max_n_threads = 10000;
- } else {
- srv_buf_pool_instances = 1;
-
- /* Saves several MB of memory, especially in
- 64-bit computers */
-
- srv_max_n_threads = 1000;
}
srv_boot();
@@ -2554,9 +2572,8 @@ files_checked:
srv_undo_tablespaces, srv_undo_logs);
if (srv_available_undo_logs == ULINT_UNDEFINED) {
- /* Can only happen if force recovery is set. */
- ut_a(srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO
- || srv_read_only_mode);
+ /* Can only happen if server is read only. */
+ ut_a(srv_read_only_mode);
srv_undo_logs = ULONG_UNDEFINED;
}
diff --git a/storage/innobase/sync/sync0arr.cc b/storage/innobase/sync/sync0arr.cc
index 00f92239b64..e06bc01c890 100644
--- a/storage/innobase/sync/sync0arr.cc
+++ b/storage/innobase/sync/sync0arr.cc
@@ -304,9 +304,10 @@ sync_cell_get_event(
/******************************************************************//**
Reserves a wait array cell for waiting for an object.
-The event of the cell is reset to nonsignalled state. */
+The event of the cell is reset to nonsignalled state.
+@return true if free cell is found, otherwise false */
UNIV_INTERN
-void
+bool
sync_array_reserve_cell(
/*====================*/
sync_array_t* arr, /*!< in: wait array */
@@ -365,13 +366,12 @@ sync_array_reserve_cell(
cell->thread = os_thread_get_curr_id();
- return;
+ return(true);
}
}
- ut_error; /* No free cell found */
-
- return;
+ /* No free cell found */
+ return false;
}
/******************************************************************//**
@@ -1077,7 +1077,7 @@ sync_array_init(
ut_a(sync_wait_array == NULL);
ut_a(srv_sync_array_size > 0);
- ut_a(n_threads > srv_sync_array_size);
+ ut_a(n_threads > 0);
sync_array_size = srv_sync_array_size;
diff --git a/storage/innobase/sync/sync0rw.cc b/storage/innobase/sync/sync0rw.cc
index 823efecaf6b..ebf73917702 100644
--- a/storage/innobase/sync/sync0rw.cc
+++ b/storage/innobase/sync/sync0rw.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -33,6 +33,7 @@ Created 9/11/1995 Heikki Tuuri
#include "sync0rw.h"
#ifdef UNIV_NONINL
#include "sync0rw.ic"
+#include "sync0arr.ic"
#endif
#include "os0thread.h"
@@ -405,11 +406,10 @@ lock_loop:
rw_lock_stats.rw_s_spin_round_count.add(counter_index, i);
- sync_arr = sync_array_get();
-
- sync_array_reserve_cell(
- sync_arr, lock, RW_LOCK_SHARED,
- file_name, line, &index);
+ sync_arr = sync_array_get_and_reserve_cell(lock,
+ RW_LOCK_SHARED,
+ file_name,
+ line, &index);
/* Set waiters before checking lock_word to ensure wake-up
signal is sent. This may lead to some unnecessary signals. */
@@ -490,11 +490,10 @@ rw_lock_x_lock_wait(
/* If there is still a reader, then go to sleep.*/
rw_lock_stats.rw_x_spin_round_count.add(counter_index, i);
- sync_arr = sync_array_get();
-
- sync_array_reserve_cell(
- sync_arr, lock, RW_LOCK_WAIT_EX,
- file_name, line, &index);
+ sync_arr = sync_array_get_and_reserve_cell(lock,
+ RW_LOCK_WAIT_EX,
+ file_name,
+ line, &index);
i = 0;
@@ -657,10 +656,8 @@ lock_loop:
rw_lock_stats.rw_x_spin_round_count.add(counter_index, i);
- sync_arr = sync_array_get();
-
- sync_array_reserve_cell(
- sync_arr, lock, RW_LOCK_EX, file_name, line, &index);
+ sync_arr = sync_array_get_and_reserve_cell(lock, RW_LOCK_EX,
+ file_name, line, &index);
/* Waiters must be set before checking lock_word, to ensure signal
is sent. This could lead to a few unnecessary wake-up signals. */
diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc
index d6f7325e2a3..90f16719e20 100644
--- a/storage/innobase/sync/sync0sync.cc
+++ b/storage/innobase/sync/sync0sync.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -33,6 +33,7 @@ Created 9/5/1995 Heikki Tuuri
#include "sync0sync.h"
#ifdef UNIV_NONINL
#include "sync0sync.ic"
+#include "sync0arr.ic"
#endif
#include "sync0rw.h"
@@ -536,10 +537,8 @@ spin_loop:
goto spin_loop;
}
- sync_arr = sync_array_get();
-
- sync_array_reserve_cell(
- sync_arr, mutex, SYNC_MUTEX, file_name, line, &index);
+ sync_arr = sync_array_get_and_reserve_cell(mutex, SYNC_MUTEX,
+ file_name, line, &index);
/* The memory order of the array reservation and the change in the
waiters field is important: when we suspend a thread, we first
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index 0747cffb791..56d46311f62 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -1256,11 +1256,13 @@ run_synchronously:
ut_a(purge_sys->n_submitted == purge_sys->n_completed);
#ifdef UNIV_DEBUG
+ rw_lock_x_lock(&purge_sys->latch);
if (purge_sys->limit.trx_no == 0) {
purge_sys->done = purge_sys->iter;
} else {
purge_sys->done = purge_sys->limit;
}
+ rw_lock_x_unlock(&purge_sys->latch);
#endif /* UNIV_DEBUG */
if (truncate) {
diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
index ea7ad65ffd9..fcf1c1cedf4 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
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
@@ -882,7 +882,7 @@ trx_sys_create_rsegs(
ut_a(n_spaces < TRX_SYS_N_RSEGS);
ut_a(n_rsegs <= TRX_SYS_N_RSEGS);
- if (srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO || srv_read_only_mode) {
+ if (srv_read_only_mode) {
return(ULINT_UNDEFINED);
}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 288e06173c0..7a75c7b573a 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -140,6 +140,12 @@ trx_create(void)
trx->op_info = "";
+ trx->api_trx = false;
+
+ trx->api_auto_commit = false;
+
+ trx->read_write = true;
+
heap = mem_heap_create(sizeof(ib_vector_t) + sizeof(void*) * 8);
heap_alloc = ib_heap_allocator_create(heap);
@@ -381,7 +387,6 @@ trx_list_rw_insert_ordered(
if (trx2 == NULL) {
UT_LIST_ADD_FIRST(trx_list, trx_sys->rw_trx_list, trx);
- ut_d(trx_sys->rw_max_trx_id = trx->id);
} else {
UT_LIST_INSERT_AFTER(
trx_list, trx_sys->rw_trx_list, trx2, trx);
@@ -390,6 +395,12 @@ trx_list_rw_insert_ordered(
UT_LIST_ADD_LAST(trx_list, trx_sys->rw_trx_list, trx);
}
+#ifdef UNIV_DEBUG
+ if (trx->id > trx_sys->rw_max_trx_id) {
+ trx_sys->rw_max_trx_id = trx->id;
+ }
+#endif /* UNIV_DEBUG */
+
ut_ad(!trx->in_rw_trx_list);
ut_d(trx->in_rw_trx_list = TRUE);
}
@@ -737,7 +748,7 @@ trx_assign_rseg_low(
trx_rseg_t* rseg;
static ulint latest_rseg = 0;
- if (srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO || srv_read_only_mode) {
+ if (srv_read_only_mode) {
ut_a(max_undo_logs == ULONG_UNDEFINED);
return(NULL);
}
@@ -753,7 +764,9 @@ trx_assign_rseg_low(
the array. Once we implement more flexible rollback segment
management this may not hold. The assertion checks for that case. */
- ut_a(trx_sys->rseg_array[0] != NULL);
+ if (trx_sys->rseg_array[0] == NULL) {
+ return(NULL);
+ }
/* Skip the system tablespace if we have more than one tablespace
defined for rollback segments. We want all UNDO records to be in
@@ -808,10 +821,12 @@ trx_start_low(
ut_ad(UT_LIST_GET_LEN(trx->lock.trx_locks) == 0);
/* Check whether it is an AUTOCOMMIT SELECT */
- trx->auto_commit = thd_trx_is_auto_commit(trx->mysql_thd);
+ trx->auto_commit = (trx->api_trx && trx->api_auto_commit)
+ || thd_trx_is_auto_commit(trx->mysql_thd);
trx->read_only =
- (!trx->ddl && thd_trx_is_read_only(trx->mysql_thd))
+ (trx->api_trx && !trx->read_write)
+ || (!trx->ddl && thd_trx_is_read_only(trx->mysql_thd))
|| srv_read_only_mode;
if (!trx->auto_commit) {
@@ -865,7 +880,11 @@ trx_start_low(
ut_ad(!trx_is_autocommit_non_locking(trx));
UT_LIST_ADD_FIRST(trx_list, trx_sys->rw_trx_list, trx);
ut_d(trx->in_rw_trx_list = TRUE);
- ut_d(trx_sys->rw_max_trx_id = trx->id);
+#ifdef UNIV_DEBUG
+ if (trx->id > trx_sys->rw_max_trx_id) {
+ trx_sys->rw_max_trx_id = trx->id;
+ }
+#endif /* UNIV_DEBUG */
}
ut_ad(trx_sys_validate_trx_list());
diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc
index e2176a4603a..939a413b4f3 100644
--- a/storage/innobase/ut/ut0ut.cc
+++ b/storage/innobase/ut/ut0ut.cc
@@ -818,6 +818,8 @@ ut_strerr(
return("Identifier name is too long");
case DB_FTS_EXCEED_RESULT_CACHE_LIMIT:
return("FTS query exceeds result cache limit");
+ case DB_TEMP_FILE_WRITE_FAILURE:
+ return("Temp file write failure");
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */