summaryrefslogtreecommitdiff
path: root/storage
diff options
context:
space:
mode:
authorSergei Golubchik <sergii@pisem.net>2014-02-26 19:21:23 +0100
committerSergei Golubchik <sergii@pisem.net>2014-02-26 19:21:23 +0100
commitac585e9ed5d4073b023387c77f90c278f137e469 (patch)
tree852de46e59c6763c02647a28f87af76df6d1c582 /storage
parent6bc7bd0eb233aa08702bcc0f0c3ca8b73fc32294 (diff)
parentb338c8eb56d92bc3a5f4665ad74e93a840eb96d3 (diff)
downloadmariadb-git-ac585e9ed5d4073b023387c77f90c278f137e469.tar.gz
Percona-Server-5.6.15-rel63.0.tar.gz merge
Diffstat (limited to 'storage')
-rw-r--r--storage/xtradb/api/api0api.cc64
-rw-r--r--storage/xtradb/btr/btr0btr.cc11
-rw-r--r--storage/xtradb/btr/btr0cur.cc31
-rw-r--r--storage/xtradb/btr/btr0pcur.cc44
-rw-r--r--storage/xtradb/buf/buf0buf.cc1
-rw-r--r--storage/xtradb/dict/dict0crea.cc14
-rw-r--r--storage/xtradb/dict/dict0load.cc2
-rw-r--r--storage/xtradb/dict/dict0mem.cc6
-rw-r--r--storage/xtradb/dict/dict0stats.cc27
-rw-r--r--storage/xtradb/fil/fil0fil.cc1
-rw-r--r--storage/xtradb/fts/fts0config.cc4
-rw-r--r--storage/xtradb/fts/fts0fts.cc61
-rw-r--r--storage/xtradb/fts/fts0opt.cc30
-rw-r--r--storage/xtradb/fts/fts0que.cc17
-rw-r--r--storage/xtradb/handler/ha_innodb.cc287
-rw-r--r--storage/xtradb/handler/handler0alter.cc12
-rw-r--r--storage/xtradb/handler/i_s.cc225
-rw-r--r--storage/xtradb/handler/xtradb_i_s.cc2
-rw-r--r--storage/xtradb/ibuf/ibuf0ibuf.cc28
-rw-r--r--storage/xtradb/include/api0api.h16
-rw-r--r--storage/xtradb/include/btr0cur.h14
-rw-r--r--storage/xtradb/include/btr0pcur.h44
-rw-r--r--storage/xtradb/include/btr0pcur.ic4
-rw-r--r--storage/xtradb/include/btr0sea.h2
-rw-r--r--storage/xtradb/include/buf0flu.h6
-rw-r--r--storage/xtradb/include/buf0flu.ic17
-rw-r--r--storage/xtradb/include/db0err.h1
-rw-r--r--storage/xtradb/include/dict0stats.ic2
-rw-r--r--storage/xtradb/include/dict0types.h5
-rw-r--r--storage/xtradb/include/fts0fts.h10
-rw-r--r--storage/xtradb/include/fts0types.h1
-rw-r--r--storage/xtradb/include/ibuf0ibuf.h5
-rw-r--r--storage/xtradb/include/log0log.h2
-rw-r--r--storage/xtradb/include/mtr0mtr.h2
-rw-r--r--storage/xtradb/include/mtr0mtr.ic39
-rw-r--r--storage/xtradb/include/row0ftsort.h6
-rw-r--r--storage/xtradb/include/srv0conc.h2
-rw-r--r--storage/xtradb/include/srv0mon.h6
-rw-r--r--storage/xtradb/include/srv0mon.ic2
-rw-r--r--storage/xtradb/include/sync0arr.h23
-rw-r--r--storage/xtradb/include/sync0arr.ic40
-rw-r--r--storage/xtradb/include/sync0rw.h8
-rw-r--r--storage/xtradb/include/sync0rw.ic32
-rw-r--r--storage/xtradb/include/sync0sync.h13
-rw-r--r--storage/xtradb/include/sync0sync.ic1
-rw-r--r--storage/xtradb/include/trx0trx.h4
-rw-r--r--storage/xtradb/include/univ.i4
-rw-r--r--storage/xtradb/include/ut0bh.h2
-rw-r--r--storage/xtradb/include/ut0bh.ic2
-rw-r--r--storage/xtradb/log/log0log.cc141
-rw-r--r--storage/xtradb/log/log0online.cc17
-rw-r--r--storage/xtradb/log/log0recv.cc10
-rw-r--r--storage/xtradb/mtr/mtr0mtr.cc29
-rw-r--r--storage/xtradb/os/os0file.cc38
-rw-r--r--storage/xtradb/os/os0thread.cc5
-rw-r--r--storage/xtradb/row/row0ftsort.cc142
-rw-r--r--storage/xtradb/row/row0log.cc140
-rw-r--r--storage/xtradb/row/row0merge.cc110
-rw-r--r--storage/xtradb/row/row0mysql.cc2
-rw-r--r--storage/xtradb/row/row0quiesce.cc2
-rw-r--r--storage/xtradb/row/row0sel.cc103
-rw-r--r--storage/xtradb/srv/srv0mon.cc28
-rw-r--r--storage/xtradb/srv/srv0start.cc55
-rw-r--r--storage/xtradb/sync/sync0arr.cc20
-rw-r--r--storage/xtradb/sync/sync0rw.cc88
-rw-r--r--storage/xtradb/sync/sync0sync.cc33
-rw-r--r--storage/xtradb/trx/trx0purge.cc2
-rw-r--r--storage/xtradb/trx/trx0sys.cc4
-rw-r--r--storage/xtradb/trx/trx0trx.cc34
-rw-r--r--storage/xtradb/ut/ut0ut.cc2
70 files changed, 1461 insertions, 726 deletions
diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc
index 647ebcde6f0..d2f1a468f25 100644
--- a/storage/xtradb/api/api0api.cc
+++ b/storage/xtradb/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/xtradb/btr/btr0btr.cc b/storage/xtradb/btr/btr0btr.cc
index 78f6d661560..cce91bdab6e 100644
--- a/storage/xtradb/btr/btr0btr.cc
+++ b/storage/xtradb/btr/btr0btr.cc
@@ -1844,6 +1844,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);
@@ -1992,6 +1994,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 */
@@ -3615,6 +3619,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);
@@ -3848,6 +3854,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:
@@ -3968,6 +3977,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_fast(block), mtr);
diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc
index bd2dd1e6095..a180649fa1e 100644
--- a/storage/xtradb/btr/btr0cur.cc
+++ b/storage/xtradb/btr/btr0cur.cc
@@ -1828,7 +1828,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(
/*========================*/
@@ -1856,18 +1856,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/xtradb/btr/btr0pcur.cc b/storage/xtradb/btr/btr0pcur.cc
index 49002ca9ab6..28a60de6ba2 100644
--- a/storage/xtradb/btr/btr0pcur.cc
+++ b/storage/xtradb/btr/btr0pcur.cc
@@ -111,7 +111,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);
@@ -128,7 +128,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
@@ -240,21 +239,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)) {
@@ -279,14 +269,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),
@@ -298,9 +288,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);
@@ -318,7 +305,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);
}
}
@@ -420,7 +413,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));
@@ -486,7 +479,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/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc
index d4b170028d9..2ec25491f4c 100644
--- a/storage/xtradb/buf/buf0buf.cc
+++ b/storage/xtradb/buf/buf0buf.cc
@@ -2752,7 +2752,6 @@ wait_until_unfixed:
buf_LRU_block_free_non_file_page(block);
mutex_exit(&buf_pool->LRU_list_mutex);
- mutex_exit(&buf_pool->zip_mutex);
rw_lock_x_unlock(hash_lock);
mutex_exit(&block->mutex);
diff --git a/storage/xtradb/dict/dict0crea.cc b/storage/xtradb/dict/dict0crea.cc
index c7cb3aa21bb..eba5417dc76 100644
--- a/storage/xtradb/dict/dict0crea.cc
+++ b/storage/xtradb/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/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc
index d731aeca55f..5c97b5aba7c 100644
--- a/storage/xtradb/dict/dict0load.cc
+++ b/storage/xtradb/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/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc
index 9214a6e6e5a..f69e6cc47ae 100644
--- a/storage/xtradb/dict/dict0mem.cc
+++ b/storage/xtradb/dict/dict0mem.cc
@@ -142,10 +142,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/xtradb/dict/dict0stats.cc b/storage/xtradb/dict/dict0stats.cc
index bfd0542b8e2..8bf02f9785c 100644
--- a/storage/xtradb/dict/dict0stats.cc
+++ b/storage/xtradb/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/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index 9861f85b814..2d81dd8db48 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -4949,6 +4949,7 @@ retry:
os_has_said_disk_full = FALSE;
}
node->being_extended = FALSE;
+ fil_node_complete_io(node, fil_system, OS_FILE_READ);
goto complete_io;
}
#endif
diff --git a/storage/xtradb/fts/fts0config.cc b/storage/xtradb/fts/fts0config.cc
index 29d6771f9e7..c5cf38ca7f9 100644
--- a/storage/xtradb/fts/fts0config.cc
+++ b/storage/xtradb/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/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc
index 83c6d1f5e80..1b114adea1f 100644
--- a/storage/xtradb/fts/fts0fts.cc
+++ b/storage/xtradb/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/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc
index 0fd577c5767..7cdad522564 100644
--- a/storage/xtradb/fts/fts0opt.cc
+++ b/storage/xtradb/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/xtradb/fts/fts0que.cc b/storage/xtradb/fts/fts0que.cc
index c2922d993bf..7da60c0d166 100644
--- a/storage/xtradb/fts/fts0que.cc
+++ b/storage/xtradb/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/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 43a99cafb64..d26c315d2eb 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -43,6 +43,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>
@@ -206,8 +207,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 */
@@ -370,6 +369,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},
@@ -555,7 +555,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
};
/*************************************************************//**
@@ -1727,6 +1728,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);
@@ -2457,6 +2465,62 @@ trx_is_started(
return(trx->state != TRX_STATE_NOT_STARTED);
}
+/****************************************************************//**
+Update log_checksum_algorithm_ptr with a pointer to the function corresponding
+to a given checksum algorithm. */
+static
+void
+innodb_log_checksum_func_update(
+/*============================*/
+ ulint algorithm) /*!< in: algorithm */
+{
+ switch (algorithm) {
+ case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
+ case SRV_CHECKSUM_ALGORITHM_INNODB:
+ log_checksum_algorithm_ptr=log_block_calc_checksum_innodb;
+ break;
+ case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
+ case SRV_CHECKSUM_ALGORITHM_CRC32:
+ log_checksum_algorithm_ptr=log_block_calc_checksum_crc32;
+ break;
+ case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
+ case SRV_CHECKSUM_ALGORITHM_NONE:
+ log_checksum_algorithm_ptr=log_block_calc_checksum_none;
+ break;
+ default:
+ ut_a(0);
+ }
+}
+
+/****************************************************************//**
+On update hook for the innodb_log_checksum_algorithm variable. */
+static
+void
+innodb_log_checksum_algorithm_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 */
+{
+ srv_checksum_algorithm_t algorithm;
+
+ algorithm = (srv_checksum_algorithm_t)
+ (*static_cast<const ulong*>(save));
+
+ /* Make sure we are the only log user */
+ mutex_enter(&log_sys->mutex);
+
+ innodb_log_checksum_func_update(algorithm);
+
+ srv_log_checksum_algorithm = algorithm;
+
+ mutex_exit(&log_sys->mutex);
+}
+
/*********************************************************************//**
Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object.
Those flags are stored in .frm file and end up in the MySQL table object,
@@ -3382,12 +3446,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;
@@ -3541,6 +3599,8 @@ innobase_change_buffering_inited_ok:
srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_NONE;
}
+ innodb_log_checksum_func_update(srv_log_checksum_algorithm);
+
#ifdef HAVE_LARGE_PAGES
if ((os_use_large_pages = (ibool) my_use_large_pages)) {
os_large_page_size = (ulint) opt_large_page_size;
@@ -3765,9 +3825,6 @@ innobase_end(
mysql_mutex_destroy(&pending_checkpoint_mutex);
}
- my_free(fts_server_stopword_table);
- fts_server_stopword_table= NULL;
-
DBUG_RETURN(err);
}
@@ -6154,6 +6211,7 @@ innobase_mysql_fts_get_token(
ut_a(cs);
token->f_n_char = token->f_len = 0;
+ token->f_str = NULL;
for (;;) {
@@ -8832,7 +8890,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();
@@ -8882,17 +8940,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);
}
@@ -8902,10 +8967,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);
@@ -9888,7 +9953,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));
}
@@ -11194,6 +11259,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;
@@ -12047,13 +12116,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;
@@ -12109,35 +12177,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. */
@@ -12159,7 +12241,7 @@ ha_innobase::check(
"InnoDB: Index %s is marked as"
" corrupted",
index_name);
- is_ok = FALSE;
+ is_ok = false;
} else {
push_warning_printf(
thd,
@@ -12192,7 +12274,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");
}
@@ -12218,7 +12300,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");
@@ -12241,21 +12323,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)) {
@@ -13248,7 +13326,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);
@@ -13325,13 +13403,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);
}
/************************************************************************//**
@@ -15076,44 +15154,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.
@@ -16016,51 +16056,6 @@ innodb_reset_all_monitor_update(
}
/****************************************************************//**
-Update log_checksum_algorithm_ptr with a pointer to the function corresponding
-to a given checksum algorithm. */
-static
-void
-innodb_log_checksum_algorithm_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 */
-{
- srv_checksum_algorithm_t algorithm;
-
- algorithm = (srv_checksum_algorithm_t)
- (*static_cast<const ulong*>(save));
-
- /* Make sure we are the only log user */
- mutex_enter(&log_sys->mutex);
-
- switch (algorithm) {
- case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
- case SRV_CHECKSUM_ALGORITHM_INNODB:
- log_checksum_algorithm_ptr=log_block_calc_checksum_innodb;
- break;
- case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
- case SRV_CHECKSUM_ALGORITHM_CRC32:
- log_checksum_algorithm_ptr=log_block_calc_checksum_crc32;
- break;
- case SRV_CHECKSUM_ALGORITHM_STRICT_NONE:
- case SRV_CHECKSUM_ALGORITHM_NONE:
- log_checksum_algorithm_ptr=log_block_calc_checksum_none;
- break;
- default:
- ut_a(0);
- }
-
- srv_log_checksum_algorithm = algorithm;
-
- mutex_exit(&log_sys->mutex);
-}
-
-/****************************************************************//**
Parse and enable InnoDB monitor counters during server startup.
User can list the monitor counters/groups to be enable by specifying
"loose-innodb_monitor_enable=monitor_name1;monitor_name2..."
@@ -16899,10 +16894,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/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index 9c535285d1e..21859cb5447 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/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));
@@ -3975,7 +3981,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. */
@@ -5737,6 +5744,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/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc
index 98a7887bc07..5603f8cfbe4 100644
--- a/storage/xtradb/handler/i_s.cc
+++ b/storage/xtradb/handler/i_s.cc
@@ -3223,12 +3223,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;
@@ -3239,6 +3249,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;
@@ -3261,8 +3285,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,
@@ -3292,6 +3315,8 @@ i_s_fts_index_cache_fill_one_index(
}
}
+ ut_free(conv_str.f_str);
+
DBUG_RETURN(0);
}
/*******************************************************************//**
@@ -3415,31 +3440,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);
@@ -3450,7 +3482,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"
@@ -3481,7 +3513,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;
}
@@ -3494,54 +3526,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));
-
- heap = mem_heap_create(1024);
+ uint dummy_errors;
+ char* word_str;
+ ulint words_size;
+ int ret = 0;
- 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;
@@ -3565,8 +3637,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,
@@ -3596,9 +3667,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/xtradb/handler/xtradb_i_s.cc b/storage/xtradb/handler/xtradb_i_s.cc
index 77050c0b7f8..7078ab752c2 100644
--- a/storage/xtradb/handler/xtradb_i_s.cc
+++ b/storage/xtradb/handler/xtradb_i_s.cc
@@ -552,6 +552,8 @@ i_s_xtradb_rseg_fill(
for(int i=0; i < TRX_SYS_N_RSEGS; i++)
{
rseg = trx_sys->rseg_array[i];
+ if (!rseg)
+ continue;
table->field[0]->store(rseg->id);
table->field[1]->store(rseg->space);
diff --git a/storage/xtradb/ibuf/ibuf0ibuf.cc b/storage/xtradb/ibuf/ibuf0ibuf.cc
index 876906fc9ce..2964fa99c8a 100644
--- a/storage/xtradb/ibuf/ibuf0ibuf.cc
+++ b/storage/xtradb/ibuf/ibuf0ibuf.cc
@@ -2792,6 +2792,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) {
@@ -4181,6 +4185,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;
}
@@ -4434,14 +4454,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/xtradb/include/api0api.h b/storage/xtradb/include/api0api.h
index 1d6aaab60bc..c294e3f34d5 100644
--- a/storage/xtradb/include/api0api.h
+++ b/storage/xtradb/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/xtradb/include/btr0cur.h b/storage/xtradb/include/btr0cur.h
index cf7c1a24139..8a35cb1a3da 100644
--- a/storage/xtradb/include/btr0cur.h
+++ b/storage/xtradb/include/btr0cur.h
@@ -332,6 +332,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/xtradb/include/btr0pcur.h b/storage/xtradb/include/btr0pcur.h
index 973fae382ab..fc008cdd185 100644
--- a/storage/xtradb/include/btr0pcur.h
+++ b/storage/xtradb/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/xtradb/include/btr0pcur.ic b/storage/xtradb/include/btr0pcur.ic
index 79afd7c322e..29f2fc722a2 100644
--- a/storage/xtradb/include/btr0pcur.ic
+++ b/storage/xtradb/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/xtradb/include/btr0sea.h b/storage/xtradb/include/btr0sea.h
index 9f9c2b04191..d40094461ff 100644
--- a/storage/xtradb/include/btr0sea.h
+++ b/storage/xtradb/include/btr0sea.h
@@ -190,8 +190,6 @@ UNIV_INTERN
ibool
btr_search_validate(void);
/*======================*/
-#else
-# define btr_search_validate() TRUE
#endif /* defined UNIV_AHI_DEBUG || defined UNIV_DEBUG */
/********************************************************************//**
diff --git a/storage/xtradb/include/buf0flu.h b/storage/xtradb/include/buf0flu.h
index f4542e7c206..73525a5bb58 100644
--- a/storage/xtradb/include/buf0flu.h
+++ b/storage/xtradb/include/buf0flu.h
@@ -279,9 +279,9 @@ buf_flush_get_dirty_pages_count(
#endif /* !UNIV_HOTBACKUP */
/******************************************************************//**
-Check if a flush list flush is in progress for any buffer pool instance for
-heuristic purposes.
-@return true if flush list flush is in progress */
+Check if a flush list flush is in progress for any buffer pool instance, or if
+all the instances are clean, for heuristic purposes.
+@return true if flush list flush is in progress or buffer pool is clean */
UNIV_INLINE
bool
buf_flush_flush_list_in_progress(void)
diff --git a/storage/xtradb/include/buf0flu.ic b/storage/xtradb/include/buf0flu.ic
index b1e64def462..06fa49754cd 100644
--- a/storage/xtradb/include/buf0flu.ic
+++ b/storage/xtradb/include/buf0flu.ic
@@ -137,14 +137,16 @@ buf_flush_recv_note_modification(
#endif /* !UNIV_HOTBACKUP */
/******************************************************************//**
-Check if a flush list flush is in progress for any buffer pool instance for
-heuristic purposes.
-@return true if flush list flush is in progress */
+Check if a flush list flush is in progress for any buffer pool instance, or if
+all the instances are clean, for heuristic purposes.
+@return true if flush list flush is in progress or buffer pool is clean */
UNIV_INLINE
bool
buf_flush_flush_list_in_progress(void)
/*==================================*/
{
+ bool all_clean = true;
+
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
const buf_pool_t* buf_pool = buf_pool_from_array(i);
@@ -153,6 +155,13 @@ buf_flush_flush_list_in_progress(void)
return(true);
}
+
+ if (all_clean) {
+
+ all_clean = (UT_LIST_GET_LEN(buf_pool->flush_list)
+ == 0);
+ }
+
}
- return(false);
+ return(all_clean);
}
diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h
index af651c61b66..17fef0dc1f4 100644
--- a/storage/xtradb/include/db0err.h
+++ b/storage/xtradb/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/xtradb/include/dict0stats.ic b/storage/xtradb/include/dict0stats.ic
index 8fb31678af9..ec9a9065470 100644
--- a/storage/xtradb/include/dict0stats.ic
+++ b/storage/xtradb/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/xtradb/include/dict0types.h b/storage/xtradb/include/dict0types.h
index 6acb6a2dcbe..1299445a8ee 100644
--- a/storage/xtradb/include/dict0types.h
+++ b/storage/xtradb/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/xtradb/include/fts0fts.h b/storage/xtradb/include/fts0fts.h
index f94112ef4d4..5bea5bc0e97 100644
--- a/storage/xtradb/include/fts0fts.h
+++ b/storage/xtradb/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/xtradb/include/fts0types.h b/storage/xtradb/include/fts0types.h
index b714d326487..64677428331 100644
--- a/storage/xtradb/include/fts0types.h
+++ b/storage/xtradb/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/xtradb/include/ibuf0ibuf.h b/storage/xtradb/include/ibuf0ibuf.h
index f2e1c80878e..ac16b10e097 100644
--- a/storage/xtradb/include/ibuf0ibuf.h
+++ b/storage/xtradb/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/xtradb/include/log0log.h b/storage/xtradb/include/log0log.h
index bab256e5a65..b9e0c2ef516 100644
--- a/storage/xtradb/include/log0log.h
+++ b/storage/xtradb/include/log0log.h
@@ -874,6 +874,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/xtradb/include/mtr0mtr.h b/storage/xtradb/include/mtr0mtr.h
index fd0fb66c464..0730e870b3f 100644
--- a/storage/xtradb/include/mtr0mtr.h
+++ b/storage/xtradb/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/xtradb/include/mtr0mtr.ic b/storage/xtradb/include/mtr0mtr.ic
index 4fe23c460ab..cc021038001 100644
--- a/storage/xtradb/include/mtr0mtr.ic
+++ b/storage/xtradb/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/xtradb/include/row0ftsort.h b/storage/xtradb/include/row0ftsort.h
index 4a486450efc..4e04a099140 100644
--- a/storage/xtradb/include/row0ftsort.h
+++ b/storage/xtradb/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/xtradb/include/srv0conc.h b/storage/xtradb/include/srv0conc.h
index 9aee1b17bf0..cf61ef5528d 100644
--- a/storage/xtradb/include/srv0conc.h
+++ b/storage/xtradb/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/xtradb/include/srv0mon.h b/storage/xtradb/include/srv0mon.h
index 209894833a0..e2ab81bf53a 100644
--- a/storage/xtradb/include/srv0mon.h
+++ b/storage/xtradb/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/xtradb/include/srv0mon.ic b/storage/xtradb/include/srv0mon.ic
index 17411d77a8b..225390c6b6f 100644
--- a/storage/xtradb/include/srv0mon.ic
+++ b/storage/xtradb/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/xtradb/include/sync0arr.h b/storage/xtradb/include/sync0arr.h
index bb4d1037a62..15dbdcb540d 100644
--- a/storage/xtradb/include/sync0arr.h
+++ b/storage/xtradb/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/xtradb/include/sync0arr.ic b/storage/xtradb/include/sync0arr.ic
index 0114a1ff5a2..18a46dd0a41 100644
--- a/storage/xtradb/include/sync0arr.ic
+++ b/storage/xtradb/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/xtradb/include/sync0rw.h b/storage/xtradb/include/sync0rw.h
index ace3a0993c8..a215d4d3f60 100644
--- a/storage/xtradb/include/sync0rw.h
+++ b/storage/xtradb/include/sync0rw.h
@@ -780,13 +780,13 @@ struct prio_rw_lock_t {
provides the lock word etc. for
the priority rw lock */
volatile ulint high_priority_s_waiters;
- /* If 1, high priority S
- waiters exist */
+ /* Number of high priority S
+ waiters */
os_event_t high_priority_s_event; /* High priority wait
array event for S waiters */
volatile ulint high_priority_x_waiters;
- /* If 1, high priority X
- waiters exist */
+ /* Number of high priority X
+ waiters */
os_event_t high_priority_x_event;
/* High priority wait arraay
event for X waiters */
diff --git a/storage/xtradb/include/sync0rw.ic b/storage/xtradb/include/sync0rw.ic
index c625ee39035..097adfded37 100644
--- a/storage/xtradb/include/sync0rw.ic
+++ b/storage/xtradb/include/sync0rw.ic
@@ -94,8 +94,8 @@ rw_lock_get_waiters(
const prio_rw_lock_t* lock) /*!< in: rw-lock */
{
return rw_lock_get_waiters(&lock->base_lock)
- | lock->high_priority_s_waiters
- | lock->high_priority_x_waiters;
+ || lock->high_priority_s_waiters
+ || lock->high_priority_x_waiters;
}
/********************************************************************//**
@@ -619,32 +619,14 @@ rw_lock_s_unlock_func(
if (lock_word == 0) {
/* A waiting next-writer exists, either high priority or
- regular. Wake up the first waiter in this order: 1) high
- priority next-writer; 2) high priority X waiters; 3) high
- priority S waiters; 4) regular priority next-waiter. This
- allows high priority requests to overtake an already-waiting
- regular priority next-waiter. */
+ regular, sharing the same wait event. */
if (lock->high_priority_wait_ex_waiter) {
lock->high_priority_wait_ex_waiter = 0;
- /* Note that we do not have a separate high priority
- next-waiter event. There can be only one such waiter,
- here we already know it's high priority, no
- regular-priority wakeup may happen. */
- os_event_set(lock->base_lock.wait_ex_event);
- } else if (lock->high_priority_x_waiters) {
-
- lock->high_priority_x_waiters = 0;
- os_event_set(lock->high_priority_x_event);
- } else if (lock->high_priority_s_waiters) {
-
- lock->high_priority_s_waiters = 0;
- os_event_set(lock->high_priority_s_event);
- } else {
-
- os_event_set(lock->base_lock.wait_ex_event);
}
+ os_event_set(lock->base_lock.wait_ex_event);
sync_array_object_signalled();
+
} else if (lock_word == X_LOCK_DECR) {
/* S-waiters may exist during an S unlock if a high-priority
@@ -765,6 +747,8 @@ rw_lock_x_unlock_func(
#endif
&lock->base_lock);
+ ut_ad(lock->high_priority_wait_ex_waiter == 0);
+
if (rw_lock_lock_word_incr(&lock->base_lock, x_lock_incr)
== X_LOCK_DECR) {
@@ -776,12 +760,10 @@ rw_lock_x_unlock_func(
if (lock->high_priority_x_waiters) {
- lock->high_priority_x_waiters = 0;
os_event_set(lock->high_priority_x_event);
sync_array_object_signalled();
} else if (lock->high_priority_s_waiters) {
- lock->high_priority_s_waiters = 0;
os_event_set(lock->high_priority_s_event);
sync_array_object_signalled();
} else if (lock->base_lock.waiters) {
diff --git a/storage/xtradb/include/sync0sync.h b/storage/xtradb/include/sync0sync.h
index f54c6d59af9..5520ed2d827 100644
--- a/storage/xtradb/include/sync0sync.h
+++ b/storage/xtradb/include/sync0sync.h
@@ -86,6 +86,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;
@@ -888,6 +889,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
@@ -977,12 +979,11 @@ struct ib_prio_mutex_t {
word etc. for the priority mutex */
os_event_t high_priority_event; /* High priority wait array
event */
- volatile ulint high_priority_waiters; /* Set to 1 if there are (or
- may be) threads that asked for this
- mutex to be acquired with high priority
- in the global wait array for this mutex
- to be released. Otherwise, this is
- 0. */
+ volatile ulint high_priority_waiters; /* Number of threads that asked
+ for this mutex to be acquired with high
+ priority in the global wait array
+ waiting for this mutex to be
+ released. */
};
/** Constant determining how long spin wait is continued before suspending
diff --git a/storage/xtradb/include/sync0sync.ic b/storage/xtradb/include/sync0sync.ic
index 396005ec83a..3ea82ebe002 100644
--- a/storage/xtradb/include/sync0sync.ic
+++ b/storage/xtradb/include/sync0sync.ic
@@ -227,7 +227,6 @@ mutex_exit_func(
/* Wake up any high priority waiters first. */
if (mutex->high_priority_waiters != 0) {
- mutex->high_priority_waiters = 0;
os_event_set(mutex->high_priority_event);
sync_array_object_signalled();
diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h
index 82e9a90fcfb..259fcd0cf6e 100644
--- a/storage/xtradb/include/trx0trx.h
+++ b/storage/xtradb/include/trx0trx.h
@@ -1024,6 +1024,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/xtradb/include/univ.i b/storage/xtradb/include/univ.i
index c9447245124..eaf2262481c 100644
--- a/storage/xtradb/include/univ.i
+++ b/storage/xtradb/include/univ.i
@@ -44,10 +44,10 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 5
#define INNODB_VERSION_MINOR 6
-#define INNODB_VERSION_BUGFIX 14
+#define INNODB_VERSION_BUGFIX 15
#ifndef PERCONA_INNODB_VERSION
-#define PERCONA_INNODB_VERSION 62.0
+#define PERCONA_INNODB_VERSION 63.0
#endif
/* Enable UNIV_LOG_ARCHIVE in XtraDB */
diff --git a/storage/xtradb/include/ut0bh.h b/storage/xtradb/include/ut0bh.h
index 84ea6dd915a..1085736c7ab 100644
--- a/storage/xtradb/include/ut0bh.h
+++ b/storage/xtradb/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/xtradb/include/ut0bh.ic b/storage/xtradb/include/ut0bh.ic
index a604237665d..b11de5b8b3e 100644
--- a/storage/xtradb/include/ut0bh.ic
+++ b/storage/xtradb/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/xtradb/log/log0log.cc b/storage/xtradb/log/log0log.cc
index 403ceda7a10..e0b378cd98b 100644
--- a/storage/xtradb/log/log0log.cc
+++ b/storage/xtradb/log/log0log.cc
@@ -237,6 +237,86 @@ log_check_tracking_margin(
return tracked_lsn_age + lsn_advance > log_sys->max_checkpoint_age;
}
+/** 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.
@return start lsn of the log record */
@@ -253,11 +333,38 @@ log_open(
ulint dummy;
#endif /* UNIV_LOG_ARCHIVE */
ulint count = 0;
+ ulint tcount = 0;
+
+ 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);
- ut_a(len < log->buf_size / 2);
+ log_buffer_extend((len + 1) * 2);
+ }
loop:
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 */
@@ -281,21 +388,6 @@ loop:
goto loop;
}
- if (log_check_tracking_margin(len_upper_limit) && (++count < 50)) {
-
- /* This log write would violate the untracked LSN free space
- margin. Limit this to 50 retries as there might be situations
- where we have no choice but to proceed anyway, i.e. if the log
- is about to be overflown, log tracking or not. */
- mutex_exit(&(log->mutex));
-
- os_thread_sleep(10000);
-
- mutex_enter(&(log->mutex));
-
- goto loop;
- }
-
#ifdef UNIV_LOG_ARCHIVE
if (log->archiving_state != LOG_ARCH_OFF) {
@@ -320,6 +412,22 @@ loop:
}
#endif /* UNIV_LOG_ARCHIVE */
+ if (log_check_tracking_margin(len_upper_limit) &&
+ (++tcount + count < 50)) {
+
+ /* This log write would violate the untracked LSN free space
+ margin. Limit this to 50 retries as there might be situations
+ where we have no choice but to proceed anyway, i.e. if the log
+ is about to be overflown, log tracking or not. */
+ mutex_exit(&(log->mutex));
+
+ os_thread_sleep(10000);
+
+ mutex_enter(&(log->mutex));
+
+ goto loop;
+ }
+
#ifdef UNIV_LOG_DEBUG
log->old_buf_free = log->buf_free;
log->old_lsn = log->lsn;
@@ -845,6 +953,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/xtradb/log/log0online.cc b/storage/xtradb/log/log0online.cc
index 8c2bc5602a9..2e66a690fea 100644
--- a/storage/xtradb/log/log0online.cc
+++ b/storage/xtradb/log/log0online.cc
@@ -1782,7 +1782,7 @@ log_online_purge_changed_page_bitmaps(
mutex_enter(&log_bmp_sys->mutex);
}
- if (!log_online_setup_bitmap_file_range(&bitmap_files, 0, lsn)) {
+ if (!log_online_setup_bitmap_file_range(&bitmap_files, 0, LSN_MAX)) {
if (srv_track_changed_pages) {
mutex_exit(&log_bmp_sys->mutex);
}
@@ -1797,8 +1797,19 @@ log_online_purge_changed_page_bitmaps(
}
for (i = 0; i < bitmap_files.count; i++) {
- if (bitmap_files.files[i].seq_num == 0
- || bitmap_files.files[i].start_lsn >= lsn) {
+
+ /* We consider the end LSN of the current bitmap, derived from
+ the start LSN of the subsequent bitmap file, to determine
+ whether to remove the current bitmap. Note that bitmap_files
+ does not contain an entry for the bitmap past the given LSN so
+ we must check the boundary conditions as well. For example,
+ consider 1_0.xdb and 2_10.xdb and querying LSN 5. bitmap_files
+ will only contain 1_0.xdb and we must not delete it since it
+ represents LSNs 0-9. */
+ if ((i + 1 == bitmap_files.count
+ || bitmap_files.files[i + 1].seq_num == 0
+ || bitmap_files.files[i + 1].start_lsn > lsn)
+ && (lsn != LSN_MAX)) {
break;
}
diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc
index d0b833f2bba..cb4b988e46c 100644
--- a/storage/xtradb/log/log0recv.cc
+++ b/storage/xtradb/log/log0recv.cc
@@ -920,9 +920,9 @@ log_block_checksum_is_ok_or_old_format(
return(TRUE);
}
- if (srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32 ||
- srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB ||
- srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_NONE) {
+ if (srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_CRC32 ||
+ srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_INNODB ||
+ srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_STRICT_NONE) {
const char* algo = NULL;
@@ -965,8 +965,8 @@ log_block_checksum_is_ok_or_old_format(
"so we intentionally assert here.");
}
- ut_ad(srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_CRC32 ||
- srv_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_INNODB);
+ ut_ad(srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_CRC32 ||
+ srv_log_checksum_algorithm == SRV_CHECKSUM_ALGORITHM_INNODB);
if (block_checksum == LOG_NO_CHECKSUM_MAGIC ||
block_checksum == log_block_calc_checksum_crc32(block) ||
diff --git a/storage/xtradb/mtr/mtr0mtr.cc b/storage/xtradb/mtr/mtr0mtr.cc
index 02e8cbdbfcc..a4877f175a1 100644
--- a/storage/xtradb/mtr/mtr0mtr.cc
+++ b/storage/xtradb/mtr/mtr0mtr.cc
@@ -171,26 +171,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/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc
index 38eb5241da1..f1d87cab19c 100644
--- a/storage/xtradb/os/os0file.cc
+++ b/storage/xtradb/os/os0file.cc
@@ -1565,18 +1565,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) */
@@ -1933,7 +1947,7 @@ os_file_create_func(
#endif /* USE_FILE_LOCK */
if (srv_use_atomic_writes && type == OS_DATA_FILE
- && !os_file_set_atomic_writes(name, file)) {
+ && file != -1 && !os_file_set_atomic_writes(name, file)) {
*success = FALSE;
close(file);
diff --git a/storage/xtradb/os/os0thread.cc b/storage/xtradb/os/os0thread.cc
index 685e89d48be..13099e243cd 100644
--- a/storage/xtradb/os/os0thread.cc
+++ b/storage/xtradb/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
@@ -203,6 +203,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/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc
index c0d996e24ea..7a673feae9b 100644
--- a/storage/xtradb/row/row0ftsort.cc
+++ b/storage/xtradb/row/row0ftsort.cc
@@ -268,6 +268,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
@@ -315,6 +318,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);
@@ -548,6 +553,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 */
@@ -560,7 +594,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;
@@ -578,7 +611,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);
@@ -602,11 +635,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;
@@ -616,17 +645,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
@@ -674,11 +694,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]);
}
@@ -687,19 +709,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;
}
}
@@ -710,9 +723,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];
@@ -724,13 +742,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,
@@ -738,21 +756,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;
}
@@ -802,9 +817,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);
@@ -820,19 +838,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]);
}
@@ -844,6 +867,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/xtradb/row/row0log.cc b/storage/xtradb/row/row0log.cc
index 49f9eb842b1..0c5ae2d3125 100644
--- a/storage/xtradb/row/row0log.cc
+++ b/storage/xtradb/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);
}
@@ -2772,7 +2729,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;
}
@@ -2812,7 +2778,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;
}
@@ -2823,17 +2806,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)
@@ -2843,8 +2827,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:
@@ -3368,7 +3355,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,
@@ -3376,12 +3363,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/xtradb/row/row0merge.cc b/storage/xtradb/row/row0merge.cc
index 08a3ecb5732..80cda9078ff 100644
--- a/storage/xtradb/row/row0merge.cc
+++ b/storage/xtradb/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;
}
@@ -1577,12 +1601,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
@@ -1640,7 +1680,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;
}
@@ -1695,11 +1735,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);
@@ -1754,9 +1808,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 = "";
@@ -3395,6 +3455,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);
@@ -3451,6 +3512,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;
}
}
@@ -3573,6 +3638,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) {
@@ -3609,6 +3675,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/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc
index 7748bd747d9..b590a04b3e8 100644
--- a/storage/xtradb/row/row0mysql.cc
+++ b/storage/xtradb/row/row0mysql.cc
@@ -3630,7 +3630,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/xtradb/row/row0quiesce.cc b/storage/xtradb/row/row0quiesce.cc
index 79cced1c533..a59a6088ad6 100644
--- a/storage/xtradb/row/row0quiesce.cc
+++ b/storage/xtradb/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/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc
index 95ebc143e61..c68b4de1125 100644
--- a/storage/xtradb/row/row0sel.cc
+++ b/storage/xtradb/row/row0sel.cc
@@ -3225,48 +3225,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);
}
@@ -4368,6 +4398,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);
@@ -4409,6 +4447,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);
@@ -5119,6 +5165,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/xtradb/srv/srv0mon.cc b/storage/xtradb/srv/srv0mon.cc
index d98315ae9a2..ea346566e57 100644
--- a/storage/xtradb/srv/srv0mon.cc
+++ b/storage/xtradb/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/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc
index 3ddfd9ab3a4..64d2d4cc896 100644
--- a/storage/xtradb/srv/srv0start.cc
+++ b/storage/xtradb/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"
@@ -1533,6 +1536,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");
}
@@ -1798,23 +1805,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();
@@ -2629,9 +2647,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/xtradb/sync/sync0arr.cc b/storage/xtradb/sync/sync0arr.cc
index 3eed5ae47f7..9dd0259b3f9 100644
--- a/storage/xtradb/sync/sync0arr.cc
+++ b/storage/xtradb/sync/sync0arr.cc
@@ -315,9 +315,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 */
@@ -374,13 +375,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;
}
/******************************************************************//**
@@ -499,7 +499,7 @@ sync_array_cell_print(
if (type == SYNC_PRIO_MUTEX) {
fprintf(file,
- "high-priority waiters flag %lu\n",
+ "high-priority waiters count %lu\n",
(ulong) prio_mutex->high_priority_waiters);
}
@@ -566,8 +566,8 @@ sync_array_cell_print(
}
if (prio_rwlock) {
- fprintf(file, "high priority S waiters flag %lu, "
- "high priority X waiters flag %lu, "
+ fprintf(file, "high priority S waiters count %lu, "
+ "high priority X waiters count %lu, "
"wait-exclusive waiter is "
"high priority if exists: %lu\n",
prio_rwlock->high_priority_s_waiters,
@@ -1165,7 +1165,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/xtradb/sync/sync0rw.cc b/storage/xtradb/sync/sync0rw.cc
index 785e877d14c..2ff75b55cf6 100644
--- a/storage/xtradb/sync/sync0rw.cc
+++ b/storage/xtradb/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"
@@ -408,8 +409,6 @@ rw_lock_validate(
/*=============*/
prio_rw_lock_t* lock) /*!< in: rw-lock */
{
- ut_ad(lock->high_priority_s_waiters < 2);
- ut_ad(lock->high_priority_x_waiters < 2);
return(rw_lock_validate(&lock->base_lock));
}
@@ -491,26 +490,32 @@ lock_loop:
return; /* Success */
} else {
+ prio_rw_lock_t* prio_rw_lock = NULL;
+
if (i > 0 && i < SYNC_SPIN_ROUNDS) {
goto 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,
- high_priority ? PRIO_RW_LOCK_SHARED : RW_LOCK_SHARED,
- file_name, line, &index);
+ sync_arr = sync_array_get_and_reserve_cell(lock,
+ high_priority
+ ? PRIO_RW_LOCK_SHARED
+ : 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. */
if (high_priority) {
- prio_rw_lock_t* prio_rw_lock
- = (prio_rw_lock_t *) _lock;
- prio_rw_lock->high_priority_s_waiters = 1;
+
+ prio_rw_lock = reinterpret_cast<prio_rw_lock_t *>
+ (_lock);
+ os_atomic_increment_ulint(
+ &prio_rw_lock->high_priority_s_waiters,
+ 1);
} else {
+
rw_lock_set_waiter_flag(lock);
}
@@ -519,6 +524,12 @@ lock_loop:
&& (TRUE == rw_lock_s_lock_low(lock, pass,
file_name, line))) {
sync_array_free_cell(sync_arr, index);
+ if (prio_rw_lock) {
+
+ os_atomic_decrement_ulint(
+ &prio_rw_lock->high_priority_s_waiters,
+ 1);
+ }
return; /* Success */
}
@@ -536,6 +547,13 @@ lock_loop:
sync_array_wait_event(sync_arr, index);
+ if (prio_rw_lock) {
+
+ os_atomic_decrement_ulint(
+ &prio_rw_lock->high_priority_s_waiters,
+ 1);
+ }
+
i = 0;
goto lock_loop;
}
@@ -584,6 +602,7 @@ rw_lock_x_lock_wait(
ulint i = 0;
sync_array_t* sync_arr;
size_t counter_index;
+ prio_rw_lock_t* prio_rw_lock = NULL;
/* We reuse the thread id to index into the counter, cache
it here for efficiency. */
@@ -604,15 +623,14 @@ 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);
if (high_priority) {
- prio_rw_lock_t* prio_rw_lock
+ prio_rw_lock
= reinterpret_cast<prio_rw_lock_t *>(lock);
prio_rw_lock->high_priority_wait_ex_waiter = 1;
}
@@ -643,6 +661,10 @@ rw_lock_x_lock_wait(
We must pass the while-loop check to proceed.*/
} else {
sync_array_free_cell(sync_arr, index);
+ if (prio_rw_lock) {
+
+ prio_rw_lock->high_priority_wait_ex_waiter = 0;
+ }
}
}
rw_lock_stats.rw_x_spin_round_count.add(counter_index, i);
@@ -739,6 +761,7 @@ rw_lock_x_lock_func(
sync_array_t* sync_arr;
ibool spinning = FALSE;
size_t counter_index;
+ prio_rw_lock_t* prio_lock = NULL;
/* We reuse the thread id to index into the counter, cache
it here for efficiency. */
@@ -810,24 +833,31 @@ lock_loop:
}
}
- sync_arr = sync_array_get();
-
- sync_array_reserve_cell(
- sync_arr, lock,
- high_priority ? PRIO_RW_LOCK_EX : RW_LOCK_EX,
- file_name, line, &index);
+ sync_arr = sync_array_get_and_reserve_cell(lock,
+ high_priority
+ ? PRIO_RW_LOCK_EX
+ : 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. */
if (high_priority) {
- prio_rw_lock_t* prio_lock = (prio_rw_lock_t *)lock;
- prio_lock->high_priority_x_waiters = 1;
+
+ prio_lock = reinterpret_cast<prio_rw_lock_t *>(lock);
+ os_atomic_increment_ulint(&prio_lock->high_priority_x_waiters,
+ 1);
} else {
rw_lock_set_waiter_flag(lock);
}
if (rw_lock_x_lock_low(lock, high_priority, pass, file_name, line)) {
sync_array_free_cell(sync_arr, index);
+ if (prio_lock) {
+
+ os_atomic_decrement_ulint(
+ &prio_lock->high_priority_x_waiters,
+ 1);
+ }
return; /* Locking succeeded */
}
@@ -845,6 +875,12 @@ lock_loop:
sync_array_wait_event(sync_arr, index);
+ if (prio_lock) {
+
+ os_atomic_decrement_ulint(&prio_lock->high_priority_x_waiters,
+ 1);
+ }
+
i = 0;
goto lock_loop;
}
diff --git a/storage/xtradb/sync/sync0sync.cc b/storage/xtradb/sync/sync0sync.cc
index e4c34faf13d..84854892d7b 100644
--- a/storage/xtradb/sync/sync0sync.cc
+++ b/storage/xtradb/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"
@@ -126,7 +127,7 @@ it and did not see the waiters byte set to 1, a case which would lead the
other thread to an infinite wait.
LEMMA 1: After a thread resets the event of a mutex (or rw_lock), some
-=======
+======
thread will eventually call os_event_set() on that particular event.
Thus no infinite wait is possible in this case.
@@ -139,7 +140,7 @@ os_event_set() with the mutex as an argument.
Q.E.D.
LEMMA 2: If an os_event_set() call is made after some thread has called
-=======
+======
the os_event_reset() and before it starts wait on that event, the call
will not be lost to the second thread. This is true even if there is an
intervening call to os_event_reset() by another thread.
@@ -550,7 +551,8 @@ mutex_spin_wait(
/* The typecast below is performed for some of the priority mutexes
too, when !high_priority. This exploits the fact that regular mutex is
a prefix of the priority mutex in memory. */
- ib_mutex_t* mutex = (ib_mutex_t *) _mutex;
+ ib_mutex_t* mutex = (ib_mutex_t *) _mutex;
+ ib_prio_mutex_t* prio_mutex = NULL;
counter_index = (size_t) os_thread_get_curr_id();
@@ -611,11 +613,11 @@ spin_loop:
goto spin_loop;
}
- sync_arr = sync_array_get();
-
- sync_array_reserve_cell(
- sync_arr, mutex, high_priority ? SYNC_PRIO_MUTEX : SYNC_MUTEX,
- file_name, line, &index);
+ sync_arr = sync_array_get_and_reserve_cell(mutex,
+ high_priority
+ ? SYNC_PRIO_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
@@ -624,8 +626,12 @@ spin_loop:
then the event is set to the signaled state. */
if (high_priority) {
- ((ib_prio_mutex_t *)_mutex)->high_priority_waiters = 1;
+
+ prio_mutex = reinterpret_cast<ib_prio_mutex_t *>(_mutex);
+ os_atomic_increment_ulint(&prio_mutex->high_priority_waiters,
+ 1);
} else {
+
mutex_set_waiters(mutex, 1);
}
@@ -641,6 +647,11 @@ spin_loop:
mutex_set_debug_info(mutex, file_name, line);
#endif
+ if (prio_mutex) {
+ os_atomic_decrement_ulint(
+ &prio_mutex->high_priority_waiters,
+ 1);
+ }
return;
/* Note that in this case we leave the waiters field
@@ -658,6 +669,7 @@ spin_loop:
mutex->count_os_wait++;
sync_array_wait_event(sync_arr, index);
+
goto mutex_loop;
}
@@ -1216,6 +1228,7 @@ sync_thread_add_level(
case SYNC_RECV:
case SYNC_FTS_BG_THREADS:
case SYNC_WORK_QUEUE:
+ case SYNC_FTS_TOKENIZE:
case SYNC_FTS_OPTIMIZE:
case SYNC_FTS_CACHE:
case SYNC_FTS_CACHE_INIT:
diff --git a/storage/xtradb/trx/trx0purge.cc b/storage/xtradb/trx/trx0purge.cc
index 3dfcf23c3f5..9d9fe73de6e 100644
--- a/storage/xtradb/trx/trx0purge.cc
+++ b/storage/xtradb/trx/trx0purge.cc
@@ -1261,11 +1261,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/xtradb/trx/trx0sys.cc b/storage/xtradb/trx/trx0sys.cc
index b86ee90b1e9..aab99a793f6 100644
--- a/storage/xtradb/trx/trx0sys.cc
+++ b/storage/xtradb/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
@@ -891,7 +891,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/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index 432cb8f6330..8c4bc087038 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -276,6 +276,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);
@@ -557,7 +563,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);
@@ -566,6 +571,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);
}
@@ -924,7 +935,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);
}
@@ -940,7 +951,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
@@ -995,10 +1008,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) {
@@ -1052,7 +1067,12 @@ 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 */
trx_reserve_descriptor(trx);
}
@@ -1495,8 +1515,6 @@ trx_commit_in_memory(
trx->dict_operation = TRX_DICT_OP_NONE;
- ut_ad(trx_sys->descr_n_used <= UT_LIST_GET_LEN(trx_sys->rw_trx_list));
-
trx->error_state = DB_SUCCESS;
/* trx->in_mysql_trx_list would hold between
diff --git a/storage/xtradb/ut/ut0ut.cc b/storage/xtradb/ut/ut0ut.cc
index f8a1593937a..f600ba1a895 100644
--- a/storage/xtradb/ut/ut0ut.cc
+++ b/storage/xtradb/ut/ut0ut.cc
@@ -821,6 +821,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 */