summaryrefslogtreecommitdiff
path: root/storage/xtradb
diff options
context:
space:
mode:
Diffstat (limited to 'storage/xtradb')
-rw-r--r--storage/xtradb/CMakeLists.txt10
-rw-r--r--storage/xtradb/api/api0api.cc116
-rw-r--r--storage/xtradb/btr/btr0cur.cc21
-rw-r--r--storage/xtradb/buf/buf0buddy.cc54
-rw-r--r--storage/xtradb/buf/buf0buf.cc550
-rw-r--r--storage/xtradb/buf/buf0dblwr.cc126
-rw-r--r--storage/xtradb/buf/buf0flu.cc476
-rw-r--r--storage/xtradb/buf/buf0lru.cc110
-rw-r--r--storage/xtradb/dict/dict0boot.cc12
-rw-r--r--storage/xtradb/dict/dict0crea.cc8
-rw-r--r--storage/xtradb/dict/dict0dict.cc143
-rw-r--r--storage/xtradb/dict/dict0load.cc36
-rw-r--r--storage/xtradb/dict/dict0mem.cc40
-rw-r--r--storage/xtradb/dict/dict0stats.cc440
-rw-r--r--storage/xtradb/fil/fil0fil.cc240
-rw-r--r--storage/xtradb/fts/fts0ast.cc20
-rw-r--r--storage/xtradb/fts/fts0blex.cc474
-rw-r--r--storage/xtradb/fts/fts0config.cc4
-rw-r--r--storage/xtradb/fts/fts0fts.cc573
-rw-r--r--storage/xtradb/fts/fts0opt.cc10
-rw-r--r--storage/xtradb/fts/fts0pars.cc81
-rw-r--r--storage/xtradb/fts/fts0pars.y11
-rw-r--r--storage/xtradb/fts/fts0que.cc296
-rw-r--r--storage/xtradb/fts/fts0sql.cc22
-rw-r--r--storage/xtradb/fts/fts0tlex.cc101
-rw-r--r--storage/xtradb/handler/ha_innodb.cc524
-rw-r--r--storage/xtradb/handler/handler0alter.cc122
-rw-r--r--storage/xtradb/handler/i_s.cc294
-rw-r--r--storage/xtradb/ibuf/ibuf0ibuf.cc10
-rw-r--r--storage/xtradb/include/api0api.h10
-rw-r--r--storage/xtradb/include/btr0pcur.h7
-rw-r--r--storage/xtradb/include/btr0pcur.ic16
-rw-r--r--storage/xtradb/include/buf0buf.h118
-rw-r--r--storage/xtradb/include/buf0buf.ic109
-rw-r--r--storage/xtradb/include/buf0dblwr.h23
-rw-r--r--storage/xtradb/include/buf0flu.h26
-rw-r--r--storage/xtradb/include/buf0types.h4
-rw-r--r--storage/xtradb/include/db0err.h2
-rw-r--r--storage/xtradb/include/dict0dict.h26
-rw-r--r--storage/xtradb/include/dict0dict.ic27
-rw-r--r--storage/xtradb/include/dict0mem.h48
-rw-r--r--storage/xtradb/include/fil0fil.h27
-rw-r--r--storage/xtradb/include/fts0priv.h7
-rw-r--r--storage/xtradb/include/fts0priv.ic24
-rw-r--r--storage/xtradb/include/ha_prototypes.h10
-rw-r--r--storage/xtradb/include/lock0lock.h17
-rw-r--r--storage/xtradb/include/log0recv.h17
-rw-r--r--storage/xtradb/include/mem0mem.h51
-rw-r--r--storage/xtradb/include/mem0mem.ic39
-rw-r--r--storage/xtradb/include/os0file.h13
-rw-r--r--storage/xtradb/include/os0sync.h36
-rw-r--r--storage/xtradb/include/os0sync.ic6
-rw-r--r--storage/xtradb/include/page0page.h8
-rw-r--r--storage/xtradb/include/page0page.ic6
-rw-r--r--storage/xtradb/include/rem0rec.h21
-rw-r--r--storage/xtradb/include/row0log.h13
-rw-r--r--storage/xtradb/include/srv0srv.h15
-rw-r--r--storage/xtradb/include/sync0rw.h14
-rw-r--r--storage/xtradb/include/sync0rw.ic33
-rw-r--r--storage/xtradb/include/sync0sync.h1
-rw-r--r--storage/xtradb/include/sync0sync.ic11
-rw-r--r--storage/xtradb/include/trx0trx.h8
-rw-r--r--storage/xtradb/include/univ.i6
-rw-r--r--storage/xtradb/include/ut0ut.h15
-rw-r--r--storage/xtradb/lock/lock0lock.cc388
-rw-r--r--storage/xtradb/log/log0recv.cc84
-rw-r--r--storage/xtradb/mem/mem0mem.cc17
-rw-r--r--storage/xtradb/mtr/mtr0log.cc2
-rw-r--r--storage/xtradb/os/os0file.cc153
-rw-r--r--storage/xtradb/os/os0stacktrace.cc4
-rw-r--r--storage/xtradb/os/os0sync.cc4
-rw-r--r--storage/xtradb/page/page0cur.cc12
-rw-r--r--storage/xtradb/page/page0page.cc32
-rw-r--r--storage/xtradb/page/page0zip.cc187
-rw-r--r--storage/xtradb/pars/lexyy.cc54
-rw-r--r--storage/xtradb/pars/pars0pars.cc13
-rw-r--r--storage/xtradb/plugin_exports14
-rw-r--r--storage/xtradb/rem/rem0cmp.cc33
-rw-r--r--storage/xtradb/rem/rem0rec.cc11
-rw-r--r--storage/xtradb/row/row0ftsort.cc31
-rw-r--r--storage/xtradb/row/row0ins.cc6
-rw-r--r--storage/xtradb/row/row0log.cc472
-rw-r--r--storage/xtradb/row/row0mysql.cc58
-rw-r--r--storage/xtradb/row/row0quiesce.cc10
-rw-r--r--storage/xtradb/row/row0sel.cc86
-rw-r--r--storage/xtradb/row/row0uins.cc5
-rw-r--r--storage/xtradb/row/row0umod.cc15
-rw-r--r--storage/xtradb/row/row0upd.cc51
-rw-r--r--storage/xtradb/row/row0vers.cc43
-rw-r--r--storage/xtradb/srv/srv0conc.cc2
-rw-r--r--storage/xtradb/srv/srv0srv.cc21
-rw-r--r--storage/xtradb/srv/srv0start.cc55
-rw-r--r--storage/xtradb/sync/sync0arr.cc225
-rw-r--r--storage/xtradb/sync/sync0rw.cc32
-rw-r--r--storage/xtradb/sync/sync0sync.cc29
-rw-r--r--storage/xtradb/trx/trx0trx.cc52
-rw-r--r--storage/xtradb/ut/ut0ut.cc2
97 files changed, 5414 insertions, 2527 deletions
diff --git a/storage/xtradb/CMakeLists.txt b/storage/xtradb/CMakeLists.txt
index a8b2c405eab..b3751b269c3 100644
--- a/storage/xtradb/CMakeLists.txt
+++ b/storage/xtradb/CMakeLists.txt
@@ -400,16 +400,6 @@ IF(WITH_INNODB)
SET(WITH_INNOBASE_STORAGE_ENGINE TRUE)
ENDIF()
-# On solaris, reduce symbol visibility, so loader does not mix
-# the same symbols from builtin innodb and from shared one.
-# Only required for old GCC (3.4.3) that does not support hidden visibility
-IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCC
- AND NOT HAVE_VISIBILITY_HIDDEN)
- SET(LINKER_SCRIPT "-Wl,-M${CMAKE_CURRENT_SOURCE_DIR}/plugin_exports")
-ELSE()
- SET(LINKER_SCRIPT)
-ENDIF()
-
IF(XTRADB_OK)
MYSQL_ADD_PLUGIN(xtradb ${INNOBASE_SOURCES} STORAGE_ENGINE
DEFAULT
diff --git a/storage/xtradb/api/api0api.cc b/storage/xtradb/api/api0api.cc
index d2f1a468f25..bb65dd82216 100644
--- a/storage/xtradb/api/api0api.cc
+++ b/storage/xtradb/api/api0api.cc
@@ -1489,7 +1489,8 @@ ib_insert_row_with_lock_retry(
que_thr_stop_for_mysql(thr);
thr->lock_state = QUE_THR_LOCK_ROW;
- lock_wait = ib_handle_errors(&err, trx, thr, savept);
+ lock_wait = static_cast<ib_bool_t>(
+ ib_handle_errors(&err, trx, thr, savept));
thr->lock_state = QUE_THR_LOCK_NOLOCK;
} else {
lock_wait = FALSE;
@@ -1823,8 +1824,8 @@ ib_update_row_with_lock_retry(
if (err != DB_RECORD_NOT_FOUND) {
thr->lock_state = QUE_THR_LOCK_ROW;
- lock_wait = ib_handle_errors(
- &err, trx, thr, savept);
+ lock_wait = static_cast<ib_bool_t>(
+ ib_handle_errors(&err, trx, thr, savept));
thr->lock_state = QUE_THR_LOCK_NOLOCK;
} else {
@@ -1977,7 +1978,8 @@ ib_delete_row(
upd = ib_update_vector_create(cursor);
- page_format = dict_table_is_comp(index->table);
+ page_format = static_cast<ib_bool_t>(
+ dict_table_is_comp(index->table));
ib_read_tuple(rec, page_format, tuple, NULL, NULL);
upd->n_fields = ib_tuple_get_n_cols(ib_tpl);
@@ -2043,7 +2045,8 @@ ib_cursor_delete_row(
ib_bool_t page_format;
mtr_t mtr;
- page_format = dict_table_is_comp(index->table);
+ page_format = static_cast<ib_bool_t>(
+ dict_table_is_comp(index->table));
mtr_start(&mtr);
@@ -2116,7 +2119,8 @@ ib_cursor_read_row(
const rec_t* rec;
ib_bool_t page_format;
- page_format = dict_table_is_comp(tuple->index->table);
+ page_format = static_cast<ib_bool_t>(
+ dict_table_is_comp(tuple->index->table));
rec = btr_pcur_get_rec(pcur);
if (prebuilt->innodb_api_rec &&
@@ -2360,7 +2364,7 @@ ib_col_set_value(
for that. */
if (ib_col_is_capped(dtype)) {
- len = ut_min(len, col_len);
+ len = ut_min(len, static_cast<ib_ulint_t>(col_len));
if (dst == NULL || len > dfield_get_len(dfield)) {
dst = mem_heap_alloc(tuple->heap, col_len);
@@ -2421,12 +2425,12 @@ ib_col_set_value(
ut_a(pad_char != ULINT_UNDEFINED);
memset((byte*) dst + len,
- pad_char,
- col_len - len);
+ static_cast<int>(pad_char),
+ static_cast<size_t>(col_len - len));
memcpy(dst, src, len);
- len = col_len;
+ len = static_cast<ib_ulint_t>(col_len);
break;
}
case DATA_BLOB:
@@ -2467,7 +2471,7 @@ ib_col_set_value(
&error);
if (true_len < len) {
- len = true_len;
+ len = static_cast<ib_ulint_t>(true_len);
}
}
}
@@ -2508,7 +2512,7 @@ ib_col_set_value(
col_len--;
}
- len = col_len;
+ len = static_cast<ib_ulint_t>(col_len);
}
break;
}
@@ -2544,7 +2548,8 @@ ib_col_get_len(
data_len = dfield_get_len(dfield);
- return(data_len == UNIV_SQL_NULL ? IB_SQL_NULL : data_len);
+ return(static_cast<ib_ulint_t>(
+ data_len == UNIV_SQL_NULL ? IB_SQL_NULL : data_len));
}
/*****************************************************************//**
@@ -2640,7 +2645,7 @@ ib_col_copy_value_low(
data_len = IB_SQL_NULL;
}
- return(data_len);
+ return(static_cast<ib_ulint_t>(data_len));
}
/*****************************************************************//**
@@ -2750,14 +2755,15 @@ ib_col_get_meta_low(
ib_col_meta->type = static_cast<ib_col_type_t>(
dtype_get_mtype(dfield_get_type(dfield)));
- ib_col_meta->type_len = dtype_get_len(dfield_get_type(dfield));
+ ib_col_meta->type_len = static_cast<ib_u32_t>(
+ dtype_get_len(dfield_get_type(dfield)));
prtype = (ib_u16_t) dtype_get_prtype(dfield_get_type(dfield));
ib_col_meta->attr = ib_col_get_attr(prtype);
ib_col_meta->client_type = prtype & DATA_MYSQL_TYPE_MASK;
- return(data_len);
+ return(static_cast<ib_ulint_t>(data_len));
}
/*************************************************************//**
@@ -3243,10 +3249,12 @@ ib_tuple_get_n_user_cols(
const ib_tuple_t* tuple = (const ib_tuple_t*) ib_tpl;
if (tuple->type == TPL_TYPE_ROW) {
- return(dict_table_get_n_user_cols(tuple->index->table));
+ return(static_cast<ib_ulint_t>(
+ dict_table_get_n_user_cols(tuple->index->table)));
}
- return(dict_index_get_n_ordering_defined_by_user(tuple->index));
+ return(static_cast<ib_ulint_t>(
+ dict_index_get_n_ordering_defined_by_user(tuple->index)));
}
/*****************************************************************//**
@@ -3260,7 +3268,7 @@ ib_tuple_get_n_cols(
{
const ib_tuple_t* tuple = (const ib_tuple_t*) ib_tpl;
- return(dtuple_get_n_fields(tuple->ptr));
+ return(static_cast<ib_ulint_t>(dtuple_get_n_fields(tuple->ptr)));
}
/*****************************************************************//**
@@ -3563,7 +3571,9 @@ ib_tuple_write_int(
return(DB_DATA_MISMATCH);
}
- return(ib_col_set_value(ib_tpl, col_no, value, type_len, true));
+ return(ib_col_set_value(
+ ib_tpl, static_cast<ib_ulint_t>(col_no),
+ value, static_cast<ib_ulint_t>(type_len), true));
}
/*****************************************************************//**
@@ -3870,6 +3880,7 @@ ib_table_truncate(
ib_err_t trunc_err;
ib_trx_t ib_trx = NULL;
ib_crsr_t ib_crsr = NULL;
+ ib_ulint_t memcached_sync = 0;
ib_trx = ib_trx_begin(IB_TRX_SERIALIZABLE, true, false);
@@ -3885,6 +3896,14 @@ ib_table_truncate(
err = DB_TABLE_NOT_FOUND;
}
+ /* Remember the memcached_sync_count and set it to 0, so the
+ truncate can be executed. */
+ if (table != NULL && err == DB_SUCCESS) {
+ memcached_sync = static_cast<ib_ulint_t>(
+ table->memcached_sync_count);
+ table->memcached_sync_count = 0;
+ }
+
dict_mutex_exit_for_mysql();
if (err == DB_SUCCESS) {
@@ -3910,6 +3929,15 @@ ib_table_truncate(
ut_a(err == DB_SUCCESS);
}
+ /* Set the memcached_sync_count back. */
+ if (table != NULL && memcached_sync != 0) {
+ dict_mutex_enter_for_mysql();
+
+ table->memcached_sync_count = memcached_sync;
+
+ dict_mutex_exit_for_mysql();
+ }
+
return(trunc_err);
}
@@ -3972,3 +4000,51 @@ ib_cfg_get_cfg()
return(cfg_status);
}
+
+/*****************************************************************//**
+Increase/decrease the memcached sync count of table to sync memcached
+DML with SQL DDLs.
+@return DB_SUCCESS or error number */
+UNIV_INTERN
+ib_err_t
+ib_cursor_set_memcached_sync(
+/*=========================*/
+ ib_crsr_t ib_crsr, /*!< in: cursor */
+ ib_bool_t flag) /*!< in: true for increase */
+{
+ const ib_cursor_t* cursor = (const ib_cursor_t*) ib_crsr;
+ row_prebuilt_t* prebuilt = cursor->prebuilt;
+ dict_table_t* table = prebuilt->table;
+ ib_err_t err = DB_SUCCESS;
+
+ if (table != NULL) {
+ /* If memcached_sync_count is -1, means table is
+ doing DDL, we just return error. */
+ if (table->memcached_sync_count == DICT_TABLE_IN_DDL) {
+ return(DB_ERROR);
+ }
+
+ if (flag) {
+#ifdef HAVE_ATOMIC_BUILTINS
+ os_atomic_increment_lint(&table->memcached_sync_count, 1);
+#else
+ dict_mutex_enter_for_mysql();
+ ++table->memcached_sync_count;
+ dict_mutex_exit_for_mysql();
+#endif
+ } else {
+#ifdef HAVE_ATOMIC_BUILTINS
+ os_atomic_decrement_lint(&table->memcached_sync_count, 1);
+#else
+ dict_mutex_enter_for_mysql();
+ --table->memcached_sync_count;
+ dict_mutex_exit_for_mysql();
+#endif
+ ut_a(table->memcached_sync_count >= 0);
+ }
+ } else {
+ err = DB_TABLE_NOT_FOUND;
+ }
+
+ return(err);
+}
diff --git a/storage/xtradb/btr/btr0cur.cc b/storage/xtradb/btr/btr0cur.cc
index a180649fa1e..5e0473daa85 100644
--- a/storage/xtradb/btr/btr0cur.cc
+++ b/storage/xtradb/btr/btr0cur.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2012, Facebook Inc.
@@ -2236,8 +2236,7 @@ btr_cur_optimistic_update(
contain trx id and roll ptr fields */
ulint cmpl_info,/*!< in: compiler info on secondary index
updates */
- que_thr_t* thr, /*!< in: query thread, or NULL if
- appropriate flags are set */
+ que_thr_t* thr, /*!< in: query thread */
trx_id_t trx_id, /*!< in: transaction id */
mtr_t* mtr) /*!< in/out: mini-transaction; if this
is a secondary index, the caller must
@@ -2537,8 +2536,7 @@ btr_cur_pessimistic_update(
the values in update vector have no effect */
ulint cmpl_info,/*!< in: compiler info on secondary index
updates */
- que_thr_t* thr, /*!< in: query thread, or NULL if
- appropriate flags are set */
+ que_thr_t* thr, /*!< in: query thread */
trx_id_t trx_id, /*!< in: transaction id */
mtr_t* mtr) /*!< in/out: mini-transaction; must be
committed before latching any further pages */
@@ -3104,10 +3102,7 @@ btr_cur_del_mark_set_clust_rec(
trx = thr_get_trx(thr);
if (dict_index_is_online_ddl(index)) {
- row_log_table_delete(
- rec, index, offsets, false,
- trx_read_trx_id(row_get_trx_id_offset(index, offsets)
- + rec));
+ row_log_table_delete(rec, index, offsets, NULL);
}
row_upd_rec_sys_fields(rec, page_zip, index, offsets, trx, roll_ptr);
@@ -4715,7 +4710,7 @@ btr_store_big_rec_extern_fields(
c_stream.next_in = (Bytef*)
big_rec_vec->fields[i].data;
- c_stream.avail_in = extern_len;
+ c_stream.avail_in = static_cast<uInt>(extern_len);
}
for (;;) {
@@ -4806,7 +4801,7 @@ alloc_another:
c_stream.next_out = page
+ FIL_PAGE_DATA;
c_stream.avail_out
- = page_zip_get_size(page_zip)
+ = static_cast<uInt>(page_zip_get_size(page_zip))
- FIL_PAGE_DATA;
err = deflate(&c_stream, Z_FINISH);
@@ -5469,7 +5464,7 @@ btr_copy_zblob_prefix(
z_stream d_stream;
d_stream.next_out = buf;
- d_stream.avail_out = len;
+ d_stream.avail_out = static_cast<uInt>(len);
d_stream.next_in = Z_NULL;
d_stream.avail_in = 0;
@@ -5531,7 +5526,7 @@ btr_copy_zblob_prefix(
}
d_stream.next_in = bpage->zip.data + offset;
- d_stream.avail_in = zip_size - offset;
+ d_stream.avail_in = static_cast<uInt>(zip_size - offset);
err = inflate(&d_stream, Z_NO_FLUSH);
switch (err) {
diff --git a/storage/xtradb/buf/buf0buddy.cc b/storage/xtradb/buf/buf0buddy.cc
index 3f8f339a81a..8f6be0cf2af 100644
--- a/storage/xtradb/buf/buf0buddy.cc
+++ b/storage/xtradb/buf/buf0buddy.cc
@@ -131,7 +131,7 @@ buf_buddy_stamp_free(
buf_buddy_free_t* buf, /*!< in/out: block to stamp */
ulint i) /*!< in: block size */
{
- ut_d(memset(buf, i, BUF_BUDDY_LOW << i));
+ ut_d(memset(buf, static_cast<int>(i), BUF_BUDDY_LOW << i));
buf_buddy_mem_invalid(buf, i);
mach_write_to_4(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET,
BUF_BUDDY_STAMP_FREE);
@@ -545,10 +545,8 @@ buf_buddy_relocate(
{
buf_page_t* bpage;
const ulint size = BUF_BUDDY_LOW << i;
- ib_mutex_t* mutex;
ulint space;
ulint offset;
- prio_rw_lock_t* hash_lock;
ut_ad(mutex_own(&buf_pool->zip_free_mutex));
ut_ad(!mutex_own(&buf_pool->zip_mutex));
@@ -570,8 +568,13 @@ buf_buddy_relocate(
ut_ad(space != BUF_BUDDY_STAMP_FREE);
mutex_exit(&buf_pool->zip_free_mutex);
- /* Lock page hash to prevent a relocation for the target page */
- bpage = buf_page_hash_get_s_locked(buf_pool, space, offset, &hash_lock);
+
+ ulint fold = buf_page_address_fold(space, offset);
+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
+
+ rw_lock_x_lock(hash_lock);
+
+ bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
if (!bpage || bpage->zip.data != src) {
/* The block has probably been freshly
@@ -579,9 +582,8 @@ buf_buddy_relocate(
added to buf_pool->page_hash yet. Obviously,
it cannot be relocated. */
- if (bpage) {
- rw_lock_s_unlock(hash_lock);
- }
+ rw_lock_x_unlock(hash_lock);
+
mutex_enter(&buf_pool->zip_free_mutex);
return(false);
}
@@ -592,7 +594,8 @@ buf_buddy_relocate(
For the sake of simplicity, give up. */
ut_ad(page_zip_get_size(&bpage->zip) < size);
- rw_lock_s_unlock(hash_lock);
+ rw_lock_x_unlock(hash_lock);
+
mutex_enter(&buf_pool->zip_free_mutex);
return(false);
}
@@ -601,31 +604,44 @@ buf_buddy_relocate(
contain uninitialized data. */
UNIV_MEM_ASSERT_W(src, size);
- mutex = buf_page_get_mutex(bpage);
-
- mutex_enter(mutex);
+ ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
- rw_lock_s_unlock(hash_lock);
+ mutex_enter(block_mutex);
mutex_enter(&buf_pool->zip_free_mutex);
if (buf_page_can_relocate(bpage)) {
/* Relocate the compressed page. */
- ullint usec = ut_time_us(NULL);
+ ullint usec = ut_time_us(NULL);
+
ut_a(bpage->zip.data == src);
- memcpy(dst, src, size);
- bpage->zip.data = (page_zip_t*) dst;
- mutex_exit(mutex);
+
+ /* Note: This is potentially expensive, we need a better
+ solution here. We go with correctness for now. */
+ ::memcpy(dst, src, size);
+
+ bpage->zip.data = reinterpret_cast<page_zip_t*>(dst);
+
+ rw_lock_x_unlock(hash_lock);
+
+ mutex_exit(block_mutex);
+
buf_buddy_mem_invalid(
reinterpret_cast<buf_buddy_free_t*>(src), i);
buf_buddy_stat_t* buddy_stat = &buf_pool->buddy_stat[i];
- buddy_stat->relocated++;
+
+ ++buddy_stat->relocated;
+
buddy_stat->relocated_usec += ut_time_us(NULL) - usec;
+
return(true);
}
- mutex_exit(mutex);
+ rw_lock_x_unlock(hash_lock);
+
+ mutex_exit(block_mutex);
+
return(false);
}
diff --git a/storage/xtradb/buf/buf0buf.cc b/storage/xtradb/buf/buf0buf.cc
index 2ec25491f4c..27e2af20298 100644
--- a/storage/xtradb/buf/buf0buf.cc
+++ b/storage/xtradb/buf/buf0buf.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -495,6 +495,26 @@ buf_block_alloc(
#endif /* !UNIV_HOTBACKUP */
/********************************************************************//**
+Checks if a page is all zeroes.
+@return TRUE if the page is all zeroes */
+bool
+buf_page_is_zeroes(
+/*===============*/
+ const byte* read_buf, /*!< in: a database page */
+ const ulint zip_size) /*!< in: size of compressed page;
+ 0 for uncompressed pages */
+{
+ const ulint page_size = zip_size ? zip_size : UNIV_PAGE_SIZE;
+
+ for (ulint i = 0; i < page_size; i++) {
+ if (read_buf[i] != 0) {
+ return(false);
+ }
+ }
+ return(true);
+}
+
+/********************************************************************//**
Checks if a page is corrupt.
@return TRUE if corrupted */
UNIV_INTERN
@@ -576,8 +596,11 @@ buf_page_is_corrupted(
if (checksum_field1 == 0 && checksum_field2 == 0
&& mach_read_from_4(read_buf + FIL_PAGE_LSN) == 0) {
/* make sure that the page is really empty */
- ut_d(for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) {
- ut_a(read_buf[i] == 0); });
+ for (ulint i = 0; i < UNIV_PAGE_SIZE; i++) {
+ if (read_buf[i] != 0) {
+ return(TRUE);
+ }
+ }
return(FALSE);
}
@@ -1319,8 +1342,8 @@ buf_pool_init_instance(
/* Number of locks protecting page_hash must be a
power of two */
- srv_n_page_hash_locks =
- ut_2_power_up(srv_n_page_hash_locks);
+ srv_n_page_hash_locks = static_cast<ulong>(
+ ut_2_power_up(srv_n_page_hash_locks));
ut_a(srv_n_page_hash_locks != 0);
ut_a(srv_n_page_hash_locks <= MAX_PAGE_HASH_LOCKS);
@@ -1650,16 +1673,19 @@ buf_pool_watch_set(
bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
- if (UNIV_LIKELY_NULL(bpage)) {
+ if (bpage != NULL) {
page_found:
if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) {
/* The page was loaded meanwhile. */
return(bpage);
}
+
/* Add to an existing watch. */
- mutex_enter(&buf_pool->zip_mutex);
- bpage->buf_fix_count++;
- mutex_exit(&buf_pool->zip_mutex);
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_increment_uint32(&bpage->buf_fix_count, 1);
+#else
+ ++bpage->buf_fix_count;
+#endif /* PAGE_ATOMIC_REF_COUNT */
return(NULL);
}
@@ -1704,8 +1730,8 @@ page_found:
mutex_enter(&buf_pool->zip_mutex);
bpage->state = BUF_BLOCK_ZIP_PAGE;
- bpage->space = space;
- bpage->offset = offset;
+ bpage->space = static_cast<ib_uint32_t>(space);
+ bpage->offset = static_cast<ib_uint32_t>(offset);
bpage->buf_fix_count = 1;
mutex_exit(&buf_pool->zip_mutex);
@@ -1782,31 +1808,32 @@ buf_pool_watch_unset(
buf_page_t* bpage;
buf_pool_t* buf_pool = buf_pool_get(space, offset);
ulint fold = buf_page_address_fold(space, offset);
- prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool,
- fold);
+ prio_rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
rw_lock_x_lock(hash_lock);
- bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
- /* The page must exist because buf_pool_watch_set()
- increments buf_fix_count. */
- ut_a(bpage);
+ /* The page must exist because buf_pool_watch_set() increments
+ buf_fix_count. */
- if (UNIV_UNLIKELY(!buf_pool_watch_is_sentinel(buf_pool, bpage))) {
- ib_mutex_t* mutex = buf_page_get_mutex(bpage);
+ bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
- mutex_enter(mutex);
- ut_a(bpage->buf_fix_count > 0);
- bpage->buf_fix_count--;
- mutex_exit(mutex);
+ if (!buf_pool_watch_is_sentinel(buf_pool, bpage)) {
+ buf_block_unfix(reinterpret_cast<buf_block_t*>(bpage));
} else {
- ut_a(bpage->buf_fix_count > 0);
- mutex_enter(&buf_pool->zip_mutex);
- if (UNIV_LIKELY(!--bpage->buf_fix_count)) {
+ ut_ad(bpage->buf_fix_count > 0);
+
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_decrement_uint32(&bpage->buf_fix_count, 1);
+#else
+ --bpage->buf_fix_count;
+#endif /* PAGE_ATOMIC_REF_COUNT */
+
+ if (bpage->buf_fix_count == 0) {
+ mutex_enter(&buf_pool->zip_mutex);
buf_pool_watch_remove(buf_pool, fold, bpage);
+ mutex_exit(&buf_pool->zip_mutex);
}
- mutex_exit(&buf_pool->zip_mutex);
}
rw_lock_x_unlock(hash_lock);
@@ -1833,10 +1860,10 @@ buf_pool_watch_occurred(
rw_lock_s_lock(hash_lock);
- bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
/* The page must exist because buf_pool_watch_set()
increments buf_fix_count. */
- ut_a(bpage);
+ bpage = buf_page_hash_get_low(buf_pool, space, offset, fold);
+
ret = !buf_pool_watch_is_sentinel(buf_pool, bpage);
rw_lock_s_unlock(hash_lock);
@@ -2093,27 +2120,32 @@ err_exit:
case BUF_BLOCK_READY_FOR_USE:
case BUF_BLOCK_MEMORY:
case BUF_BLOCK_REMOVE_HASH:
- break;
+ ut_error;
+
case BUF_BLOCK_ZIP_PAGE:
case BUF_BLOCK_ZIP_DIRTY:
block_mutex = &buf_pool->zip_mutex;
mutex_enter(block_mutex);
- bpage->buf_fix_count++;
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_increment_uint32(&bpage->buf_fix_count, 1);
+#else
+ ++bpage->buf_fix_count;
+#endif /* PAGE_ATOMIC_REF_COUNT */
goto got_block;
case BUF_BLOCK_FILE_PAGE:
/* Discard the uncompressed page frame if possible. */
if (!discard_attempted) {
rw_lock_s_unlock(hash_lock);
- buf_block_try_discard_uncompressed(space,
- offset);
+ buf_block_try_discard_uncompressed(space, offset);
discard_attempted = TRUE;
goto lookup;
}
block_mutex = &((buf_block_t*) bpage)->mutex;
+
mutex_enter(block_mutex);
- buf_block_buf_fix_inc((buf_block_t*) bpage,
- __FILE__, __LINE__);
+
+ buf_block_buf_fix_inc((buf_block_t*) bpage, __FILE__, __LINE__);
goto got_block;
}
@@ -2126,7 +2158,7 @@ got_block:
rw_lock_s_unlock(hash_lock);
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
ut_a(!bpage->file_page_was_freed);
-#endif
+#endif /* defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG */
buf_page_set_accessed(bpage);
@@ -2451,7 +2483,7 @@ buf_block_is_uncompressed(
const buf_block_t* block) /*!< in: pointer to block,
not dereferenced */
{
- if (UNIV_UNLIKELY((((ulint) block) % sizeof *block) != 0)) {
+ if ((((ulint) block) % sizeof *block) != 0) {
/* The pointer should be aligned. */
return(FALSE);
}
@@ -2481,6 +2513,70 @@ buf_debug_execute_is_force_flush()
}
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
+/**
+Wait for the block to be read in.
+@param block The block to check
+@param trx Transaction to account the I/Os to */
+static
+void
+buf_wait_for_read(buf_block_t* block, trx_t* trx)
+{
+ /* Note: For the PAGE_ATOMIC_REF_COUNT case:
+
+ We are using the block->lock to check for IO state (and a dirty read).
+ We set the IO_READ state under the protection of the hash_lock
+ (and block->mutex). This is safe because another thread can only
+ access the block (and check for IO state) after the block has been
+ added to the page hashtable. */
+
+ if (buf_block_get_io_fix_unlocked(block) == BUF_IO_READ) {
+
+ ib_uint64_t start_time;
+ ulint sec;
+ ulint ms;
+
+ /* Wait until the read operation completes */
+
+ ib_mutex_t* mutex = buf_page_get_mutex(&block->page);
+
+ if (UNIV_UNLIKELY(trx && trx->take_stats))
+ {
+ ut_usectime(&sec, &ms);
+ start_time = (ib_uint64_t)sec * 1000000 + ms;
+ } else {
+ start_time = 0;
+ }
+
+ for (;;) {
+ buf_io_fix io_fix;
+
+ mutex_enter(mutex);
+
+ io_fix = buf_block_get_io_fix(block);
+
+ mutex_exit(mutex);
+
+ if (io_fix == BUF_IO_READ) {
+ /* Wait by temporaly s-latch */
+ rw_lock_s_lock(&block->lock);
+ rw_lock_s_unlock(&block->lock);
+ } else {
+ break;
+ }
+ }
+
+ if (UNIV_UNLIKELY(start_time != 0))
+ {
+ ut_usectime(&sec, &ms);
+ ib_uint64_t finish_time
+ = (ib_uint64_t)sec * 1000000 + ms;
+ trx->io_reads_wait_timer
+ += (ulint)(finish_time - start_time);
+ }
+
+ }
+}
+
/********************************************************************//**
This is the general function used to get access to a database page.
@return pointer to the block or NULL */
@@ -2505,15 +2601,11 @@ buf_page_get_gen(
ulint fold;
unsigned access_time;
ulint fix_type;
- ibool must_read;
prio_rw_lock_t* hash_lock;
- ib_mutex_t* block_mutex;
ulint retries = 0;
trx_t* trx = NULL;
- ulint sec;
- ulint ms;
- ib_uint64_t start_time;
- ib_uint64_t finish_time;
+ buf_block_t* fix_block;
+ ib_mutex_t* fix_mutex = NULL;
buf_pool_t* buf_pool = buf_pool_get(space, offset);
ut_ad(mtr);
@@ -2553,7 +2645,9 @@ loop:
block = guess;
rw_lock_s_lock(hash_lock);
- if (block) {
+
+ if (block != NULL) {
+
/* If the guess is a compressed page descriptor that
has been allocated by buf_page_alloc_descriptor(),
it may have been freed by buf_relocate(). */
@@ -2591,10 +2685,10 @@ loop:
if (UNIV_LIKELY_NULL(block)) {
/* We can release hash_lock after we
- acquire block_mutex to make sure that
- no state change takes place. */
- block_mutex = buf_page_get_mutex(&block->page);
- mutex_enter(block_mutex);
+ increment the fix count to make
+ sure that no state change takes place. */
+ fix_block = block;
+ buf_block_fix(fix_block);
/* Now safe to release page_hash mutex */
rw_lock_x_unlock(hash_lock);
@@ -2649,48 +2743,60 @@ loop:
ut_a(++buf_dbg_counter % 5771 || buf_validate());
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
goto loop;
+ } else {
+ fix_block = block;
}
-
- /* We can release hash_lock after we acquire block_mutex to
- make sure that no state change takes place. */
- block_mutex = buf_page_get_mutex(&block->page);
- mutex_enter(block_mutex);
+ buf_block_fix(fix_block);
/* Now safe to release page_hash mutex */
rw_lock_s_unlock(hash_lock);
got_block:
+
+ fix_mutex = buf_page_get_mutex(&fix_block->page);
+
ut_ad(page_zip_get_size(&block->page.zip) == zip_size);
- ut_ad(mutex_own(block_mutex));
- must_read = buf_block_get_io_fix(block) == BUF_IO_READ;
+ if (mode == BUF_GET_IF_IN_POOL || mode == BUF_PEEK_IF_IN_POOL) {
- if (must_read && (mode == BUF_GET_IF_IN_POOL
- || mode == BUF_PEEK_IF_IN_POOL)) {
+ bool must_read;
- /* The page is being read to buffer pool,
- but we cannot wait around for the read to
- complete. */
-null_exit:
- mutex_exit(block_mutex);
+ {
+ buf_page_t* fix_page = &fix_block->page;
- return(NULL);
+ mutex_enter(fix_mutex);
+
+ buf_io_fix io_fix = buf_page_get_io_fix(fix_page);
+
+ must_read = (io_fix == BUF_IO_READ);
+
+ mutex_exit(fix_mutex);
+ }
+
+ if (must_read) {
+ /* The page is being read to buffer pool,
+ but we cannot wait around for the read to
+ complete. */
+ buf_block_unfix(fix_block);
+
+ return(NULL);
+ }
}
- if (UNIV_UNLIKELY(block->page.is_corrupt &&
+ if (UNIV_UNLIKELY(fix_block->page.is_corrupt &&
srv_pass_corrupt_table <= 1)) {
- mutex_exit(block_mutex);
+ buf_block_unfix(fix_block);
return(NULL);
}
- switch (buf_block_get_state(block)) {
+ switch(buf_block_get_state(fix_block)) {
buf_page_t* bpage;
case BUF_BLOCK_FILE_PAGE:
- ut_ad(block_mutex != &buf_pool->zip_mutex);
+ ut_ad(fix_mutex != &buf_pool->zip_mutex);
break;
case BUF_BLOCK_ZIP_PAGE:
@@ -2700,19 +2806,24 @@ null_exit:
adaptive hash index. There cannot be an
adaptive hash index for a compressed-only
page, so do not bother decompressing the page. */
- goto null_exit;
+ buf_block_unfix(fix_block);
+
+ return(NULL);
}
bpage = &block->page;
- ut_ad(block_mutex == &buf_pool->zip_mutex);
+ ut_ad(fix_mutex == &buf_pool->zip_mutex);
+
+ /* Note: We have already buffer fixed this block. */
+ if (bpage->buf_fix_count > 1
+ || buf_page_get_io_fix_unlocked(bpage) != BUF_IO_NONE) {
- if (bpage->buf_fix_count
- || buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
/* This condition often occurs when the buffer
is not buffer-fixed, but I/O-fixed by
buf_page_init_for_read(). */
- mutex_exit(&buf_pool->zip_mutex);
-wait_until_unfixed:
+
+ buf_block_unfix(fix_block);
+
/* The block is buffer-fixed or I/O-fixed.
Try again later. */
os_thread_sleep(WAIT_FOR_READ);
@@ -2723,24 +2834,34 @@ wait_until_unfixed:
/* Buffer-fix the block so that it cannot be evicted
or relocated while we are attempting to allocate an
uncompressed page. */
- bpage->buf_fix_count++;
/* Allocate an uncompressed page. */
- mutex_exit(&buf_pool->zip_mutex);
+
block = buf_LRU_get_free_block(buf_pool);
- ut_a(block);
mutex_enter(&buf_pool->LRU_list_mutex);
rw_lock_x_lock(hash_lock);
+
/* Buffer-fixing prevents the page_hash from changing. */
ut_ad(bpage == buf_page_hash_get_low(
buf_pool, space, offset, fold));
- mutex_enter(&block->mutex);
+ buf_block_mutex_enter(block);
+
mutex_enter(&buf_pool->zip_mutex);
- if (--bpage->buf_fix_count
+ ut_ad(fix_block->page.buf_fix_count > 0);
+
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_decrement_uint32(&fix_block->page.buf_fix_count, 1);
+#else
+ --fix_block->page.buf_fix_count;
+#endif /* PAGE_ATOMIC_REF_COUNT */
+
+ fix_block = block;
+
+ if (bpage->buf_fix_count > 0
|| buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
mutex_exit(&buf_pool->zip_mutex);
@@ -2753,23 +2874,31 @@ wait_until_unfixed:
buf_LRU_block_free_non_file_page(block);
mutex_exit(&buf_pool->LRU_list_mutex);
rw_lock_x_unlock(hash_lock);
- mutex_exit(&block->mutex);
+ buf_block_mutex_exit(block);
- goto wait_until_unfixed;
+ /* Try again */
+ goto loop;
}
/* Move the compressed page from bpage to block,
and uncompress it. */
+ /* Note: this is the uncompressed block and it is not
+ accessible by other threads yet because it is not in
+ any list or hash table */
buf_relocate(bpage, &block->page);
+
buf_block_init_low(block);
+
+ /* Set after relocate(). */
+ block->page.buf_fix_count = 1;
+
block->lock_hash_val = lock_rec_hash(space, offset);
UNIV_MEM_DESC(&block->page.zip.data,
- page_zip_get_size(&block->page.zip));
+ page_zip_get_size(&block->page.zip));
- if (buf_page_get_state(&block->page)
- == BUF_BLOCK_ZIP_PAGE) {
+ if (buf_page_get_state(&block->page) == BUF_BLOCK_ZIP_PAGE) {
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
UT_LIST_REMOVE(list, buf_pool->zip_clean,
&block->page);
@@ -2777,8 +2906,7 @@ wait_until_unfixed:
ut_ad(!block->page.in_flush_list);
} else {
/* Relocate buf_pool->flush_list. */
- buf_flush_relocate_on_flush_list(bpage,
- &block->page);
+ buf_flush_relocate_on_flush_list(bpage, &block->page);
}
/* Buffer-fix, I/O-fix, and X-latch the block
@@ -2791,7 +2919,6 @@ wait_until_unfixed:
mutex_exit(&buf_pool->LRU_list_mutex);
- block->page.buf_fix_count = 1;
buf_block_set_io_fix(block, BUF_IO_READ);
rw_lock_x_lock_inline(&block->lock, 0, file, line);
@@ -2801,10 +2928,12 @@ wait_until_unfixed:
os_atomic_increment_ulint(&buf_pool->n_pend_unzip, 1);
- access_time = buf_page_is_accessed(&block->page);
- mutex_exit(&block->mutex);
mutex_exit(&buf_pool->zip_mutex);
+ access_time = buf_page_is_accessed(&block->page);
+
+ buf_block_mutex_exit(block);
+
buf_page_free_descriptor(bpage);
/* Decompress the page while not holding
@@ -2813,9 +2942,12 @@ wait_until_unfixed:
/* Page checksum verification is already done when
the page is read from disk. Hence page checksum
verification is not necessary when decompressing the page. */
- ut_a(buf_zip_decompress(block, FALSE));
+ {
+ bool success = buf_zip_decompress(block, FALSE);
+ ut_a(success);
+ }
- if (UNIV_LIKELY(!recv_no_ibuf_operations)) {
+ if (!recv_no_ibuf_operations) {
if (access_time) {
#ifdef UNIV_IBUF_COUNT_DEBUG
ut_a(ibuf_count_get(space, offset) == 0);
@@ -2827,10 +2959,14 @@ wait_until_unfixed:
}
/* Unfix and unlatch the block. */
- mutex_enter(&block->mutex);
- block->page.buf_fix_count--;
- buf_block_set_io_fix(block, BUF_IO_NONE);
+ buf_block_mutex_enter(fix_block);
+
+ buf_block_set_io_fix(fix_block, BUF_IO_NONE);
+
+ buf_block_mutex_exit(fix_block);
+
os_atomic_decrement_ulint(&buf_pool->n_pend_unzip, 1);
+
rw_lock_x_unlock(&block->lock);
break;
@@ -2844,39 +2980,45 @@ wait_until_unfixed:
break;
}
+ ut_ad(block == fix_block);
+ ut_ad(fix_block->page.buf_fix_count > 0);
+
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX));
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED));
#endif /* UNIV_SYNC_DEBUG */
- ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+ ut_ad(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE);
#if UNIV_WORD_SIZE == 4
/* On 32-bit systems, there is no padding in buf_page_t. On
other systems, Valgrind could complain about uninitialized pad
bytes. */
- UNIV_MEM_ASSERT_RW(&block->page, sizeof block->page);
+ UNIV_MEM_ASSERT_RW(&fix_block->page, sizeof(fix_block->page));
#endif
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
if ((mode == BUF_GET_IF_IN_POOL || mode == BUF_GET_IF_IN_POOL_OR_WATCH)
&& (ibuf_debug || buf_debug_execute_is_force_flush())) {
+
/* Try to evict the block from the buffer pool, to use the
insert buffer (change buffer) as much as possible. */
- /* To obey the latching order, release the
- block->mutex before acquiring buf_pool->LRU_list_mutex. Protect
- the block from changes by temporarily buffer-fixing it
- for the time we are not holding block->mutex. */
-
- buf_block_buf_fix_inc(block, file, line);
- mutex_exit(&block->mutex);
mutex_enter(&buf_pool->LRU_list_mutex);
- mutex_enter(&block->mutex);
- buf_block_buf_fix_dec(block);
- if (buf_LRU_free_page(&block->page, true)) {
- mutex_exit(&block->mutex);
+ buf_block_unfix(fix_block);
+
+ /* Now we are only holding the buf_pool->LRU_list_mutex,
+ not block->mutex or hash_lock. Blocks cannot be
+ relocated or enter or exit the buf_pool while we
+ are holding the buf_pool->LRU_list_mutex. */
+
+ fix_mutex = buf_page_get_mutex(&fix_block->page);
+ mutex_enter(fix_mutex);
+
+ if (buf_LRU_free_page(&fix_block->page, true)) {
+
+ mutex_exit(fix_mutex);
rw_lock_x_lock(hash_lock);
if (mode == BUF_GET_IF_IN_POOL_OR_WATCH) {
@@ -2892,7 +3034,7 @@ wait_until_unfixed:
rw_lock_x_unlock(hash_lock);
- if (UNIV_LIKELY_NULL(block)) {
+ if (block != NULL) {
/* Either the page has been read in or
a watch was set on that in the window
where we released the buf_pool::mutex
@@ -2906,111 +3048,108 @@ wait_until_unfixed:
"innodb_change_buffering_debug evict %u %u\n",
(unsigned) space, (unsigned) offset);
return(NULL);
- } else {
-
- mutex_exit(&buf_pool->LRU_list_mutex);
}
- if (buf_flush_page_try(buf_pool, block)) {
+ if (buf_flush_page_try(buf_pool, fix_block)) {
fprintf(stderr,
"innodb_change_buffering_debug flush %u %u\n",
(unsigned) space, (unsigned) offset);
- guess = block;
+ guess = fix_block;
goto loop;
}
+ mutex_exit(&buf_pool->LRU_list_mutex);
+
+ buf_block_mutex_exit(fix_block);
+
+ buf_block_fix(fix_block);
+
/* Failed to evict the page; change it directly */
}
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
- buf_block_buf_fix_inc(block, file, line);
+ ut_ad(fix_block->page.buf_fix_count > 0);
+
+#ifdef UNIV_SYNC_DEBUG
+ /* We have already buffer fixed the page, and we are committed to
+ returning this page to the caller. Register for debugging. */
+ {
+ ibool ret;
+ ret = rw_lock_s_lock_nowait(&fix_block->debug_latch, file, line);
+ ut_a(ret);
+ }
+#endif /* UNIV_SYNC_DEBUG */
+
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
ut_a(mode == BUF_GET_POSSIBLY_FREED
- || !block->page.file_page_was_freed);
+ || !fix_block->page.file_page_was_freed);
#endif
/* Check if this is the first access to the page */
- access_time = buf_page_is_accessed(&block->page);
+ access_time = buf_page_is_accessed(&fix_block->page);
- buf_page_set_accessed(&block->page);
+ /* This is a heuristic and we don't care about ordering issues. */
+ if (access_time == 0) {
+ buf_block_mutex_enter(fix_block);
- mutex_exit(&block->mutex);
+ buf_page_set_accessed(&fix_block->page);
+
+ buf_block_mutex_exit(fix_block);
+ }
if (mode != BUF_PEEK_IF_IN_POOL) {
- buf_page_make_young_if_needed(&block->page);
+ buf_page_make_young_if_needed(&fix_block->page);
}
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
- ut_a(block->page.buf_fix_count > 0);
- ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
+ ut_a(fix_block->page.buf_fix_count > 0);
+ ut_a(buf_block_get_state(fix_block) == BUF_BLOCK_FILE_PAGE);
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
+#ifdef PAGE_ATOMIC_REF_COUNT
+ /* We have to wait here because the IO_READ state was set
+ under the protection of the hash_lock and the block->mutex
+ but not the block->lock. */
+ buf_wait_for_read(fix_block, trx);
+#endif /* PAGE_ATOMIC_REF_COUNT */
+
switch (rw_latch) {
case RW_NO_LATCH:
- if (must_read) {
- /* Let us wait until the read operation
- completes */
-
- if (UNIV_UNLIKELY(trx && trx->take_stats))
- {
- ut_usectime(&sec, &ms);
- start_time = (ib_uint64_t)sec * 1000000 + ms;
- } else {
- start_time = 0;
- }
- for (;;) {
- enum buf_io_fix io_fix;
- mutex_enter(&block->mutex);
- io_fix = buf_block_get_io_fix(block);
- mutex_exit(&block->mutex);
-
- if (io_fix == BUF_IO_READ) {
- /* wait by temporaly s-latch */
- rw_lock_s_lock(&(block->lock));
- rw_lock_s_unlock(&(block->lock));
- } else {
- break;
- }
- }
- if (UNIV_UNLIKELY(start_time != 0))
- {
- ut_usectime(&sec, &ms);
- finish_time = (ib_uint64_t)sec * 1000000 + ms;
- trx->io_reads_wait_timer += (ulint)(finish_time - start_time);
- }
- }
+#ifndef PAGE_ATOMIC_REF_COUNT
+ buf_wait_for_read(fix_block, trx);
+#endif /* !PAGE_ATOMIC_REF_COUNT */
fix_type = MTR_MEMO_BUF_FIX;
break;
case RW_S_LATCH:
- rw_lock_s_lock_inline(&(block->lock), 0, file, line);
+ rw_lock_s_lock_inline(&fix_block->lock, 0, file, line);
fix_type = MTR_MEMO_PAGE_S_FIX;
break;
default:
ut_ad(rw_latch == RW_X_LATCH);
- rw_lock_x_lock_inline(&(block->lock), 0, file, line);
+ rw_lock_x_lock_inline(&fix_block->lock, 0, file, line);
fix_type = MTR_MEMO_PAGE_X_FIX;
break;
}
- mtr_memo_push(mtr, block, fix_type);
+ mtr_memo_push(mtr, fix_block, fix_type);
if (mode != BUF_PEEK_IF_IN_POOL && !access_time) {
/* In the case of a first access, try to apply linear
read-ahead */
- buf_read_ahead_linear(space, zip_size, offset,
- ibuf_inside(mtr), trx);
+ buf_read_ahead_linear(
+ space, zip_size, offset, ibuf_inside(mtr), trx);
}
#ifdef UNIV_IBUF_COUNT_DEBUG
- ut_a(ibuf_count_get(buf_block_get_space(block),
- buf_block_get_page_no(block)) == 0);
+ ut_a(ibuf_count_get(buf_block_get_space(fix_block),
+ buf_block_get_page_no(fix_block)) == 0);
#endif
#ifdef UNIV_SYNC_DEBUG
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX));
@@ -3021,7 +3160,7 @@ wait_until_unfixed:
_increment_page_get_statistics(block, trx);
}
- return(block);
+ return(fix_block);
}
/********************************************************************//**
@@ -3085,9 +3224,7 @@ buf_page_optimistic_get(
}
if (UNIV_UNLIKELY(!success)) {
- mutex_enter(&block->mutex);
buf_block_buf_fix_dec(block);
- mutex_exit(&block->mutex);
return(FALSE);
}
@@ -3101,9 +3238,7 @@ buf_page_optimistic_get(
rw_lock_x_unlock(&(block->lock));
}
- mutex_enter(&block->mutex);
buf_block_buf_fix_dec(block);
- mutex_exit(&block->mutex);
return(FALSE);
}
@@ -3215,9 +3350,7 @@ buf_page_get_known_nowait(
}
if (!success) {
- mutex_enter(&block->mutex);
buf_block_buf_fix_dec(block);
- mutex_exit(&block->mutex);
return(FALSE);
}
@@ -3325,9 +3458,7 @@ buf_page_try_get_func(
}
if (!success) {
- mutex_enter(&block->mutex);
buf_block_buf_fix_dec(block);
- mutex_exit(&block->mutex);
return(NULL);
}
@@ -3425,16 +3556,23 @@ buf_page_init(
hash_page = buf_page_hash_get_low(buf_pool, space, offset, fold);
- if (UNIV_LIKELY(!hash_page)) {
+ if (hash_page == NULL) {
+ /* Block not found in the hash table */
} else if (buf_pool_watch_is_sentinel(buf_pool, hash_page)) {
- /* Preserve the reference count. */
mutex_enter(&buf_pool->zip_mutex);
- ulint buf_fix_count = hash_page->buf_fix_count;
+ ib_uint32_t buf_fix_count = hash_page->buf_fix_count;
ut_a(buf_fix_count > 0);
- block->page.buf_fix_count += buf_fix_count;
+
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_increment_uint32(
+ &block->page.buf_fix_count, buf_fix_count);
+#else
+ block->page.buf_fix_count += ulint(buf_fix_count);
+#endif /* PAGE_ATOMIC_REF_COUNT */
+
buf_pool_watch_remove(buf_pool, fold, hash_page);
mutex_exit(&buf_pool->zip_mutex);
@@ -3459,8 +3597,9 @@ buf_page_init(
ut_ad(!block->page.in_zip_hash);
ut_ad(!block->page.in_page_hash);
ut_d(block->page.in_page_hash = TRUE);
- HASH_INSERT(buf_page_t, hash, buf_pool->page_hash,
- fold, &block->page);
+
+ HASH_INSERT(buf_page_t, hash, buf_pool->page_hash, fold, &block->page);
+
if (zip_size) {
page_zip_set_size(&block->page.zip, zip_size);
}
@@ -3497,7 +3636,7 @@ buf_page_init_for_read(
prio_rw_lock_t* hash_lock;
mtr_t mtr;
ulint fold;
- ibool lru = FALSE;
+ ibool lru;
void* data;
buf_pool_t* buf_pool = buf_pool_get(space, offset);
@@ -3572,12 +3711,18 @@ err_exit:
ut_ad(buf_pool_from_bpage(bpage) == buf_pool);
buf_page_init(buf_pool, space, offset, fold, zip_size, block);
- rw_lock_x_unlock(hash_lock);
+
+#ifdef PAGE_ATOMIC_REF_COUNT
+ /* Note: We set the io state without the protection of
+ the block->lock. This is because other threads cannot
+ access this block unless it is in the hash table. */
+
+ buf_page_set_io_fix(bpage, BUF_IO_READ);
+#endif /* PAGE_ATOMIC_REF_COUNT */
/* The block must be put to the LRU list, to the old blocks */
buf_LRU_add_block(bpage, TRUE/* to old blocks */);
mutex_exit(&buf_pool->LRU_list_mutex);
- lru = TRUE;
/* We set a pass-type x-lock on the frame because then
the same thread which called for the read operation
@@ -3589,7 +3734,12 @@ err_exit:
io-handler thread. */
rw_lock_x_lock_gen(&block->lock, BUF_IO_READ);
+
+#ifndef PAGE_ATOMIC_REF_COUNT
buf_page_set_io_fix(bpage, BUF_IO_READ);
+#endif /* !PAGE_ATOMIC_REF_COUNT */
+
+ rw_lock_x_unlock(hash_lock);
if (zip_size) {
/* buf_pool->LRU_list_mutex may be released and
@@ -3628,28 +3778,24 @@ err_exit:
rw_lock_x_lock(hash_lock);
- /* If buf_buddy_alloc() allocated storage from the LRU list,
- it released and reacquired buf_pool->LRU_list_mutex. Thus, we
- must check the page_hash again, as it may have been
+ /* We must check the page_hash again, as it may have been
modified. */
- if (UNIV_UNLIKELY(lru)) {
- watch_page = buf_page_hash_get_low(
+ watch_page = buf_page_hash_get_low(
buf_pool, space, offset, fold);
- if (UNIV_UNLIKELY(watch_page
+ if (UNIV_UNLIKELY(watch_page
&& !buf_pool_watch_is_sentinel(buf_pool,
watch_page))) {
- /* The block was added by some other thread. */
- mutex_exit(&buf_pool->LRU_list_mutex);
- rw_lock_x_unlock(hash_lock);
- watch_page = NULL;
- buf_buddy_free(buf_pool, data, zip_size);
+ /* The block was added by some other thread. */
+ mutex_exit(&buf_pool->LRU_list_mutex);
+ rw_lock_x_unlock(hash_lock);
+ watch_page = NULL;
+ buf_buddy_free(buf_pool, data, zip_size);
- bpage = NULL;
- goto func_exit;
- }
+ bpage = NULL;
+ goto func_exit;
}
bpage = buf_page_alloc_descriptor();
@@ -3668,8 +3814,8 @@ err_exit:
buf_page_init_low(bpage);
bpage->state = BUF_BLOCK_ZIP_PAGE;
- bpage->space = space;
- bpage->offset = offset;
+ bpage->space = static_cast<ib_uint32_t>(space);
+ bpage->offset = static_cast<ib_uint32_t>(offset);
#ifdef UNIV_DEBUG
bpage->in_page_hash = FALSE;
@@ -3681,13 +3827,24 @@ err_exit:
ut_d(bpage->in_page_hash = TRUE);
- if (UNIV_LIKELY_NULL(watch_page)) {
+ if (watch_page != NULL) {
/* Preserve the reference count. */
- ulint buf_fix_count = watch_page->buf_fix_count;
+ ib_uint32_t buf_fix_count;
+
+ buf_fix_count = watch_page->buf_fix_count;
+
ut_a(buf_fix_count > 0);
+
ut_ad(buf_own_zip_mutex_for_page(bpage));
+
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_increment_uint32(
+ &bpage->buf_fix_count, buf_fix_count);
+#else
bpage->buf_fix_count += buf_fix_count;
+#endif /* PAGE_ATOMIC_REF_COUNT */
+
ut_ad(buf_pool_watch_is_sentinel(buf_pool, watch_page));
buf_pool_watch_remove(buf_pool, fold, watch_page);
}
@@ -3783,8 +3940,7 @@ buf_page_create(
buf_block_free(free_block);
- return(buf_page_get_with_no_latch(space, zip_size,
- offset, mtr));
+ return(buf_page_get_with_no_latch(space, zip_size, offset, mtr));
}
/* If we get here, the page was not in buf_pool: init it there */
diff --git a/storage/xtradb/buf/buf0dblwr.cc b/storage/xtradb/buf/buf0dblwr.cc
index 506a5b177ba..f4d1c637e3e 100644
--- a/storage/xtradb/buf/buf0dblwr.cc
+++ b/storage/xtradb/buf/buf0dblwr.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, 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
@@ -351,13 +351,13 @@ At a database startup initializes the doublewrite buffer memory structure if
we already have a doublewrite buffer created in the data files. If we are
upgrading to an InnoDB version which supports multiple tablespaces, then this
function performs the necessary update operations. If we are in a crash
-recovery, this function uses a possible doublewrite buffer to restore
-half-written pages in the data files. */
-UNIV_INTERN
+recovery, this function loads the pages from double write buffer into memory. */
void
-buf_dblwr_init_or_restore_pages(
-/*============================*/
- ibool restore_corrupt_pages) /*!< in: TRUE=restore pages */
+buf_dblwr_init_or_load_pages(
+/*=========================*/
+ os_file_t file,
+ char* path,
+ bool load_corrupt_pages)
{
byte* buf;
byte* read_buf;
@@ -368,8 +368,9 @@ buf_dblwr_init_or_restore_pages(
ibool reset_space_ids = FALSE;
byte* doublewrite;
ulint space_id;
- ulint page_no;
ulint i;
+ ulint block_bytes = 0;
+ recv_dblwr_t& recv_dblwr = recv_sys->dblwr;
/* We do the file i/o past the buffer pool */
@@ -380,9 +381,9 @@ buf_dblwr_init_or_restore_pages(
/* Read the trx sys header to check if we are using the doublewrite
buffer */
+ off_t trx_sys_page = TRX_SYS_PAGE_NO * UNIV_PAGE_SIZE;
+ os_file_read(file, read_buf, trx_sys_page, UNIV_PAGE_SIZE);
- fil_io(OS_FILE_READ, true, TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, 0,
- UNIV_PAGE_SIZE, read_buf, NULL);
doublewrite = read_buf + TRX_SYS_DOUBLEWRITE;
if (mach_read_from_4(doublewrite + TRX_SYS_DOUBLEWRITE_MAGIC)
@@ -416,13 +417,12 @@ buf_dblwr_init_or_restore_pages(
/* Read the pages from the doublewrite buffer to memory */
- fil_io(OS_FILE_READ, true, TRX_SYS_SPACE, 0, block1, 0,
- TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
- buf, NULL);
- fil_io(OS_FILE_READ, true, TRX_SYS_SPACE, 0, block2, 0,
- TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
- buf + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
- NULL);
+ block_bytes = TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE;
+
+ os_file_read(file, buf, block1 * UNIV_PAGE_SIZE, block_bytes);
+ os_file_read(file, buf + block_bytes, block2 * UNIV_PAGE_SIZE,
+ block_bytes);
+
/* Check if any of these pages is half-written in data files, in the
intended position */
@@ -431,13 +431,12 @@ buf_dblwr_init_or_restore_pages(
for (i = 0; i < TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * 2; i++) {
ulint source_page_no;
- page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
if (reset_space_ids) {
space_id = 0;
mach_write_to_4(page
- + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, 0);
+ + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
/* We do not need to calculate new checksums for the
pages because the field .._SPACE_ID does not affect
them. Write the page back to where we read it from. */
@@ -449,19 +448,53 @@ buf_dblwr_init_or_restore_pages(
+ i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE;
}
- fil_io(OS_FILE_WRITE, true, 0, 0, source_page_no, 0,
- UNIV_PAGE_SIZE, page, NULL);
- } else {
+ os_file_write(path, file, page,
+ source_page_no * UNIV_PAGE_SIZE,
+ UNIV_PAGE_SIZE);
- space_id = mach_read_from_4(
- page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ } else if (load_corrupt_pages) {
+
+ recv_dblwr.add(page);
}
- if (!restore_corrupt_pages) {
- /* The database was shut down gracefully: no need to
- restore pages */
+ page += UNIV_PAGE_SIZE;
+ }
+
+ if (reset_space_ids) {
+ os_file_flush(file);
+ }
+
+leave_func:
+ ut_free(unaligned_read_buf);
+}
+
+/****************************************************************//**
+Process the double write buffer pages. */
+void
+buf_dblwr_process()
+/*===============*/
+{
+ ulint space_id;
+ ulint page_no;
+ ulint page_no_dblwr = 0;
+ byte* page;
+ byte* read_buf;
+ byte* unaligned_read_buf;
+ recv_dblwr_t& recv_dblwr = recv_sys->dblwr;
+
+ unaligned_read_buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
+
+ read_buf = static_cast<byte*>(
+ ut_align(unaligned_read_buf, UNIV_PAGE_SIZE));
+
+ for (std::list<byte*>::iterator i = recv_dblwr.pages.begin();
+ i != recv_dblwr.pages.end(); ++i, ++page_no_dblwr ) {
+
+ page = *i;
+ page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
+ space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID);
- } else if (!fil_tablespace_exists_in_mem(space_id)) {
+ if (!fil_tablespace_exists_in_mem(space_id)) {
/* Maybe we have dropped the single-table tablespace
and this page once belonged to it: do nothing */
@@ -472,19 +505,8 @@ buf_dblwr_init_or_restore_pages(
"within space bounds; space id %lu "
"page number %lu, page %lu in "
"doublewrite buf.",
- (ulong) space_id, (ulong) page_no, (ulong) i);
-
- } else if (space_id == TRX_SYS_SPACE
- && ((page_no >= block1
- && page_no
- < block1 + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
- || (page_no >= block2
- && page_no
- < (block2
- + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)))) {
-
- /* It is an unwritten doublewrite buffer page:
- do nothing */
+ (ulong) space_id, (ulong) page_no,
+ page_no_dblwr);
} else {
ulint zip_size = fil_space_get_zip_size(space_id);
@@ -549,15 +571,28 @@ buf_dblwr_init_or_restore_pages(
ib_logf(IB_LOG_LEVEL_INFO,
"Recovered the page from"
" the doublewrite buffer.");
+
+ } else if (buf_page_is_zeroes(read_buf, zip_size)) {
+
+ if (!buf_page_is_zeroes(page, zip_size)
+ && !buf_page_is_corrupted(true, page,
+ zip_size)) {
+
+ /* Database page contained only
+ zeroes, while a valid copy is
+ available in dblwr buffer. */
+
+ fil_io(OS_FILE_WRITE, true, space_id,
+ zip_size, page_no, 0,
+ zip_size ? zip_size
+ : UNIV_PAGE_SIZE,
+ page, NULL);
+ }
}
}
-
- page += UNIV_PAGE_SIZE;
}
fil_flush_file_spaces(FIL_TABLESPACE);
-
-leave_func:
ut_free(unaligned_read_buf);
}
@@ -776,6 +811,7 @@ buf_dblwr_write_block_to_datafile(
fil_io(flags, sync, buf_block_get_space(block), 0,
buf_block_get_page_no(block), 0, UNIV_PAGE_SIZE,
(void*) block->frame, (void*) block);
+
}
/********************************************************************//**
diff --git a/storage/xtradb/buf/buf0flu.cc b/storage/xtradb/buf/buf0flu.cc
index a7f55eb9c79..9e8b57fe7ca 100644
--- a/storage/xtradb/buf/buf0flu.cc
+++ b/storage/xtradb/buf/buf0flu.cc
@@ -59,8 +59,12 @@ need to protect it by a mutex. It is only ever read by the thread
doing the shutdown */
UNIV_INTERN ibool buf_page_cleaner_is_active = FALSE;
+/** Flag indicating if the lru_manager is in active state. */
+UNIV_INTERN bool buf_lru_manager_is_active = false;
+
#ifdef UNIV_PFS_THREAD
UNIV_INTERN mysql_pfs_key_t buf_page_cleaner_thread_key;
+UNIV_INTERN mysql_pfs_key_t buf_lru_manager_thread_key;
#endif /* UNIV_PFS_THREAD */
/** If LRU list of a buf_pool is less than this size then LRU eviction
@@ -74,7 +78,10 @@ in thrashing. */
/** Handled page counters for a single flush */
struct flush_counters_t {
ulint flushed; /*!< number of dirty pages flushed */
- ulint evicted; /*!< number of clean pages evicted */
+ ulint evicted; /*!< number of clean pages evicted, including
+ evicted uncompressed page images */
+ ulint unzip_LRU_evicted;/*!< number of uncompressed page images
+ evicted */
};
/******************************************************************//**
@@ -503,15 +510,15 @@ buf_flush_ready_for_replace(
#ifdef UNIV_DEBUG
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
ut_ad(mutex_own(&buf_pool->LRU_list_mutex));
-#endif
+#endif /* UNIV_DEBUG */
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
ut_ad(bpage->in_LRU_list);
- if (UNIV_LIKELY(buf_page_in_file(bpage))) {
+ if (buf_page_in_file(bpage)) {
return(bpage->oldest_modification == 0
- && buf_page_get_io_fix(bpage) == BUF_IO_NONE
- && bpage->buf_fix_count == 0);
+ && bpage->buf_fix_count == 0
+ && buf_page_get_io_fix(bpage) == BUF_IO_NONE);
}
ut_print_timestamp(stderr);
@@ -539,7 +546,7 @@ buf_flush_ready_for_flush(
ut_ad(flush_type < BUF_FLUSH_N_TYPES);
ut_ad(mutex_own(buf_page_get_mutex(bpage))
|| flush_type == BUF_FLUSH_LIST);
- ut_a(buf_page_in_file(bpage));
+ ut_a(buf_page_in_file(bpage) || buf_page_get_state(bpage) == BUF_BLOCK_REMOVE_HASH);
if (bpage->oldest_modification == 0
|| buf_page_get_io_fix_unlocked(bpage) != BUF_IO_NONE) {
@@ -552,13 +559,8 @@ buf_flush_ready_for_flush(
case BUF_FLUSH_LIST:
case BUF_FLUSH_LRU:
case BUF_FLUSH_SINGLE_PAGE:
- /* Because any thread may call single page flush, even
- when owning locks on pages, to avoid deadlocks, we must
- make sure that the that it is not buffer fixed.
- The same holds true for LRU flush because a user thread
- may end up waiting for an LRU flush to end while
- holding locks on other pages. */
- return(bpage->buf_fix_count == 0);
+ return(true);
+
case BUF_FLUSH_N_TYPES:
break;
}
@@ -750,9 +752,11 @@ buf_flush_update_zip_checksum(
{
ut_a(zip_size > 0);
- ib_uint32_t checksum = page_zip_calc_checksum(
- page, zip_size,
- static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm));
+ ib_uint32_t checksum = static_cast<ib_uint32_t>(
+ page_zip_calc_checksum(
+ page, zip_size,
+ static_cast<srv_checksum_algorithm_t>(
+ srv_checksum_algorithm)));
mach_write_to_8(page + FIL_PAGE_LSN, lsn);
memset(page + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
@@ -982,9 +986,12 @@ Writes a flushable page asynchronously from the buffer pool to a file.
NOTE: in simulated aio we must call
os_aio_simulated_wake_handler_threads after we have posted a batch of
writes! NOTE: buf_page_get_mutex(bpage) must be held upon entering this
-function, and it will be released by this function. */
+function, and it will be released by this function if it returns true.
+LRU_list_mutex must be held iff performing a single page flush and will be
+released by the function if it returns true.
+@return TRUE if the page was flushed */
UNIV_INTERN
-void
+bool
buf_flush_page(
/*===========*/
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
@@ -992,111 +999,98 @@ buf_flush_page(
buf_flush_t flush_type, /*!< in: type of flush */
bool sync) /*!< in: true if sync IO request */
{
- ib_mutex_t* block_mutex;
- ibool is_uncompressed;
-
ut_ad(flush_type < BUF_FLUSH_N_TYPES);
- ut_ad(!mutex_own(&buf_pool->LRU_list_mutex));
+ /* Hold the LRU list mutex iff called for a single page LRU
+ flush. A single page LRU flush is already non-performant, and holding
+ the LRU list mutex allows us to avoid having to store the previous LRU
+ list page or to restart the LRU scan in
+ buf_flush_single_page_from_LRU(). */
+ ut_ad(flush_type == BUF_FLUSH_SINGLE_PAGE ||
+ !mutex_own(&buf_pool->LRU_list_mutex));
+ ut_ad(flush_type != BUF_FLUSH_SINGLE_PAGE ||
+ mutex_own(&buf_pool->LRU_list_mutex));
ut_ad(buf_page_in_file(bpage));
ut_ad(!sync || flush_type == BUF_FLUSH_SINGLE_PAGE);
- block_mutex = buf_page_get_mutex(bpage);
+ ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
+
ut_ad(mutex_own(block_mutex));
ut_ad(buf_flush_ready_for_flush(bpage, flush_type));
- mutex_enter(&buf_pool->flush_state_mutex);
-
- buf_page_set_io_fix(bpage, BUF_IO_WRITE);
-
- buf_page_set_flush_type(bpage, flush_type);
+ bool is_uncompressed;
- if (buf_pool->n_flush[flush_type] == 0) {
+ is_uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
+ ut_ad(is_uncompressed == (block_mutex != &buf_pool->zip_mutex));
- os_event_reset(buf_pool->no_flush[flush_type]);
- }
+ ibool flush;
+ rw_lock_t* rw_lock;
+ bool no_fix_count = bpage->buf_fix_count == 0;
- buf_pool->n_flush[flush_type]++;
+ if (!is_uncompressed) {
+ flush = TRUE;
+ rw_lock = NULL;
- mutex_exit(&buf_pool->flush_state_mutex);
+ } else if (!(no_fix_count || flush_type == BUF_FLUSH_LIST)) {
+ /* This is a heuristic, to avoid expensive S attempts. */
+ flush = FALSE;
+ } else {
- is_uncompressed = (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
- ut_ad(is_uncompressed == (block_mutex != &buf_pool->zip_mutex));
+ rw_lock = &reinterpret_cast<buf_block_t*>(bpage)->lock;
- switch (flush_type) {
- ibool is_s_latched;
- case BUF_FLUSH_LIST:
- /* If the simulated aio thread is not running, we must
- not wait for any latch, as we may end up in a deadlock:
- if buf_fix_count == 0, then we know we need not wait */
-
- is_s_latched = (bpage->buf_fix_count == 0);
- if (is_s_latched && is_uncompressed) {
- rw_lock_s_lock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_WRITE);
+ if (flush_type != BUF_FLUSH_LIST) {
+ flush = rw_lock_s_lock_gen_nowait(
+ rw_lock, BUF_IO_WRITE);
+ } else {
+ /* Will S lock later */
+ flush = TRUE;
}
+ }
- mutex_exit(block_mutex);
+ if (flush) {
- /* Even though bpage is not protected by any mutex at
- this point, it is safe to access bpage, because it is
- io_fixed and oldest_modification != 0. Thus, it
- cannot be relocated in the buffer pool or removed from
- flush_list or LRU_list. */
+ /* We are committed to flushing by the time we get here */
- if (!is_s_latched) {
- buf_dblwr_flush_buffered_writes();
+ mutex_enter(&buf_pool->flush_state_mutex);
- if (is_uncompressed) {
- rw_lock_s_lock_gen(&((buf_block_t*) bpage)
- ->lock, BUF_IO_WRITE);
- }
- }
+ buf_page_set_io_fix(bpage, BUF_IO_WRITE);
- break;
+ buf_page_set_flush_type(bpage, flush_type);
- case BUF_FLUSH_LRU:
- case BUF_FLUSH_SINGLE_PAGE:
- /* VERY IMPORTANT:
- Because any thread may call single page flush, even when
- owning locks on pages, to avoid deadlocks, we must make
- sure that the s-lock is acquired on the page without
- waiting: this is accomplished because
- buf_flush_ready_for_flush() must hold, and that requires
- the page not to be bufferfixed.
- The same holds true for LRU flush because a user thread
- may end up waiting for an LRU flush to end while
- holding locks on other pages. */
-
- if (is_uncompressed) {
- rw_lock_s_lock_gen(&((buf_block_t*) bpage)->lock,
- BUF_IO_WRITE);
+ if (buf_pool->n_flush[flush_type] == 0) {
+
+ os_event_reset(buf_pool->no_flush[flush_type]);
}
- /* Note that the s-latch is acquired before releasing the
- buf_page_get_mutex() mutex: this ensures that the latch is
- acquired immediately. */
+ ++buf_pool->n_flush[flush_type];
+
+ mutex_exit(&buf_pool->flush_state_mutex);
mutex_exit(block_mutex);
- break;
- default:
- ut_error;
- }
+ if (flush_type == BUF_FLUSH_SINGLE_PAGE)
+ mutex_exit(&buf_pool->LRU_list_mutex);
+
+ if (flush_type == BUF_FLUSH_LIST
+ && is_uncompressed
+ && !rw_lock_s_lock_gen_nowait(rw_lock, BUF_IO_WRITE)) {
+ /* avoiding deadlock possibility involves doublewrite
+ buffer, should flush it, because it might hold the
+ another block->lock. */
+ buf_dblwr_flush_buffered_writes();
- /* Even though bpage is not protected by any mutex at this
- point, it is safe to access bpage, because it is io_fixed and
- oldest_modification != 0. Thus, it cannot be relocated in the
- buffer pool or removed from flush_list or LRU_list. */
+ rw_lock_s_lock_gen(rw_lock, BUF_IO_WRITE);
+ }
-#ifdef UNIV_DEBUG
- if (buf_debug_prints) {
- fprintf(stderr,
- "Flushing %u space %u page %u\n",
- flush_type, bpage->space, bpage->offset);
- }
-#endif /* UNIV_DEBUG */
- buf_flush_write_block_low(bpage, flush_type, sync);
+ /* Even though bpage is not protected by any mutex at this
+ point, it is safe to access bpage, because it is io_fixed and
+ oldest_modification != 0. Thus, it cannot be relocated in the
+ buffer pool or removed from flush_list or LRU_list. */
+
+ buf_flush_write_block_low(bpage, flush_type, sync);
+ }
+
+ return(flush);
}
# if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
@@ -1115,15 +1109,16 @@ buf_flush_page_try(
{
ut_ad(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
ut_ad(mutex_own(&block->mutex));
+ ut_ad(mutex_own(&buf_pool->LRU_list_mutex));
if (!buf_flush_ready_for_flush(&block->page, BUF_FLUSH_SINGLE_PAGE)) {
return(FALSE);
}
- /* The following call will release the buffer pool and
- block mutex. */
- buf_flush_page(buf_pool, &block->page, BUF_FLUSH_SINGLE_PAGE, true);
- return(TRUE);
+ /* The following call will release the LRU list and
+ block mutex if successful. */
+ return(buf_flush_page(
+ buf_pool, &block->page, BUF_FLUSH_SINGLE_PAGE, true));
}
# endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
/***********************************************************//**
@@ -1199,7 +1194,6 @@ buf_flush_try_neighbors(
ulint i;
ulint low;
ulint high;
- ulint count = 0;
buf_pool_t* buf_pool = buf_pool_get(space, offset);
ut_ad(flush_type == BUF_FLUSH_LRU || flush_type == BUF_FLUSH_LIST);
@@ -1257,9 +1251,10 @@ buf_flush_try_neighbors(
high = fil_space_get_size(space);
}
+ ulint count = 0;
+
for (i = low; i < high; i++) {
- buf_page_t* bpage;
prio_rw_lock_t* hash_lock;
ib_mutex_t* block_mutex;
@@ -1281,10 +1276,10 @@ buf_flush_try_neighbors(
buf_pool = buf_pool_get(space, i);
/* We only want to flush pages from this buffer pool. */
- bpage = buf_page_hash_get_s_locked(buf_pool, space, i,
- &hash_lock);
+ buf_page_t* bpage = buf_page_hash_get_s_locked(buf_pool,
+ space, i, &hash_lock);
- if (!bpage) {
+ if (bpage == NULL) {
continue;
}
@@ -1305,19 +1300,12 @@ buf_flush_try_neighbors(
|| buf_page_is_old(bpage)) {
if (buf_flush_ready_for_flush(bpage, flush_type)
- && (i == offset || !bpage->buf_fix_count)) {
- /* We only try to flush those
- neighbors != offset where the buf fix
- count is zero, as we then know that we
- probably can latch the page without a
- semaphore wait. Semaphore waits are
- expensive because we must flush the
- doublewrite buffer before we start
- waiting. */
-
- buf_flush_page(buf_pool, bpage, flush_type, false);
- ut_ad(!mutex_own(block_mutex));
- count++;
+ && (i == offset || bpage->buf_fix_count == 0)
+ && buf_flush_page(
+ buf_pool, bpage, flush_type, false)) {
+
+ ++count;
+
continue;
}
}
@@ -1358,8 +1346,8 @@ buf_flush_page_and_try_neighbors(
ulint* count) /*!< in/out: number of pages
flushed */
{
+ ibool flushed;
ib_mutex_t* block_mutex = NULL;
- ibool flushed = FALSE;
#ifdef UNIV_DEBUG
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
#endif /* UNIV_DEBUG */
@@ -1374,21 +1362,10 @@ buf_flush_page_and_try_neighbors(
mutex_enter(block_mutex);
}
- if (UNIV_UNLIKELY(buf_page_get_state(bpage)
- == BUF_BLOCK_REMOVE_HASH)) {
-
- /* In case we don't hold the LRU list mutex, we may see a page
- that is about to be relocated on the flush list. Do not
- attempt to flush it. */
- ut_ad(flush_type == BUF_FLUSH_LIST);
- return (flushed);
- }
-
- ut_a(buf_page_in_file(bpage));
+ ut_a(buf_page_in_file(bpage)
+ || buf_page_get_state(bpage) == BUF_BLOCK_REMOVE_HASH);
if (buf_flush_ready_for_flush(bpage, flush_type)) {
- ulint space;
- ulint offset;
buf_pool_t* buf_pool;
buf_pool = buf_pool_from_bpage(bpage);
@@ -1399,8 +1376,10 @@ buf_flush_page_and_try_neighbors(
/* These fields are protected by the buf_page_get_mutex()
mutex. */
- space = buf_page_get_space(bpage);
- offset = buf_page_get_page_no(bpage);
+ /* Read the fields directly in order to avoid asserting on
+ BUF_BLOCK_REMOVE_HASH pages. */
+ ulint space = bpage->space;
+ ulint offset = bpage->offset;
if (flush_type == BUF_FLUSH_LRU) {
mutex_exit(block_mutex);
@@ -1409,11 +1388,8 @@ buf_flush_page_and_try_neighbors(
}
/* Try to flush also all the neighbors */
- *count += buf_flush_try_neighbors(space,
- offset,
- flush_type,
- *count,
- n_to_flush);
+ *count += buf_flush_try_neighbors(
+ space, offset, flush_type, *count, n_to_flush);
if (flush_type == BUF_FLUSH_LRU) {
mutex_enter(&buf_pool->LRU_list_mutex);
@@ -1421,8 +1397,12 @@ buf_flush_page_and_try_neighbors(
buf_flush_list_mutex_enter(buf_pool);
}
flushed = TRUE;
+
} else if (flush_type == BUF_FLUSH_LRU) {
mutex_exit(block_mutex);
+ flushed = FALSE;
+ } else {
+ flushed = FALSE;
}
ut_ad((flush_type == BUF_FLUSH_LRU
@@ -1531,6 +1511,7 @@ buf_flush_LRU_list_batch(
n->flushed = 0;
n->evicted = 0;
+ n->unzip_LRU_evicted = 0;
ut_ad(mutex_own(&buf_pool->LRU_list_mutex));
@@ -1574,6 +1555,7 @@ buf_flush_LRU_list_batch(
of the flushed pages then the scan becomes
O(n*n). */
if (evict) {
+
if (buf_LRU_free_page(bpage, true)) {
mutex_exit(block_mutex);
@@ -1588,19 +1570,42 @@ buf_flush_LRU_list_batch(
}
} else if (UNIV_LIKELY(!failed_acquire)) {
+ ulint space;
+ ulint offset;
+ buf_page_t* prev_bpage;
+
+ prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
+
+ /* Save the previous bpage */
+
+ if (prev_bpage != NULL) {
+ space = prev_bpage->space;
+ offset = prev_bpage->offset;
+ } else {
+ space = ULINT_UNDEFINED;
+ offset = ULINT_UNDEFINED;
+ }
+
if (buf_flush_page_and_try_neighbors(
bpage,
BUF_FLUSH_LRU, max, &n->flushed)) {
- lru_position = 0;
-
/* LRU list mutex was released.
- Restart the scan. */
- bpage = UT_LIST_GET_LAST(buf_pool->LRU);
- } else {
+ reposition the iterator. Note: the
+ prev block could have been repositioned
+ too but that should be rare. */
- bpage = UT_LIST_GET_PREV(LRU, bpage);
+ if (prev_bpage != NULL) {
+
+ ut_ad(space != ULINT_UNDEFINED);
+ ut_ad(offset != ULINT_UNDEFINED);
+
+ prev_bpage = buf_page_hash_get(
+ buf_pool, space, offset);
+ }
}
+
+ bpage = prev_bpage;
}
free_len = UT_LIST_GET_LEN(buf_pool->free);
@@ -1642,21 +1647,22 @@ buf_do_LRU_batch(
flush_counters_t* n) /*!< out: flushed/evicted page
counts */
{
- ulint count = 0;
-
if (buf_LRU_evict_from_unzip_LRU(buf_pool)) {
- count += buf_free_from_unzip_LRU_list_batch(buf_pool, max);
+ n->unzip_LRU_evicted
+ += buf_free_from_unzip_LRU_list_batch(buf_pool, max);
+ } else {
+ n->unzip_LRU_evicted = 0;
}
- if (max > count) {
- buf_flush_LRU_list_batch(buf_pool, max - count, limited_scan,
- n);
+ if (max > n->unzip_LRU_evicted) {
+ buf_flush_LRU_list_batch(buf_pool, max - n->unzip_LRU_evicted,
+ limited_scan, n);
} else {
n->evicted = 0;
n->flushed = 0;
}
- n->flushed += count;
+ n->evicted += n->unzip_LRU_evicted;
}
/*******************************************************************//**
@@ -1912,7 +1918,7 @@ buf_flush_wait_batch_end(
}
} else {
thd_wait_begin(NULL, THD_WAIT_DISKIO);
- os_event_wait(buf_pool->no_flush[type]);
+ os_event_wait(buf_pool->no_flush[type]);
thd_wait_end(NULL);
}
}
@@ -2101,9 +2107,7 @@ buf_flush_single_page_from_LRU(
{
ulint scanned;
buf_page_t* bpage;
- ib_mutex_t* block_mutex;
- ibool freed;
- bool evict_zip;
+ ibool flushed = FALSE;
mutex_enter(&buf_pool->LRU_list_mutex);
@@ -2111,18 +2115,30 @@ buf_flush_single_page_from_LRU(
bpage != NULL;
bpage = UT_LIST_GET_PREV(LRU, bpage), ++scanned) {
- block_mutex = buf_page_get_mutex(bpage);
+ ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
+
mutex_enter(block_mutex);
- if (buf_flush_ready_for_flush(bpage,
- BUF_FLUSH_SINGLE_PAGE)) {
- /* buf_flush_page() will release the block
- mutex */
- break;
+
+ if (buf_flush_ready_for_flush(bpage, BUF_FLUSH_SINGLE_PAGE)) {
+
+ /* The following call will release the LRU list
+ and block mutex. */
+
+ flushed = buf_flush_page(buf_pool, bpage,
+ BUF_FLUSH_SINGLE_PAGE, true);
+
+ if (flushed) {
+ /* buf_flush_page() will release the
+ block mutex */
+ break;
+ }
}
+
mutex_exit(block_mutex);
}
- mutex_exit(&buf_pool->LRU_list_mutex);
+ if (!flushed)
+ mutex_exit(&buf_pool->LRU_list_mutex);
MONITOR_INC_VALUE_CUMULATIVE(
MONITOR_LRU_SINGLE_FLUSH_SCANNED,
@@ -2130,13 +2146,13 @@ buf_flush_single_page_from_LRU(
MONITOR_LRU_SINGLE_FLUSH_SCANNED_PER_CALL,
scanned);
- if (!bpage) {
+ if (bpage == NULL) {
/* Can't find a single flushable page. */
return(FALSE);
}
- /* The following call will release the buf_page_get_mutex() mutex. */
- buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, true);
+
+ ibool freed = FALSE;
/* At this point the page has been written to the disk.
As we are not holding LRU list or buf_page_get_mutex() mutex therefore
@@ -2151,30 +2167,30 @@ buf_flush_single_page_from_LRU(
bpage != NULL;
bpage = UT_LIST_GET_PREV(LRU, bpage)) {
- ibool ready;
+ ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
- block_mutex = buf_page_get_mutex(bpage);
mutex_enter(block_mutex);
- ready = buf_flush_ready_for_replace(bpage);
+
+ ibool ready = buf_flush_ready_for_replace(bpage);
+
if (ready) {
+ bool evict_zip;
+
+ evict_zip = !buf_LRU_evict_from_unzip_LRU(buf_pool);;
+
+ freed = buf_LRU_free_page(bpage, evict_zip);
+
+ mutex_exit(block_mutex);
+
break;
}
- mutex_exit(block_mutex);
- }
+ mutex_exit(block_mutex);
- if (!bpage) {
- /* Can't find a single replaceable page. */
- mutex_exit(&buf_pool->LRU_list_mutex);
- return(FALSE);
}
- evict_zip = !buf_LRU_evict_from_unzip_LRU(buf_pool);;
-
- freed = buf_LRU_free_page(bpage, evict_zip);
if (!freed)
mutex_exit(&buf_pool->LRU_list_mutex);
- mutex_exit(block_mutex);
return(freed);
}
@@ -2260,9 +2276,15 @@ buf_flush_LRU_tail(void)
requested_pages[i] += lru_chunk_size;
+ /* If we failed to flush or evict this
+ instance, do not bother anymore. But take into
+ account that we might have zero flushed pages
+ because the flushing request was fully
+ satisfied by unzip_LRU evictions. */
if (requested_pages[i] >= scan_depth[i]
|| !(srv_cleaner_eviction_factor
- ? n.evicted : n.flushed)) {
+ ? n.evicted
+ : (n.flushed + n.unzip_LRU_evicted))) {
active_instance[i] = false;
remaining_instances--;
@@ -2498,7 +2520,7 @@ page_cleaner_flush_pages_if_needed(void)
}
if (last_pages && cur_lsn - last_lsn > lsn_avg_rate / 2) {
- age_factor = prev_pages / last_pages;
+ age_factor = static_cast<int>(prev_pages / last_pages);
}
MONITOR_SET(MONITOR_FLUSH_N_TO_FLUSH_REQUESTED, n_pages);
@@ -2626,7 +2648,7 @@ page_cleaner_adapt_flush_sleep_time(void)
/******************************************************************//**
page_cleaner thread tasked with flushing dirty pages from the buffer
-pools. As of now we'll have only one instance of this thread.
+pool flush lists. As of now we'll have only one instance of this thread.
@return a dummy parameter */
extern "C" UNIV_INTERN
os_thread_ret_t
@@ -2639,7 +2661,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
ulint next_loop_time = ut_time_ms() + 1000;
ulint n_flushed = 0;
ulint last_activity = srv_get_activity_count();
- ulint lru_sleep_time = srv_cleaner_max_lru_time;
+ ulint last_activity_time = ut_time_ms();
ut_ad(!srv_read_only_mode);
@@ -2660,8 +2682,8 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
- ulint flush_sleep_time;
ulint page_cleaner_sleep_time;
+ ibool server_active;
srv_current_thread_priority = srv_cleaner_thread_priority;
@@ -2674,20 +2696,20 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
page_cleaner_sleep_if_needed(next_loop_time);
}
- page_cleaner_adapt_lru_sleep_time(&lru_sleep_time);
-
- flush_sleep_time = page_cleaner_adapt_flush_sleep_time();
-
- page_cleaner_sleep_time = ut_min(lru_sleep_time,
- flush_sleep_time);
+ page_cleaner_sleep_time
+ = page_cleaner_adapt_flush_sleep_time();
next_loop_time = ut_time_ms() + page_cleaner_sleep_time;
- /* Flush pages from end of LRU if required */
- n_flushed = buf_flush_LRU_tail();
+ server_active = srv_check_activity(last_activity);
+ if (server_active
+ || ut_time_ms() - last_activity_time < 1000) {
+
+ if (server_active) {
- if (srv_check_activity(last_activity)) {
- last_activity = srv_get_activity_count();
+ last_activity = srv_get_activity_count();
+ last_activity_time = ut_time_ms();
+ }
/* Flush pages from flush_list if required */
n_flushed += page_cleaner_flush_pages_if_needed();
@@ -2778,6 +2800,74 @@ thread_exit:
OS_THREAD_DUMMY_RETURN;
}
+/******************************************************************//**
+lru_manager thread tasked with performing LRU flushes and evictions to refill
+the buffer pool free lists. As of now we'll have only one instance of this
+thread.
+@return a dummy parameter */
+extern "C" UNIV_INTERN
+os_thread_ret_t
+DECLARE_THREAD(buf_flush_lru_manager_thread)(
+/*==========================================*/
+ void* arg __attribute__((unused)))
+ /*!< in: a dummy parameter required by
+ os_thread_create */
+{
+ ulint next_loop_time = ut_time_ms() + 1000;
+ ulint lru_sleep_time = srv_cleaner_max_lru_time;
+
+#ifdef UNIV_PFS_THREAD
+ pfs_register_thread(buf_lru_manager_thread_key);
+#endif /* UNIV_PFS_THREAD */
+
+ srv_lru_manager_tid = os_thread_get_tid();
+
+ os_thread_set_priority(srv_lru_manager_tid,
+ srv_sched_priority_cleaner);
+
+#ifdef UNIV_DEBUG_THREAD_CREATION
+ fprintf(stderr, "InnoDB: lru_manager thread running, id %lu\n",
+ os_thread_pf(os_thread_get_curr_id()));
+#endif /* UNIV_DEBUG_THREAD_CREATION */
+
+ buf_lru_manager_is_active = true;
+
+ /* On server shutdown, the LRU manager thread runs through cleanup
+ phase to provide free pages for the master and purge threads. */
+ while (srv_shutdown_state == SRV_SHUTDOWN_NONE
+ || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP) {
+
+ ulint n_flushed_lru;
+
+ srv_current_thread_priority = srv_cleaner_thread_priority;
+
+ page_cleaner_sleep_if_needed(next_loop_time);
+
+ page_cleaner_adapt_lru_sleep_time(&lru_sleep_time);
+
+ next_loop_time = ut_time_ms() + lru_sleep_time;
+
+ n_flushed_lru = buf_flush_LRU_tail();
+
+ if (n_flushed_lru) {
+
+ MONITOR_INC_VALUE_CUMULATIVE(
+ MONITOR_FLUSH_BACKGROUND_TOTAL_PAGE,
+ MONITOR_FLUSH_BACKGROUND_COUNT,
+ MONITOR_FLUSH_BACKGROUND_PAGES,
+ n_flushed_lru);
+ }
+ }
+
+ buf_lru_manager_is_active = false;
+
+ /* We count the number of threads in os_thread_exit(). A created
+ thread should always use that to exit and not use return() to exit. */
+ os_thread_exit(NULL);
+
+ OS_THREAD_DUMMY_RETURN;
+}
+
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
/** Functor to validate the flush list. */
diff --git a/storage/xtradb/buf/buf0lru.cc b/storage/xtradb/buf/buf0lru.cc
index 8a6d042f4c7..3449982b1dd 100644
--- a/storage/xtradb/buf/buf0lru.cc
+++ b/storage/xtradb/buf/buf0lru.cc
@@ -503,17 +503,15 @@ buf_flush_or_remove_page(
yet; maybe the system is currently reading it
in, or flushing the modifications to the file */
return(false);
-
}
- bool processed = false;
-
buf_flush_list_mutex_exit(buf_pool);
/* We don't have to worry about bpage becoming a dangling
pointer by a compressed page flush list relocation because
buf_page_get_gen() won't be called for pages from this
tablespace. */
+ bool processed;
mutex_enter(block_mutex);
@@ -529,6 +527,7 @@ buf_flush_or_remove_page(
mutex_exit(block_mutex);
*must_restart = TRUE;
+ processed = false;
} else if (!flush) {
@@ -538,29 +537,29 @@ buf_flush_or_remove_page(
processed = true;
- } else if (buf_flush_ready_for_flush(bpage,
- BUF_FLUSH_SINGLE_PAGE)) {
+ } else if (buf_flush_ready_for_flush(bpage, BUF_FLUSH_SINGLE_PAGE)) {
- mutex_exit(&buf_pool->LRU_list_mutex);
+ if (buf_flush_page(
+ buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, false)) {
- /* The following call will release the buf_page_get_mutex()
- mutex. */
- buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, false);
- ut_ad(!mutex_own(block_mutex));
+ /* Wake possible simulated aio thread to actually
+ post the writes to the operating system */
+ os_aio_simulated_wake_handler_threads();
- /* Wake possible simulated aio thread to actually
- post the writes to the operating system */
- os_aio_simulated_wake_handler_threads();
+ mutex_enter(&buf_pool->LRU_list_mutex);
- mutex_enter(&buf_pool->LRU_list_mutex);
+ processed = true;
+
+ } else {
+ mutex_exit(block_mutex);
+
+ processed = false;
+ }
- processed = true;
} else {
- /* Not ready for flush. It can't be IO fixed because we
- checked for that at the start of the function. It must
- be buffer fixed. */
- ut_ad(bpage->buf_fix_count > 0);
mutex_exit(block_mutex);
+
+ processed = false;
}
buf_flush_list_mutex_enter(buf_pool);
@@ -1358,15 +1357,17 @@ loop:
memset(&block->page.zip, 0, sizeof block->page.zip);
if (started_monitor) {
- srv_print_innodb_monitor = mon_value_was;
+ srv_print_innodb_monitor =
+ static_cast<my_bool>(mon_value_was);
}
return(block);
}
if (srv_empty_free_list_algorithm == SRV_EMPTY_FREE_LIST_BACKOFF
- && buf_page_cleaner_is_active
- && srv_shutdown_state == SRV_SHUTDOWN_NONE) {
+ && buf_lru_manager_is_active
+ && (srv_shutdown_state == SRV_SHUTDOWN_NONE
+ || srv_shutdown_state == SRV_SHUTDOWN_CLEANUP)) {
/* Backoff to minimize the free list mutex contention while the
free list is empty */
@@ -1408,12 +1409,13 @@ loop:
goto loop;
} else {
- /* The cleaner is not running or Oracle MySQL 5.6 algorithm was
- requested, will perform a single page flush */
+ /* The LRU manager is not running or Oracle MySQL 5.6 algorithm
+ was requested, will perform a single page flush */
ut_ad((srv_empty_free_list_algorithm
== SRV_EMPTY_FREE_LIST_LEGACY)
- || !buf_page_cleaner_is_active
- || (srv_shutdown_state != SRV_SHUTDOWN_NONE));
+ || !buf_lru_manager_is_active
+ || (srv_shutdown_state != SRV_SHUTDOWN_NONE
+ && srv_shutdown_state != SRV_SHUTDOWN_CLEANUP));
}
mutex_enter(&buf_pool->flush_state_mutex);
@@ -1829,8 +1831,6 @@ buf_LRU_add_block_low(
{
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
- ut_ad(buf_pool);
- ut_ad(bpage);
ut_ad(mutex_own(&buf_pool->LRU_list_mutex));
ut_a(buf_page_in_file(bpage));
@@ -1980,7 +1980,7 @@ buf_LRU_free_page(
if (!buf_page_can_relocate(bpage)) {
- /* Do not free buffer-fixed or I/O-fixed blocks. */
+ /* Do not free buffer fixed or I/O-fixed blocks. */
return(false);
}
@@ -1995,12 +1995,10 @@ buf_LRU_free_page(
if (bpage->oldest_modification) {
return(false);
}
- } else if ((bpage->oldest_modification)
- && (buf_page_get_state(bpage)
- != BUF_BLOCK_FILE_PAGE)) {
+ } else if (bpage->oldest_modification > 0
+ && buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
- ut_ad(buf_page_get_state(bpage)
- == BUF_BLOCK_ZIP_DIRTY);
+ ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_DIRTY);
return(false);
@@ -2088,10 +2086,8 @@ not_freed:
rw_lock_x_lock(hash_lock);
mutex_enter(block_mutex);
- ut_a(!buf_page_hash_get_low(buf_pool,
- bpage->space,
- bpage->offset,
- fold));
+ ut_a(!buf_page_hash_get_low(
+ buf_pool, b->space, b->offset, fold));
b->state = b->oldest_modification
? BUF_BLOCK_ZIP_DIRTY
@@ -2215,11 +2211,12 @@ not_freed:
buf_pool->page_hash, thus inaccessible by any
other thread. */
- checksum = page_zip_calc_checksum(
- b->zip.data,
- page_zip_get_size(&b->zip),
- static_cast<srv_checksum_algorithm_t>(
- srv_checksum_algorithm));
+ checksum = static_cast<ib_uint32_t>(
+ page_zip_calc_checksum(
+ b->zip.data,
+ page_zip_get_size(&b->zip),
+ static_cast<srv_checksum_algorithm_t>(
+ srv_checksum_algorithm)));
mach_write_to_4(b->zip.data + FIL_PAGE_SPACE_OR_CHKSUM,
checksum);
@@ -2432,6 +2429,25 @@ buf_LRU_block_remove_hashed(
" in the hash table\n",
(ulong) bpage->space,
(ulong) bpage->offset);
+
+#ifdef UNIV_DEBUG
+ fprintf(stderr,
+ "InnoDB: in_page_hash %lu in_zip_hash %lu\n"
+ " in_free_list %lu in_flush_list %lu in_LRU_list %lu\n"
+ " zip.data %p zip_size %lu page_state %d\n",
+ bpage->in_page_hash, bpage->in_zip_hash,
+ bpage->in_free_list, bpage->in_flush_list,
+ bpage->in_LRU_list, bpage->zip.data,
+ buf_page_get_zip_size(bpage),
+ buf_page_get_state(bpage));
+#else
+ fprintf(stderr,
+ "InnoDB: zip.data %p zip_size %lu page_state %d\n",
+ bpage->zip.data,
+ buf_page_get_zip_size(bpage),
+ buf_page_get_state(bpage));
+#endif
+
if (hashed_bpage) {
fprintf(stderr,
"InnoDB: In hash table we find block"
@@ -2442,6 +2458,9 @@ buf_LRU_block_remove_hashed(
(const void*) bpage);
}
+ ut_a(buf_page_get_io_fix(bpage) == BUF_IO_NONE);
+ ut_a(bpage->buf_fix_count == 0);
+
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
mutex_exit(buf_page_get_mutex(bpage));
rw_lock_x_unlock(hash_lock);
@@ -2489,6 +2508,11 @@ buf_LRU_block_remove_hashed(
UNIV_PAGE_SIZE);
buf_page_set_state(bpage, BUF_BLOCK_REMOVE_HASH);
+ if (buf_pool->flush_rbt == NULL) {
+ bpage->space = ULINT32_UNDEFINED;
+ bpage->offset = ULINT32_UNDEFINED;
+ }
+
/* Question: If we release bpage and hash mutex here
then what protects us against:
1) Some other thread buffer fixing this page
diff --git a/storage/xtradb/dict/dict0boot.cc b/storage/xtradb/dict/dict0boot.cc
index 94a3af2852b..b57a8873bd5 100644
--- a/storage/xtradb/dict/dict0boot.cc
+++ b/storage/xtradb/dict/dict0boot.cc
@@ -302,7 +302,8 @@ dict_boot(void)
/* Insert into the dictionary cache the descriptions of the basic
system tables */
/*-------------------------*/
- table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0, 0);
+ table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0, 0,
+ false);
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
@@ -356,7 +357,8 @@ dict_boot(void)
ut_a(error == DB_SUCCESS);
/*-------------------------*/
- table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0, 0);
+ table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0, 0,
+ false);
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
@@ -389,7 +391,8 @@ dict_boot(void)
ut_a(error == DB_SUCCESS);
/*-------------------------*/
- table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0, 0);
+ table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0, 0,
+ false);
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
@@ -422,7 +425,8 @@ dict_boot(void)
ut_a(error == DB_SUCCESS);
/*-------------------------*/
- table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0, 0);
+ table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 0, 0,
+ false);
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
diff --git a/storage/xtradb/dict/dict0crea.cc b/storage/xtradb/dict/dict0crea.cc
index eba5417dc76..ff892749d4f 100644
--- a/storage/xtradb/dict/dict0crea.cc
+++ b/storage/xtradb/dict/dict0crea.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
@@ -270,6 +270,12 @@ dict_build_table_def_step(
thr_get_trx(thr)->table_id = table->id;
+ /* Always set this bit for all new created tables */
+ DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME);
+ DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
+ DICT_TF2_FLAG_UNSET(table,
+ DICT_TF2_FTS_AUX_HEX_NAME););
+
if (use_tablespace) {
/* This table will not use the system tablespace.
Get a new space id. */
diff --git a/storage/xtradb/dict/dict0dict.cc b/storage/xtradb/dict/dict0dict.cc
index 0aaec42cd2f..31d7639aee5 100644
--- a/storage/xtradb/dict/dict0dict.cc
+++ b/storage/xtradb/dict/dict0dict.cc
@@ -121,18 +121,10 @@ UNIV_INTERN mysql_pfs_key_t dict_foreign_err_mutex_key;
/** Identifies generated InnoDB foreign key names */
static char dict_ibfk[] = "_ibfk_";
-/** array of rw locks protecting
-dict_table_t::stat_initialized
-dict_table_t::stat_n_rows (*)
-dict_table_t::stat_clustered_index_size
-dict_table_t::stat_sum_of_other_index_sizes
-dict_table_t::stat_modified_counter (*)
-dict_table_t::indexes*::stat_n_diff_key_vals[]
-dict_table_t::indexes*::stat_index_size
-dict_table_t::indexes*::stat_n_leaf_pages
-(*) those are not always protected for performance reasons */
-#define DICT_TABLE_STATS_LATCHES_SIZE 64
-static rw_lock_t dict_table_stats_latches[DICT_TABLE_STATS_LATCHES_SIZE];
+bool innodb_table_stats_not_found = false;
+bool innodb_index_stats_not_found = false;
+static bool innodb_table_stats_not_found_reported = false;
+static bool innodb_index_stats_not_found_reported = false;
/*******************************************************************//**
Tries to find column names for the index and sets the col field of the
@@ -332,32 +324,31 @@ dict_mutex_exit_for_mysql(void)
mutex_exit(&(dict_sys->mutex));
}
-/** Get the latch that protects the stats of a given table */
-#define GET_TABLE_STATS_LATCH(table) \
- (&dict_table_stats_latches[ut_fold_ull((ib_uint64_t) table) \
- % DICT_TABLE_STATS_LATCHES_SIZE])
-
/**********************************************************************//**
-Lock the appropriate latch to protect a given table's statistics.
-table->id is used to pick the corresponding latch from a global array of
-latches. */
+Lock the appropriate latch to protect a given table's statistics. */
UNIV_INTERN
void
dict_table_stats_lock(
/*==================*/
- const dict_table_t* table, /*!< in: table */
- ulint latch_mode) /*!< in: RW_S_LATCH or
- RW_X_LATCH */
+ dict_table_t* table, /*!< in: table */
+ ulint latch_mode) /*!< in: RW_S_LATCH or RW_X_LATCH */
{
ut_ad(table != NULL);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
+ if (table->stats_latch == NULL) {
+ /* This is a dummy table object that is private in the current
+ thread and is not shared between multiple threads, thus we
+ skip any locking. */
+ return;
+ }
+
switch (latch_mode) {
case RW_S_LATCH:
- rw_lock_s_lock(GET_TABLE_STATS_LATCH(table));
+ rw_lock_s_lock(table->stats_latch);
break;
case RW_X_LATCH:
- rw_lock_x_lock(GET_TABLE_STATS_LATCH(table));
+ rw_lock_x_lock(table->stats_latch);
break;
case RW_NO_LATCH:
/* fall through */
@@ -372,19 +363,26 @@ UNIV_INTERN
void
dict_table_stats_unlock(
/*====================*/
- const dict_table_t* table, /*!< in: table */
- ulint latch_mode) /*!< in: RW_S_LATCH or
+ dict_table_t* table, /*!< in: table */
+ ulint latch_mode) /*!< in: RW_S_LATCH or
RW_X_LATCH */
{
ut_ad(table != NULL);
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
+ if (table->stats_latch == NULL) {
+ /* This is a dummy table object that is private in the current
+ thread and is not shared between multiple threads, thus we
+ skip any locking. */
+ return;
+ }
+
switch (latch_mode) {
case RW_S_LATCH:
- rw_lock_s_unlock(GET_TABLE_STATS_LATCH(table));
+ rw_lock_s_unlock(table->stats_latch);
break;
case RW_X_LATCH:
- rw_lock_x_unlock(GET_TABLE_STATS_LATCH(table));
+ rw_lock_x_unlock(table->stats_latch);
break;
case RW_NO_LATCH:
/* fall through */
@@ -880,8 +878,6 @@ void
dict_init(void)
/*===========*/
{
- int i;
-
dict_sys = static_cast<dict_sys_t*>(mem_zalloc(sizeof(*dict_sys)));
mutex_create(dict_sys_mutex_key, &dict_sys->mutex, SYNC_DICT);
@@ -902,11 +898,6 @@ dict_init(void)
mutex_create(dict_foreign_err_mutex_key,
&dict_foreign_err_mutex, SYNC_NO_ORDER_CHECK);
}
-
- for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
- rw_lock_create(dict_table_stats_latch_key,
- &dict_table_stats_latches[i], SYNC_INDEX_TREE);
- }
}
/**********************************************************************//**
@@ -5770,7 +5761,8 @@ dict_ind_init(void)
dict_table_t* table;
/* create dummy table and index for REDUNDANT infimum and supremum */
- table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0, 0);
+ table = dict_mem_table_create("SYS_DUMMY1", DICT_HDR_SPACE, 1, 0, 0,
+ true);
dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
DATA_ENGLISH | DATA_NOT_NULL, 8);
@@ -5783,7 +5775,7 @@ dict_ind_init(void)
/* create dummy table and index for COMPACT infimum and supremum */
table = dict_mem_table_create("SYS_DUMMY2",
DICT_HDR_SPACE, 1,
- DICT_TF_COMPACT, 0);
+ DICT_TF_COMPACT, 0, true);
dict_mem_table_add_col(table, NULL, NULL, DATA_CHAR,
DATA_ENGLISH | DATA_NOT_NULL, 8);
dict_ind_compact = dict_mem_index_create("SYS_DUMMY2", "SYS_DUMMY2",
@@ -6010,6 +6002,17 @@ dict_table_check_for_dup_indexes(
}
#endif /* UNIV_DEBUG */
+/** Auxiliary macro used inside dict_table_schema_check(). */
+#define CREATE_TYPES_NAMES() \
+ dtype_sql_name((unsigned) req_schema->columns[i].mtype, \
+ (unsigned) req_schema->columns[i].prtype_mask, \
+ (unsigned) req_schema->columns[i].len, \
+ req_type, sizeof(req_type)); \
+ dtype_sql_name(table->cols[j].mtype, \
+ table->cols[j].prtype, \
+ table->cols[j].len, \
+ actual_type, sizeof(actual_type))
+
/*********************************************************************//**
Checks whether a table exists and whether it has the given structure.
The table must have the same number of columns with the same names and
@@ -6029,6 +6032,8 @@ dict_table_schema_check(
size_t errstr_sz) /*!< in: errstr size */
{
char buf[MAX_FULL_NAME_LEN];
+ char req_type[64];
+ char actual_type[64];
dict_table_t* table;
ulint i;
@@ -6037,14 +6042,34 @@ dict_table_schema_check(
table = dict_table_get_low(req_schema->table_name);
if (table == NULL) {
+ bool should_print=true;
/* no such table */
- ut_snprintf(errstr, errstr_sz,
- "Table %s not found.",
- ut_format_name(req_schema->table_name,
- TRUE, buf, sizeof(buf)));
+ if (innobase_strcasecmp(req_schema->table_name, "mysql/innodb_table_stats") == 0) {
+ if (innodb_table_stats_not_found_reported == false) {
+ innodb_table_stats_not_found = true;
+ innodb_table_stats_not_found_reported = true;
+ } else {
+ should_print = false;
+ }
+ } else if (innobase_strcasecmp(req_schema->table_name, "mysql/innodb_index_stats") == 0 ) {
+ if (innodb_index_stats_not_found_reported == false) {
+ innodb_index_stats_not_found = true;
+ innodb_index_stats_not_found_reported = true;
+ } else {
+ should_print = false;
+ }
+ }
- return(DB_TABLE_NOT_FOUND);
+ if (should_print) {
+ ut_snprintf(errstr, errstr_sz,
+ "Table %s not found.",
+ ut_format_name(req_schema->table_name,
+ TRUE, buf, sizeof(buf)));
+ return(DB_TABLE_NOT_FOUND);
+ } else {
+ return(DB_STATS_DO_NOT_EXIST);
+ }
}
if (table->ibd_file_missing) {
@@ -6080,9 +6105,6 @@ dict_table_schema_check(
for (i = 0; i < req_schema->n_cols; i++) {
ulint j;
- char req_type[64];
- char actual_type[64];
-
/* check if i'th column is the same in both arrays */
if (innobase_strcasecmp(req_schema->columns[i].name,
dict_table_get_col_name(table, i)) == 0) {
@@ -6124,19 +6146,11 @@ dict_table_schema_check(
/* we found a column with the same name on j'th position,
compare column types and flags */
- dtype_sql_name(req_schema->columns[i].mtype,
- req_schema->columns[i].prtype_mask,
- req_schema->columns[i].len,
- req_type, sizeof(req_type));
-
- dtype_sql_name(table->cols[j].mtype,
- table->cols[j].prtype,
- table->cols[j].len,
- actual_type, sizeof(actual_type));
-
/* check length for exact match */
if (req_schema->columns[i].len != table->cols[j].len) {
+ CREATE_TYPES_NAMES();
+
ut_snprintf(errstr, errstr_sz,
"Column %s in table %s is %s "
"but should be %s (length mismatch).",
@@ -6151,6 +6165,8 @@ dict_table_schema_check(
/* check mtype for exact match */
if (req_schema->columns[i].mtype != table->cols[j].mtype) {
+ CREATE_TYPES_NAMES();
+
ut_snprintf(errstr, errstr_sz,
"Column %s in table %s is %s "
"but should be %s (type mismatch).",
@@ -6168,6 +6184,8 @@ dict_table_schema_check(
& req_schema->columns[i].prtype_mask)
!= req_schema->columns[i].prtype_mask) {
+ CREATE_TYPES_NAMES();
+
ut_snprintf(errstr, errstr_sz,
"Column %s in table %s is %s "
"but should be %s (flags mismatch).",
@@ -6236,9 +6254,8 @@ dict_fs2utf8(
db[db_len] = '\0';
strconvert(
- &my_charset_filename, db, db_len,
- system_charset_info, db_utf8, db_utf8_size,
- &errors);
+ &my_charset_filename, db, db_len, system_charset_info,
+ db_utf8, static_cast<uint>(db_utf8_size), &errors);
/* convert each # to @0023 in table name and store the result in buf */
const char* table = dict_remove_db_name(db_and_table);
@@ -6263,8 +6280,8 @@ dict_fs2utf8(
errors = 0;
strconvert(
- &my_charset_filename, buf, buf_p - buf,
- system_charset_info, table_utf8, table_utf8_size,
+ &my_charset_filename, buf, buf_p - buf, system_charset_info,
+ table_utf8, static_cast<uint>(table_utf8_size),
&errors);
if (errors != 0) {
@@ -6326,10 +6343,6 @@ dict_close(void)
mem_free(dict_sys);
dict_sys = NULL;
-
- for (i = 0; i < DICT_TABLE_STATS_LATCHES_SIZE; i++) {
- rw_lock_free(&dict_table_stats_latches[i]);
- }
}
#ifdef UNIV_DEBUG
diff --git a/storage/xtradb/dict/dict0load.cc b/storage/xtradb/dict/dict0load.cc
index 5c97b5aba7c..013a5fb7b37 100644
--- a/storage/xtradb/dict/dict0load.cc
+++ b/storage/xtradb/dict/dict0load.cc
@@ -1065,7 +1065,8 @@ loop:
bool is_temp = false;
bool discarded = false;
- ib_uint32_t flags2 = mach_read_from_4(field);
+ ib_uint32_t flags2 = static_cast<ib_uint32_t>(
+ mach_read_from_4(field));
/* Check that the tablespace (the .ibd file) really
exists; print a warning to the .err log if not.
@@ -1092,10 +1093,34 @@ loop:
case DICT_CHECK_ALL_LOADED:
/* All tablespaces should have been found in
fil_load_single_table_tablespaces(). */
-
- fil_space_for_table_exists_in_mem(
+ if (fil_space_for_table_exists_in_mem(
space_id, name, TRUE, !(is_temp || discarded),
- false, NULL, 0);
+ false, NULL, 0)
+ && !(is_temp || discarded)) {
+ /* If user changes the path of .ibd files in
+ *.isl files before doing crash recovery ,
+ then this leads to inconsistency in
+ SYS_DATAFILES system table because the
+ tables are loaded from the updated path
+ but the SYS_DATAFILES still points to the
+ old path.Therefore after crash recovery
+ update SYS_DATAFILES with the updated path.*/
+ ut_ad(space_id);
+ ut_ad(recv_needed_recovery);
+ char *dict_path = dict_get_first_path(space_id,
+ name);
+ char *remote_path = fil_read_link_file(name);
+ if(dict_path && remote_path) {
+ if(strcmp(dict_path,remote_path)) {
+ dict_update_filepath(space_id,
+ remote_path);
+ }
+ }
+ if(dict_path)
+ mem_free(dict_path);
+ if(remote_path)
+ mem_free(remote_path);
+ }
break;
case DICT_CHECK_SOME_LOADED:
@@ -2151,7 +2176,8 @@ err_len:
/* See if the tablespace is available. */
*table = dict_mem_table_create(
- name, space, n_cols & ~DICT_N_COLS_COMPACT, flags, flags2);
+ name, space, n_cols & ~DICT_N_COLS_COMPACT, flags, flags2,
+ false);
field = rec_get_nth_field_old(rec, DICT_FLD__SYS_TABLES__ID, &len);
ut_ad(len == 8); /* this was checked earlier */
diff --git a/storage/xtradb/dict/dict0mem.cc b/storage/xtradb/dict/dict0mem.cc
index f69e6cc47ae..7ce42fa8efc 100644
--- a/storage/xtradb/dict/dict0mem.cc
+++ b/storage/xtradb/dict/dict0mem.cc
@@ -65,7 +65,10 @@ dict_mem_table_create(
the table is placed */
ulint n_cols, /*!< in: number of columns */
ulint flags, /*!< in: table flags */
- ulint flags2) /*!< in: table flags2 */
+ ulint flags2, /*!< in: table flags2 */
+ bool nonshared)/*!< in: whether the table object is a dummy
+ one that does not need the initialization of
+ locking-related fields. */
{
dict_table_t* table;
mem_heap_t* heap;
@@ -95,12 +98,27 @@ dict_mem_table_create(
ut_d(table->magic_n = DICT_TABLE_MAGIC_N);
+ if (!nonshared) {
+ table->stats_latch = new rw_lock_t;
+ rw_lock_create(dict_table_stats_latch_key, table->stats_latch,
+ SYNC_INDEX_TREE);
+ } else {
+ table->stats_latch = NULL;
+ }
+
#ifndef UNIV_HOTBACKUP
- table->autoinc_lock = static_cast<ib_lock_t*>(
- mem_heap_alloc(heap, lock_get_size()));
- mutex_create(autoinc_mutex_key,
- &table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
+ if (!nonshared) {
+
+ table->autoinc_lock = static_cast<ib_lock_t*>(
+ mem_heap_alloc(heap, lock_get_size()));
+
+ mutex_create(autoinc_mutex_key,
+ &table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
+ } else {
+
+ table->autoinc_lock = NULL;
+ }
table->autoinc = 0;
@@ -150,8 +168,18 @@ dict_mem_table_free(
}
}
#ifndef UNIV_HOTBACKUP
- mutex_free(&(table->autoinc_mutex));
+ if (table->stats_latch) {
+
+ mutex_free(&(table->autoinc_mutex));
+ }
#endif /* UNIV_HOTBACKUP */
+
+ if (table->stats_latch) {
+
+ rw_lock_free(table->stats_latch);
+ delete table->stats_latch;
+ }
+
ut_free(table->name);
mem_heap_free(table->heap);
}
diff --git a/storage/xtradb/dict/dict0stats.cc b/storage/xtradb/dict/dict0stats.cc
index 8bf02f9785c..aa417bbae7b 100644
--- a/storage/xtradb/dict/dict0stats.cc
+++ b/storage/xtradb/dict/dict0stats.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2009, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2009, 2014, 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
@@ -46,6 +46,7 @@ Created Jan 06, 2010 Vasil Dimov
#include "ut0rnd.h" /* ut_rnd_interval() */
#include "ut0ut.h" /* ut_format_name(), ut_time() */
+#include <map>
#include <vector>
/* Sampling algorithm description @{
@@ -143,6 +144,17 @@ data: b,b,b,b,b,b,g,g,j,j,j, x, y
then we would store 5,7,10,11,12 in the array. */
typedef std::vector<ib_uint64_t> boundaries_t;
+/* This is used to arrange the index based on the index name.
+@return true if index_name1 is smaller than index_name2. */
+struct index_cmp
+{
+ bool operator()(const char* index_name1, const char* index_name2) const {
+ return(strcmp(index_name1, index_name2) < 0);
+ }
+};
+
+typedef std::map<const char*, dict_index_t*, index_cmp> index_map_t;
+
/*********************************************************************//**
Checks whether an index should be ignored in stats manipulations:
* stats fetch
@@ -256,32 +268,36 @@ dict_stats_persistent_storage_check(
mutex_exit(&(dict_sys->mutex));
}
- if (ret != DB_SUCCESS) {
+ if (ret != DB_SUCCESS && ret != DB_STATS_DO_NOT_EXIST) {
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Error: %s\n", errstr);
return(false);
+ } else if (ret == DB_STATS_DO_NOT_EXIST) {
+ return false;
}
/* else */
return(true);
}
-/*********************************************************************//**
-Executes a given SQL statement using the InnoDB internal SQL parser
-in its own transaction and commits it.
+/** Executes a given SQL statement using the InnoDB internal SQL parser.
This function will free the pinfo object.
+@param[in,out] pinfo pinfo to pass to que_eval_sql() must already
+have any literals bound to it
+@param[in] sql SQL string to execute
+@param[in,out] trx in case of NULL the function will allocate and
+free the trx object. If it is not NULL then it will be rolled back
+only in the case of error, but not freed.
@return DB_SUCCESS or error code */
static
dberr_t
dict_stats_exec_sql(
-/*================*/
- pars_info_t* pinfo, /*!< in/out: pinfo to pass to que_eval_sql()
- must already have any literals bound to it */
- const char* sql) /*!< in: SQL string to execute */
+ pars_info_t* pinfo,
+ const char* sql,
+ trx_t* trx)
{
- trx_t* trx;
dberr_t err;
-
+ bool trx_started = false;
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
@@ -292,11 +308,24 @@ dict_stats_exec_sql(
return(DB_STATS_DO_NOT_EXIST);
}
- trx = trx_allocate_for_background();
- trx_start_if_not_started(trx);
+ if (trx == NULL) {
+ trx = trx_allocate_for_background();
+ trx_start_if_not_started(trx);
+ trx_started = true;
+ }
err = que_eval_sql(pinfo, sql, FALSE, trx); /* pinfo is freed here */
+ DBUG_EXECUTE_IF("stats_index_error",
+ if (!trx_started) {
+ err = DB_STATS_DO_NOT_EXIST;
+ trx->error_state = DB_STATS_DO_NOT_EXIST;
+ });
+
+ if (!trx_started && err == DB_SUCCESS) {
+ return(DB_SUCCESS);
+ }
+
if (err == DB_SUCCESS) {
trx_commit_for_mysql(trx);
} else {
@@ -308,7 +337,9 @@ dict_stats_exec_sql(
ut_a(trx->error_state == DB_SUCCESS);
}
- trx_free_for_background(trx);
+ if (trx_started) {
+ trx_free_for_background(trx);
+ }
return(err);
}
@@ -400,6 +431,11 @@ dict_stats_table_clone_create(
t->corrupted = table->corrupted;
+ /* This private object "t" is not shared with other threads, so
+ we do not need the stats_latch. The lock/unlock routines will do
+ nothing if stats_latch is NULL. */
+ t->stats_latch = NULL;
+
UT_LIST_INIT(t->indexes);
for (index = dict_table_get_first_index(table);
@@ -731,7 +767,7 @@ static
dict_table_t*
dict_stats_snapshot_create(
/*=======================*/
- const dict_table_t* table) /*!< in: table whose stats to copy */
+ dict_table_t* table) /*!< in: table whose stats to copy */
{
mutex_enter(&dict_sys->mutex);
@@ -1583,7 +1619,8 @@ dict_stats_analyze_index_for_n_prefix(
== !(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
btr_pcur_get_rec(&pcur), page_is_comp(page))));
- last_idx_on_level = boundaries->at(n_diff_for_this_prefix - 1);
+ last_idx_on_level = boundaries->at(
+ static_cast<unsigned int>(n_diff_for_this_prefix - 1));
rec_idx = 0;
@@ -1595,7 +1632,7 @@ dict_stats_analyze_index_for_n_prefix(
for (i = 0; i < n_recs_to_dive_below; i++) {
ib_uint64_t left;
ib_uint64_t right;
- ulint rnd;
+ ib_uint64_t rnd;
ib_uint64_t dive_below_idx;
/* there are n_diff_for_this_prefix elements
@@ -1636,9 +1673,11 @@ dict_stats_analyze_index_for_n_prefix(
/* we do not pass (left, right) because we do not want to ask
ut_rnd_interval() to work with too big numbers since
ib_uint64_t could be bigger than ulint */
- rnd = ut_rnd_interval(0, (ulint) (right - left));
+ rnd = static_cast<ib_uint64_t>(
+ ut_rnd_interval(0, static_cast<ulint>(right - left)));
- dive_below_idx = boundaries->at(left + rnd);
+ dive_below_idx = boundaries->at(
+ static_cast<unsigned int>(left + rnd));
#if 0
DEBUG_PRINTF(" %s(): dive below record with index="
@@ -2079,20 +2118,28 @@ dict_stats_update_persistent(
}
#include "mysql_com.h"
-/*********************************************************************//**
-Save an individual index's statistic into the persistent statistics
+/** Save an individual index's statistic into the persistent statistics
storage.
+@param[in] index index to be updated
+@param[in] last_update timestamp of the stat
+@param[in] stat_name name of the stat
+@param[in] stat_value value of the stat
+@param[in] sample_size n pages sampled or NULL
+@param[in] stat_description description of the stat
+@param[in,out] trx in case of NULL the function will
+allocate and free the trx object. If it is not NULL then it will be
+rolled back only in the case of error, but not freed.
@return DB_SUCCESS or error code */
static
dberr_t
dict_stats_save_index_stat(
-/*=======================*/
- dict_index_t* index, /*!< in: index */
- lint last_update, /*!< in: timestamp of the stat */
- const char* stat_name, /*!< in: name of the stat */
- ib_uint64_t stat_value, /*!< in: value of the stat */
- ib_uint64_t* sample_size, /*!< in: n pages sampled or NULL */
- const char* stat_description)/*!< in: description of the stat */
+ dict_index_t* index,
+ lint last_update,
+ const char* stat_name,
+ ib_uint64_t stat_value,
+ ib_uint64_t* sample_size,
+ const char* stat_description,
+ trx_t* trx)
{
pars_info_t* pinfo;
dberr_t ret;
@@ -2131,8 +2178,16 @@ dict_stats_save_index_stat(
ret = dict_stats_exec_sql(
pinfo,
- "PROCEDURE INDEX_STATS_SAVE_INSERT () IS\n"
+ "PROCEDURE INDEX_STATS_SAVE () IS\n"
"BEGIN\n"
+
+ "DELETE FROM \"" INDEX_STATS_NAME "\"\n"
+ "WHERE\n"
+ "database_name = :database_name AND\n"
+ "table_name = :table_name AND\n"
+ "index_name = :index_name AND\n"
+ "stat_name = :stat_name;\n"
+
"INSERT INTO \"" INDEX_STATS_NAME "\"\n"
"VALUES\n"
"(\n"
@@ -2145,74 +2200,41 @@ dict_stats_save_index_stat(
":sample_size,\n"
":stat_description\n"
");\n"
- "END;");
-
- if (ret == DB_DUPLICATE_KEY) {
-
- pinfo = pars_info_create();
- pars_info_add_str_literal(pinfo, "database_name", db_utf8);
- pars_info_add_str_literal(pinfo, "table_name", table_utf8);
- UNIV_MEM_ASSERT_RW_ABORT(index->name, strlen(index->name));
- pars_info_add_str_literal(pinfo, "index_name", index->name);
- UNIV_MEM_ASSERT_RW_ABORT(&last_update, 4);
- pars_info_add_int4_literal(pinfo, "last_update", last_update);
- UNIV_MEM_ASSERT_RW_ABORT(stat_name, strlen(stat_name));
- pars_info_add_str_literal(pinfo, "stat_name", stat_name);
- UNIV_MEM_ASSERT_RW_ABORT(&stat_value, 8);
- pars_info_add_ull_literal(pinfo, "stat_value", stat_value);
- if (sample_size != NULL) {
- UNIV_MEM_ASSERT_RW_ABORT(sample_size, 8);
- pars_info_add_ull_literal(pinfo, "sample_size", *sample_size);
- } else {
- pars_info_add_literal(pinfo, "sample_size", NULL,
- UNIV_SQL_NULL, DATA_FIXBINARY, 0);
- }
- UNIV_MEM_ASSERT_RW_ABORT(stat_description, strlen(stat_description));
- pars_info_add_str_literal(pinfo, "stat_description",
- stat_description);
-
- ret = dict_stats_exec_sql(
- pinfo,
- "PROCEDURE INDEX_STATS_SAVE_UPDATE () IS\n"
- "BEGIN\n"
- "UPDATE \"" INDEX_STATS_NAME "\" SET\n"
- "last_update = :last_update,\n"
- "stat_value = :stat_value,\n"
- "sample_size = :sample_size,\n"
- "stat_description = :stat_description\n"
- "WHERE\n"
- "database_name = :database_name AND\n"
- "table_name = :table_name AND\n"
- "index_name = :index_name AND\n"
- "stat_name = :stat_name;\n"
- "END;");
- }
+ "END;", trx);
if (ret != DB_SUCCESS) {
- char buf_table[MAX_FULL_NAME_LEN];
- char buf_index[MAX_FULL_NAME_LEN];
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Cannot save index statistics for table "
- "%s, index %s, stat name \"%s\": %s\n",
- ut_format_name(index->table->name, TRUE,
- buf_table, sizeof(buf_table)),
- ut_format_name(index->name, FALSE,
- buf_index, sizeof(buf_index)),
- stat_name, ut_strerr(ret));
+ if (innodb_index_stats_not_found == false &&
+ index->stats_error_printed == false) {
+ char buf_table[MAX_FULL_NAME_LEN];
+ char buf_index[MAX_FULL_NAME_LEN];
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Cannot save index statistics for table "
+ "%s, index %s, stat name \"%s\": %s\n",
+ ut_format_name(index->table->name, TRUE,
+ buf_table, sizeof(buf_table)),
+ ut_format_name(index->name, FALSE,
+ buf_index, sizeof(buf_index)),
+ stat_name, ut_strerr(ret));
+ index->stats_error_printed = true;
+ }
}
return(ret);
}
-/*********************************************************************//**
-Save the table's statistics into the persistent statistics storage.
+/** Save the table's statistics into the persistent statistics storage.
+@param[in] table_orig table whose stats to save
+@param[in] only_for_index if this is non-NULL, then stats for indexes
+that are not equal to it will not be saved, if NULL, then all
+indexes' stats are saved
@return DB_SUCCESS or error code */
static
dberr_t
dict_stats_save(
/*============*/
- dict_table_t* table_orig) /*!< in: table */
+ dict_table_t* table_orig,
+ const index_id_t* only_for_index)
{
pars_info_t* pinfo;
lint now;
@@ -2234,26 +2256,27 @@ dict_stats_save(
lint */
now = (lint) ut_time();
-#define PREPARE_PINFO_FOR_TABLE_SAVE(p, t, n) \
- do { \
- pars_info_add_str_literal((p), "database_name", db_utf8); \
- pars_info_add_str_literal((p), "table_name", table_utf8); \
- pars_info_add_int4_literal((p), "last_update", (n)); \
- pars_info_add_ull_literal((p), "n_rows", (t)->stat_n_rows); \
- pars_info_add_ull_literal((p), "clustered_index_size", \
- (t)->stat_clustered_index_size); \
- pars_info_add_ull_literal((p), "sum_of_other_index_sizes", \
- (t)->stat_sum_of_other_index_sizes); \
- } while(false);
-
pinfo = pars_info_create();
- PREPARE_PINFO_FOR_TABLE_SAVE(pinfo, table, now);
+ pars_info_add_str_literal(pinfo, "database_name", db_utf8);
+ pars_info_add_str_literal(pinfo, "table_name", table_utf8);
+ pars_info_add_int4_literal(pinfo, "last_update", now);
+ pars_info_add_ull_literal(pinfo, "n_rows", table->stat_n_rows);
+ pars_info_add_ull_literal(pinfo, "clustered_index_size",
+ table->stat_clustered_index_size);
+ pars_info_add_ull_literal(pinfo, "sum_of_other_index_sizes",
+ table->stat_sum_of_other_index_sizes);
ret = dict_stats_exec_sql(
pinfo,
- "PROCEDURE TABLE_STATS_SAVE_INSERT () IS\n"
+ "PROCEDURE TABLE_STATS_SAVE () IS\n"
"BEGIN\n"
+
+ "DELETE FROM \"" TABLE_STATS_NAME "\"\n"
+ "WHERE\n"
+ "database_name = :database_name AND\n"
+ "table_name = :table_name;\n"
+
"INSERT INTO \"" TABLE_STATS_NAME "\"\n"
"VALUES\n"
"(\n"
@@ -2264,28 +2287,7 @@ dict_stats_save(
":clustered_index_size,\n"
":sum_of_other_index_sizes\n"
");\n"
- "END;");
-
- if (ret == DB_DUPLICATE_KEY) {
- pinfo = pars_info_create();
-
- PREPARE_PINFO_FOR_TABLE_SAVE(pinfo, table, now);
-
- ret = dict_stats_exec_sql(
- pinfo,
- "PROCEDURE TABLE_STATS_SAVE_UPDATE () IS\n"
- "BEGIN\n"
- "UPDATE \"" TABLE_STATS_NAME "\" SET\n"
- "last_update = :last_update,\n"
- "n_rows = :n_rows,\n"
- "clustered_index_size = :clustered_index_size,\n"
- "sum_of_other_index_sizes = "
- " :sum_of_other_index_sizes\n"
- "WHERE\n"
- "database_name = :database_name AND\n"
- "table_name = :table_name;\n"
- "END;");
- }
+ "END;", NULL);
if (ret != DB_SUCCESS) {
char buf[MAX_FULL_NAME_LEN];
@@ -2295,39 +2297,56 @@ dict_stats_save(
"%s: %s\n",
ut_format_name(table->name, TRUE, buf, sizeof(buf)),
ut_strerr(ret));
- goto end;
+
+ mutex_exit(&dict_sys->mutex);
+ rw_lock_x_unlock(&dict_operation_lock);
+
+ dict_stats_snapshot_free(table);
+
+ return(ret);
}
+ trx_t* trx = trx_allocate_for_background();
+ trx_start_if_not_started(trx);
+
dict_index_t* index;
+ index_map_t indexes;
+
+ /* Below we do all the modifications in innodb_index_stats in a single
+ transaction for performance reasons. Modifying more than one row in a
+ single transaction may deadlock with other transactions if they
+ lock the rows in different order. Other transaction could be for
+ example when we DROP a table and do
+ DELETE FROM innodb_index_stats WHERE database_name = '...'
+ AND table_name = '...'; which will affect more than one row. To
+ prevent deadlocks we always lock the rows in the same order - the
+ order of the PK, which is (database_name, table_name, index_name,
+ stat_name). This is why below we sort the indexes by name and then
+ for each index, do the mods ordered by stat_name. */
for (index = dict_table_get_first_index(table);
index != NULL;
index = dict_table_get_next_index(index)) {
- if (dict_stats_should_ignore_index(index)) {
- continue;
- }
+ indexes[index->name] = index;
+ }
- ut_ad(!dict_index_is_univ(index));
+ index_map_t::const_iterator it;
- ret = dict_stats_save_index_stat(index, now, "size",
- index->stat_index_size,
- NULL,
- "Number of pages "
- "in the index");
- if (ret != DB_SUCCESS) {
- goto end;
+ for (it = indexes.begin(); it != indexes.end(); ++it) {
+
+ index = it->second;
+
+ if (only_for_index != NULL && index->id != *only_for_index) {
+ continue;
}
- ret = dict_stats_save_index_stat(index, now, "n_leaf_pages",
- index->stat_n_leaf_pages,
- NULL,
- "Number of leaf pages "
- "in the index");
- if (ret != DB_SUCCESS) {
- goto end;
+ if (dict_stats_should_ignore_index(index)) {
+ continue;
}
+ ut_ad(!dict_index_is_univ(index));
+
for (ulint i = 0; i < index->n_uniq; i++) {
char stat_name[16];
@@ -2355,15 +2374,37 @@ dict_stats_save(
index, now, stat_name,
index->stat_n_diff_key_vals[i],
&index->stat_n_sample_sizes[i],
- stat_description);
+ stat_description, trx);
if (ret != DB_SUCCESS) {
goto end;
}
}
+
+ ret = dict_stats_save_index_stat(index, now, "n_leaf_pages",
+ index->stat_n_leaf_pages,
+ NULL,
+ "Number of leaf pages "
+ "in the index", trx);
+ if (ret != DB_SUCCESS) {
+ goto end;
+ }
+
+ ret = dict_stats_save_index_stat(index, now, "size",
+ index->stat_index_size,
+ NULL,
+ "Number of pages "
+ "in the index", trx);
+ if (ret != DB_SUCCESS) {
+ goto end;
+ }
}
+ trx_commit_for_mysql(trx);
+
end:
+ trx_free_for_background(trx);
+
mutex_exit(&dict_sys->mutex);
rw_lock_x_unlock(&dict_operation_lock);
@@ -2860,25 +2901,29 @@ dict_stats_update_for_index(
dict_table_stats_lock(index->table, RW_X_LATCH);
dict_stats_analyze_index(index);
dict_table_stats_unlock(index->table, RW_X_LATCH);
- dict_stats_save(index->table);
+ dict_stats_save(index->table, &index->id);
DBUG_VOID_RETURN;
}
/* else */
- /* Fall back to transient stats since the persistent
- storage is not present or is corrupted */
- char buf_table[MAX_FULL_NAME_LEN];
- char buf_index[MAX_FULL_NAME_LEN];
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Recalculation of persistent statistics "
- "requested for table %s index %s but the required "
- "persistent statistics storage is not present or is "
- "corrupted. Using transient stats instead.\n",
- ut_format_name(index->table->name, TRUE,
- buf_table, sizeof(buf_table)),
- ut_format_name(index->name, FALSE,
- buf_index, sizeof(buf_index)));
+ if (innodb_index_stats_not_found == false &&
+ index->stats_error_printed == false) {
+ /* Fall back to transient stats since the persistent
+ storage is not present or is corrupted */
+ char buf_table[MAX_FULL_NAME_LEN];
+ char buf_index[MAX_FULL_NAME_LEN];
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Recalculation of persistent statistics "
+ "requested for table %s index %s but the required "
+ "persistent statistics storage is not present or is "
+ "corrupted. Using transient stats instead.\n",
+ ut_format_name(index->table->name, TRUE,
+ buf_table, sizeof(buf_table)),
+ ut_format_name(index->name, FALSE,
+ buf_index, sizeof(buf_index)));
+ index->stats_error_printed = false;
+ }
}
dict_table_stats_lock(index->table, RW_X_LATCH);
@@ -2955,7 +3000,7 @@ dict_stats_update(
return(err);
}
- err = dict_stats_save(table);
+ err = dict_stats_save(table, NULL);
return(err);
}
@@ -2963,13 +3008,17 @@ dict_stats_update(
/* Fall back to transient stats since the persistent
storage is not present or is corrupted */
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Recalculation of persistent statistics "
- "requested for table %s but the required persistent "
- "statistics storage is not present or is corrupted. "
- "Using transient stats instead.\n",
- ut_format_name(table->name, TRUE, buf, sizeof(buf)));
+ if (innodb_table_stats_not_found == false &&
+ table->stats_error_printed == false) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Recalculation of persistent statistics "
+ "requested for table %s but the required persistent "
+ "statistics storage is not present or is corrupted. "
+ "Using transient stats instead.\n",
+ ut_format_name(table->name, TRUE, buf, sizeof(buf)));
+ table->stats_error_printed = true;
+ }
goto transient;
@@ -2988,7 +3037,7 @@ dict_stats_update(
if (dict_stats_persistent_storage_check(false)) {
- return(dict_stats_save(table));
+ return(dict_stats_save(table, NULL));
}
return(DB_STATS_DO_NOT_EXIST);
@@ -3013,17 +3062,21 @@ dict_stats_update(
/* persistent statistics storage does not exist
or is corrupted, calculate the transient stats */
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error: Fetch of persistent "
- "statistics requested for table %s but the "
- "required system tables %s and %s are not "
- "present or have unexpected structure. "
- "Using transient stats instead.\n",
- ut_format_name(table->name, TRUE,
- buf, sizeof(buf)),
- TABLE_STATS_NAME_PRINT,
- INDEX_STATS_NAME_PRINT);
+ if (innodb_table_stats_not_found == false &&
+ table->stats_error_printed == false) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error: Fetch of persistent "
+ "statistics requested for table %s but the "
+ "required system tables %s and %s are not "
+ "present or have unexpected structure. "
+ "Using transient stats instead.\n",
+ ut_format_name(table->name, TRUE,
+ buf, sizeof(buf)),
+ TABLE_STATS_NAME_PRINT,
+ INDEX_STATS_NAME_PRINT);
+ table->stats_error_printed = true;
+ }
goto transient;
}
@@ -3093,16 +3146,19 @@ dict_stats_update(
dict_stats_table_clone_free(t);
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Error fetching persistent statistics "
- "for table %s from %s and %s: %s. "
- "Using transient stats method instead.\n",
- ut_format_name(table->name, TRUE, buf,
- sizeof(buf)),
- TABLE_STATS_NAME,
- INDEX_STATS_NAME,
- ut_strerr(err));
+ if (innodb_table_stats_not_found == false &&
+ table->stats_error_printed == false) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Error fetching persistent statistics "
+ "for table %s from %s and %s: %s. "
+ "Using transient stats method instead.\n",
+ ut_format_name(table->name, TRUE, buf,
+ sizeof(buf)),
+ TABLE_STATS_NAME,
+ INDEX_STATS_NAME,
+ ut_strerr(err));
+ }
goto transient;
}
@@ -3178,7 +3234,7 @@ dict_stats_drop_index(
"database_name = :database_name AND\n"
"table_name = :table_name AND\n"
"index_name = :index_name;\n"
- "END;\n");
+ "END;\n", NULL);
mutex_exit(&dict_sys->mutex);
rw_lock_x_unlock(&dict_operation_lock);
@@ -3246,7 +3302,7 @@ dict_stats_delete_from_table_stats(
"DELETE FROM \"" TABLE_STATS_NAME "\" WHERE\n"
"database_name = :database_name AND\n"
"table_name = :table_name;\n"
- "END;\n");
+ "END;\n", NULL);
return(ret);
}
@@ -3284,7 +3340,7 @@ dict_stats_delete_from_index_stats(
"DELETE FROM \"" INDEX_STATS_NAME "\" WHERE\n"
"database_name = :database_name AND\n"
"table_name = :table_name;\n"
- "END;\n");
+ "END;\n", NULL);
return(ret);
}
@@ -3407,7 +3463,7 @@ dict_stats_rename_in_table_stats(
"WHERE\n"
"database_name = :old_dbname_utf8 AND\n"
"table_name = :old_tablename_utf8;\n"
- "END;\n");
+ "END;\n", NULL);
return(ret);
}
@@ -3453,7 +3509,7 @@ dict_stats_rename_in_index_stats(
"WHERE\n"
"database_name = :old_dbname_utf8 AND\n"
"table_name = :old_tablename_utf8;\n"
- "END;\n");
+ "END;\n", NULL);
return(ret);
}
@@ -3834,7 +3890,7 @@ test_dict_stats_save()
index2_stat_n_sample_sizes[2] = TEST_IDX2_N_DIFF3_SAMPLE_SIZE;
index2_stat_n_sample_sizes[3] = TEST_IDX2_N_DIFF4_SAMPLE_SIZE;
- ret = dict_stats_save(&table);
+ ret = dict_stats_save(&table, NULL);
ut_a(ret == DB_SUCCESS);
diff --git a/storage/xtradb/fil/fil0fil.cc b/storage/xtradb/fil/fil0fil.cc
index 5e797f2583c..8d219604a61 100644
--- a/storage/xtradb/fil/fil0fil.cc
+++ b/storage/xtradb/fil/fil0fil.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, 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
@@ -2409,27 +2409,21 @@ fil_op_log_parse_or_replay(
break;
case MLOG_FILE_RENAME:
- /* We do the rename based on space id, not old file name;
- this should guarantee that after the log replay each .ibd file
- has the correct name for the latest log sequence number; the
- proof is left as an exercise :) */
-
- if (fil_tablespace_exists_in_mem(space_id)) {
+ /* In order to replay the rename, the following must hold:
+ * The new name is not already used.
+ * A tablespace is open in memory with the old name.
+ * The space ID for that tablepace matches this log entry.
+ This will prevent unintended renames during recovery. */
+
+ if (fil_get_space_id_for_table(new_name) == ULINT_UNDEFINED
+ && space_id == fil_get_space_id_for_table(name)) {
/* Create the database directory for the new name, if
it does not exist yet */
fil_create_directory_for_tablename(new_name);
- /* Rename the table if there is not yet a tablespace
- with the same name */
-
- if (fil_get_space_id_for_table(new_name)
- == ULINT_UNDEFINED) {
- /* We do not care about the old name, that
- is why we pass NULL as the first argument. */
- if (!fil_rename_tablespace(NULL, space_id,
- new_name, NULL)) {
- ut_error;
- }
+ if (!fil_rename_tablespace(name, space_id,
+ new_name, NULL)) {
+ ut_error;
}
}
@@ -3631,17 +3625,6 @@ fil_report_bad_tablespace(
(ulong) expected_id, (ulong) expected_flags);
}
-struct fsp_open_info {
- ibool success; /*!< Has the tablespace been opened? */
- const char* check_msg; /*!< fil_check_first_page() message */
- ibool valid; /*!< Is the tablespace valid? */
- os_file_t file; /*!< File handle */
- char* filepath; /*!< File path to open */
- lsn_t lsn; /*!< Flushed LSN from header page */
- ulint id; /*!< Space ID */
- ulint flags; /*!< Tablespace flags */
-};
-
/********************************************************************//**
Tries to open a single-table tablespace and optionally checks that the
space id in it is correct. If this does not succeed, print an error message
@@ -4035,6 +4018,175 @@ fil_make_ibbackup_old_name(
}
#endif /* UNIV_HOTBACKUP */
+
+/*******************************************************************//**
+Determine the space id of the given file descriptor by reading a few
+pages from the beginning of the .ibd file.
+@return true if space id was successfully identified, or false. */
+static
+bool
+fil_user_tablespace_find_space_id(
+/*==============================*/
+ fsp_open_info* fsp) /* in/out: contains file descriptor, which is
+ used as input. contains space_id, which is
+ the output */
+{
+ bool st;
+ os_offset_t file_size;
+
+ file_size = os_file_get_size(fsp->file);
+
+ if (file_size == (os_offset_t) -1) {
+ ib_logf(IB_LOG_LEVEL_ERROR, "Could not get file size: %s",
+ fsp->filepath);
+ return(false);
+ }
+
+ /* Assuming a page size, read the space_id from each page and store it
+ in a map. Find out which space_id is agreed on by majority of the
+ pages. Choose that space_id. */
+ for (ulint page_size = UNIV_ZIP_SIZE_MIN;
+ page_size <= UNIV_PAGE_SIZE_MAX; page_size <<= 1) {
+
+ /* map[space_id] = count of pages */
+ std::map<ulint, ulint> verify;
+
+ ulint page_count = 64;
+ ulint valid_pages = 0;
+
+ /* Adjust the number of pages to analyze based on file size */
+ while ((page_count * page_size) > file_size) {
+ --page_count;
+ }
+
+ ib_logf(IB_LOG_LEVEL_INFO, "Page size:%lu Pages to analyze:"
+ "%lu", page_size, page_count);
+
+ byte* buf = static_cast<byte*>(ut_malloc(2*page_size));
+ byte* page = static_cast<byte*>(ut_align(buf, page_size));
+
+ for (ulint j = 0; j < page_count; ++j) {
+
+ st = os_file_read(fsp->file, page, (j* page_size), page_size);
+
+ if (!st) {
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "READ FAIL: page_no:%lu", j);
+ continue;
+ }
+
+ bool uncompressed_ok = false;
+
+ /* For uncompressed pages, the page size must be equal
+ to UNIV_PAGE_SIZE. */
+ if (page_size == UNIV_PAGE_SIZE) {
+ uncompressed_ok = !buf_page_is_corrupted(
+ false, page, 0);
+ }
+
+ bool compressed_ok = !buf_page_is_corrupted(
+ false, page, page_size);
+
+ if (uncompressed_ok || compressed_ok) {
+
+ ulint space_id = mach_read_from_4(page
+ + FIL_PAGE_SPACE_ID);
+
+ if (space_id > 0) {
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "VALID: space:%lu "
+ "page_no:%lu page_size:%lu",
+ space_id, j, page_size);
+ verify[space_id]++;
+ ++valid_pages;
+ }
+ }
+ }
+
+ ut_free(buf);
+
+ ib_logf(IB_LOG_LEVEL_INFO, "Page size: %lu, Possible space_id "
+ "count:%lu", page_size, (ulint) verify.size());
+
+ const ulint pages_corrupted = 3;
+ for (ulint missed = 0; missed <= pages_corrupted; ++missed) {
+
+ for (std::map<ulint, ulint>::iterator
+ m = verify.begin(); m != verify.end(); ++m ) {
+
+ ib_logf(IB_LOG_LEVEL_INFO, "space_id:%lu, "
+ "Number of pages matched: %lu/%lu "
+ "(%lu)", m->first, m->second,
+ valid_pages, page_size);
+
+ if (m->second == (valid_pages - missed)) {
+
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Chosen space:%lu\n", m->first);
+
+ fsp->id = m->first;
+ return(true);
+ }
+ }
+
+ }
+ }
+
+ return(false);
+}
+
+/*******************************************************************//**
+Finds the given page_no of the given space id from the double write buffer,
+and copies it to the corresponding .ibd file.
+@return true if copy was successful, or false. */
+bool
+fil_user_tablespace_restore_page(
+/*==============================*/
+ fsp_open_info* fsp, /* in: contains space id and .ibd
+ file information */
+ ulint page_no) /* in: page_no to obtain from double
+ write buffer */
+{
+ bool err;
+ ulint flags;
+ ulint zip_size;
+ ulint page_size;
+ ulint buflen;
+ byte* page;
+
+ ib_logf(IB_LOG_LEVEL_INFO, "Restoring page %lu of tablespace %lu",
+ page_no, fsp->id);
+
+ // find if double write buffer has page_no of given space id
+ page = recv_sys->dblwr.find_page(fsp->id, page_no);
+
+ if (!page) {
+ ib_logf(IB_LOG_LEVEL_WARN, "Doublewrite does not have "
+ "page_no=%lu of space: %lu", page_no, fsp->id);
+ err = false;
+ goto out;
+ }
+
+ flags = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page);
+ zip_size = fsp_flags_get_zip_size(flags);
+ page_size = fsp_flags_get_page_size(flags);
+
+ ut_ad(page_no == page_get_page_no(page));
+
+ buflen = zip_size ? zip_size: page_size;
+
+ ib_logf(IB_LOG_LEVEL_INFO, "Writing %lu bytes into file: %s",
+ buflen, fsp->filepath);
+
+ err = os_file_write(fsp->filepath, fsp->file, page,
+ (zip_size ? zip_size : page_size) * page_no,
+ buflen);
+
+ os_file_flush(fsp->file);
+out:
+ return(err);
+}
+
/********************************************************************//**
Opens an .ibd file and adds the associated single-table tablespace to the
InnoDB fil0fil.cc data structures.
@@ -4046,6 +4198,10 @@ fil_validate_single_table_tablespace(
const char* tablename, /*!< in: database/tablename */
fsp_open_info* fsp) /*!< in/out: tablespace info */
{
+ bool restore_attempted = false;
+
+check_first_page:
+ fsp->success = TRUE;
if (const char* check_msg = fil_read_first_page(
fsp->file, FALSE, &fsp->flags, &fsp->id,
&fsp->lsn, &fsp->lsn)) {
@@ -4053,6 +4209,21 @@ fil_validate_single_table_tablespace(
"%s in tablespace %s (table %s)",
check_msg, fsp->filepath, tablename);
fsp->success = FALSE;
+ }
+
+ if (!fsp->success) {
+ if (!restore_attempted) {
+ if (!fil_user_tablespace_find_space_id(fsp)) {
+ return;
+ }
+ restore_attempted = true;
+
+ if (fsp->id > 0
+ && !fil_user_tablespace_restore_page(fsp, 0)) {
+ return;
+ }
+ goto check_first_page;
+ }
return;
}
@@ -4170,7 +4341,7 @@ fil_load_single_table_tablespace(
/* Try to open the tablespace in the datadir. */
def.file = os_file_create_simple_no_error_handling(
innodb_file_data_key, def.filepath, OS_FILE_OPEN,
- OS_FILE_READ_ONLY, &def.success);
+ OS_FILE_READ_WRITE, &def.success);
/* Read the first page of the remote tablespace */
if (def.success) {
@@ -5372,7 +5543,7 @@ _fil_io(
ulint mode;
fil_space_t* space;
fil_node_t* node;
- ibool ret;
+ ibool ret=TRUE;
ulint is_log;
ulint wake_later;
os_offset_t offset;
@@ -5596,7 +5767,6 @@ _fil_io(
offset, len);
}
#endif /* !UNIV_HOTBACKUP */
- ut_a(ret);
if (mode == OS_AIO_SYNC) {
/* The i/o operation is already completed when we return from
@@ -5611,7 +5781,11 @@ _fil_io(
ut_ad(fil_validate_skip());
}
- return(DB_SUCCESS);
+ if (!ret) {
+ return(DB_OUT_OF_FILE_SPACE);
+ } else {
+ return(DB_SUCCESS);
+ }
}
#ifndef UNIV_HOTBACKUP
diff --git a/storage/xtradb/fts/fts0ast.cc b/storage/xtradb/fts/fts0ast.cc
index 3a03fc63303..d6c19c0050a 100644
--- a/storage/xtradb/fts/fts0ast.cc
+++ b/storage/xtradb/fts/fts0ast.cc
@@ -112,9 +112,11 @@ fts_ast_create_node_term(
if (str.f_n_char > 0) {
/* If the subsequent term (after the first one)'s size
- is less than fts_min_token_size, we shall ignore
- that. This is to make consistent with MyISAM behavior */
- if (first_node && (str.f_n_char < fts_min_token_size)) {
+ is less than fts_min_token_size or the term is greater
+ than fts_max_token_size, we shall ignore that. This is
+ to make consistent with MyISAM behavior */
+ if ((first_node && (str.f_n_char < fts_min_token_size))
+ || str.f_n_char > fts_max_token_size) {
continue;
}
@@ -394,6 +396,10 @@ fts_ast_term_set_distance(
ulint distance) /*!< in: the text proximity
distance */
{
+ if (node == NULL) {
+ return;
+ }
+
ut_a(node->type == FTS_AST_TEXT);
ut_a(node->text.distance == ULINT_UNDEFINED);
@@ -551,14 +557,6 @@ fts_ast_visit(
break;
- case FTS_AST_SUBEXP_LIST:
- if (visit_pass != FTS_PASS_FIRST) {
- break;
- }
-
- error = fts_ast_visit_sub_exp(node, visitor, arg);
- break;
-
case FTS_AST_OPER:
oper = node->oper;
oper_node = node;
diff --git a/storage/xtradb/fts/fts0blex.cc b/storage/xtradb/fts/fts0blex.cc
index dccedac0212..f83523825d2 100644
--- a/storage/xtradb/fts/fts0blex.cc
+++ b/storage/xtradb/fts/fts0blex.cc
@@ -35,7 +35,7 @@
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
+ * if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
@@ -52,7 +52,7 @@ typedef uint32_t flex_uint32_t;
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
+typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
@@ -184,15 +184,15 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
#define EOB_ACT_END_OF_FILE 1
#define EOB_ACT_LAST_MATCH 2
- #define YY_LESS_LINENO(n)
-
+#define YY_LESS_LINENO(n)
+
/* Return all but the first "n" matched characters back to the input stream. */
#define yyless(n) \
do \
{ \
/* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
*yy_cp = yyg->yy_hold_char; \
YY_RESTORE_YY_MORE_OFFSET \
yyg->yy_c_buf_p = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
@@ -245,9 +245,9 @@ struct yy_buffer_state
*/
int yy_at_bol;
- int yy_bs_lineno; /**< The line count. */
- int yy_bs_column; /**< The column count. */
-
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
@@ -305,18 +305,18 @@ YY_BUFFER_STATE fts0b_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner
YY_BUFFER_STATE fts0b_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
YY_BUFFER_STATE fts0b_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
-void *fts0balloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
-void *fts0brealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
-void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
+void *fts0balloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
+void *fts0brealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
+void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
#define yy_new_buffer fts0b_create_buffer
#define yy_set_interactive(is_interactive) \
{ \
if ( ! YY_CURRENT_BUFFER ){ \
- fts0bensure_buffer_stack (yyscanner); \
+ fts0bensure_buffer_stack (yyscanner); \
YY_CURRENT_BUFFER_LVALUE = \
- fts0b_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ fts0b_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
} \
YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
}
@@ -324,9 +324,9 @@ void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attri
#define yy_set_bol(at_bol) \
{ \
if ( ! YY_CURRENT_BUFFER ){\
- fts0bensure_buffer_stack (yyscanner); \
+ fts0bensure_buffer_stack (yyscanner); \
YY_CURRENT_BUFFER_LVALUE = \
- fts0b_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
+ fts0b_create_buffer(yyin,YY_BUF_SIZE ,yyscanner); \
} \
YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
}
@@ -347,14 +347,14 @@ typedef int yy_state_type;
static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
static int yy_get_next_buffer (yyscan_t yyscanner );
-static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
+static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
/* Done after the current pattern has been matched and before the
* corresponding action - sets up yytext.
*/
#define YY_DO_BEFORE_ACTION \
yyg->yytext_ptr = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
+ yyleng = static_cast<int>(yy_cp - yy_bp); \
yyg->yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \
yyg->yy_c_buf_p = yy_cp;
@@ -499,37 +499,37 @@ this program; if not, write to the Free Software Foundation, Inc.,
/* Holds the entire state of the reentrant scanner. */
struct yyguts_t
- {
-
- /* User-defined. Not touched by flex. */
- YY_EXTRA_TYPE yyextra_r;
-
- /* The rest are the same as the globals declared in the non-reentrant scanner. */
- FILE *yyin_r, *yyout_r;
- size_t yy_buffer_stack_top; /**< index of top of stack. */
- size_t yy_buffer_stack_max; /**< capacity of stack. */
- YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
- char yy_hold_char;
- int yy_n_chars;
- int yyleng_r;
- char *yy_c_buf_p;
- int yy_init;
- int yy_start;
- int yy_did_buffer_switch_on_eof;
- int yy_start_stack_ptr;
- int yy_start_stack_depth;
- int *yy_start_stack;
- yy_state_type yy_last_accepting_state;
- char* yy_last_accepting_cpos;
-
- int yylineno_r;
- int yy_flex_debug_r;
-
- char *yytext_r;
- int yy_more_flag;
- int yy_more_len;
-
- }; /* end struct yyguts_t */
+{
+
+ /* User-defined. Not touched by flex. */
+ YY_EXTRA_TYPE yyextra_r;
+
+ /* The rest are the same as the globals declared in the non-reentrant scanner. */
+ FILE *yyin_r, *yyout_r;
+ size_t yy_buffer_stack_top; /**< index of top of stack. */
+ size_t yy_buffer_stack_max; /**< capacity of stack. */
+ YY_BUFFER_STATE * yy_buffer_stack; /**< Stack as an array. */
+ char yy_hold_char;
+ int yy_n_chars;
+ int yyleng_r;
+ char *yy_c_buf_p;
+ int yy_init;
+ int yy_start;
+ int yy_did_buffer_switch_on_eof;
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int *yy_start_stack;
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ int yylineno_r;
+ int yy_flex_debug_r;
+
+ char *yytext_r;
+ int yy_more_flag;
+ int yy_more_len;
+
+}; /* end struct yyguts_t */
static int yy_init_globals (yyscan_t yyscanner );
@@ -579,11 +579,11 @@ extern int fts0bwrap (yyscan_t yyscanner );
#endif
#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
+static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
+static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
#endif
#ifndef YY_NO_INPUT
@@ -622,8 +622,8 @@ static int input (yyscan_t yyscanner );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
- size_t n; \
- for ( n = 0; n < max_size && \
+ int n; \
+ for ( n = 0; n < static_cast<int>(max_size) && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
if ( c == '\n' ) \
@@ -635,7 +635,8 @@ static int input (yyscan_t yyscanner );
else \
{ \
errno=0; \
- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ while ( (result = static_cast<int>(fread(buf, 1, max_size, yyin))) \
+ == 0 && ferror(yyin) ) \
{ \
if( errno != EINTR) \
{ \
@@ -703,12 +704,12 @@ YY_DECL
register yy_state_type yy_current_state;
register char *yy_cp, *yy_bp;
register int yy_act;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
#line 43 "fts0blex.l"
-#line 711 "fts0blex.cc"
+#line 712 "fts0blex.cc"
if ( !yyg->yy_init )
{
@@ -839,7 +840,7 @@ YY_RULE_SETUP
#line 73 "fts0blex.l"
ECHO;
YY_BREAK
-#line 842 "fts0blex.cc"
+#line 843 "fts0blex.cc"
case YY_STATE_EOF(INITIAL):
yyterminate();
@@ -982,7 +983,7 @@ case YY_STATE_EOF(INITIAL):
*/
static int yy_get_next_buffer (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
register char *source = yyg->yytext_ptr;
register int number_to_move, i;
@@ -1027,8 +1028,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else
{
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+ int num_to_read = static_cast<int>(
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1);
while ( num_to_read <= 0 )
{ /* Not enough room in the buffer - grow it. */
@@ -1041,7 +1042,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
if ( b->yy_is_our_buffer )
{
- int new_size = b->yy_buf_size * 2;
+ int new_size = static_cast<int>(b->yy_buf_size * 2);
if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8;
@@ -1062,8 +1063,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
- num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
- number_to_move - 1;
+ num_to_read = static_cast<int>(
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1);
}
@@ -1072,7 +1073,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
/* Read in more data. */
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- yyg->yy_n_chars, (size_t) num_to_read );
+ yyg->yy_n_chars, num_to_read);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
}
@@ -1115,11 +1116,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
/* yy_get_previous_state - get the state just before the EOB char was reached */
- static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
+static yy_state_type yy_get_previous_state (yyscan_t yyscanner)
{
register yy_state_type yy_current_state;
register char *yy_cp;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
yy_current_state = yyg->yy_start;
@@ -1148,10 +1149,10 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
* synopsis
* next_state = yy_try_NUL_trans( current_state );
*/
- static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
+static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state , yyscan_t yyscanner)
{
register int yy_is_jam;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner; /* This var may be unused depending upon options. */
register char *yy_cp = yyg->yy_c_buf_p;
register YY_CHAR yy_c = 1;
@@ -1174,14 +1175,14 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
#ifndef YY_NO_INPUT
#ifdef __cplusplus
- static int yyinput (yyscan_t yyscanner)
+ static int yyinput (yyscan_t yyscanner)
#else
- static int input (yyscan_t yyscanner)
+ static int input (yyscan_t yyscanner)
#endif
{
int c;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
*yyg->yy_c_buf_p = yyg->yy_hold_char;
@@ -1252,14 +1253,14 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
* @param yyscanner The scanner object.
* @note This function does not reset the start condition to @c INITIAL .
*/
- void fts0brestart (FILE * input_file , yyscan_t yyscanner)
+void fts0brestart (FILE * input_file , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if ( ! YY_CURRENT_BUFFER ){
- fts0bensure_buffer_stack (yyscanner);
+ fts0bensure_buffer_stack (yyscanner);
YY_CURRENT_BUFFER_LVALUE =
- fts0b_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
+ fts0b_create_buffer(yyin,YY_BUF_SIZE ,yyscanner);
}
fts0b_init_buffer(YY_CURRENT_BUFFER,input_file ,yyscanner);
@@ -1270,15 +1271,15 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
* @param new_buffer The new input buffer.
* @param yyscanner The scanner object.
*/
- void fts0b_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
+void fts0b_switch_to_buffer (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
/* TODO. We should be able to replace this entire function body
* with
* fts0bpop_buffer_state();
* fts0bpush_buffer_state(new_buffer);
- */
+ */
fts0bensure_buffer_stack (yyscanner);
if ( YY_CURRENT_BUFFER == new_buffer )
return;
@@ -1304,7 +1305,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
static void fts0b_load_buffer_state (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
yyg->yy_n_chars = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
yyg->yytext_ptr = yyg->yy_c_buf_p = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
@@ -1317,10 +1318,10 @@ static void fts0b_load_buffer_state (yyscan_t yyscanner)
* @param yyscanner The scanner object.
* @return the allocated buffer state.
*/
- YY_BUFFER_STATE fts0b_create_buffer (FILE * file, int size , yyscan_t yyscanner)
+YY_BUFFER_STATE fts0b_create_buffer (FILE * file, int size , yyscan_t yyscanner)
{
YY_BUFFER_STATE b;
-
+
b = (YY_BUFFER_STATE) fts0balloc(sizeof( struct yy_buffer_state ) ,yyscanner );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in fts0b_create_buffer()" );
@@ -1345,9 +1346,9 @@ static void fts0b_load_buffer_state (yyscan_t yyscanner)
* @param b a buffer created with fts0b_create_buffer()
* @param yyscanner The scanner object.
*/
- void fts0b_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+void fts0b_delete_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if ( ! b )
return;
@@ -1365,28 +1366,28 @@ static void fts0b_load_buffer_state (yyscan_t yyscanner)
* This function is sometimes called more than once on the same buffer,
* such as during a fts0brestart() or at EOF.
*/
- static void fts0b_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
+static void fts0b_init_buffer (YY_BUFFER_STATE b, FILE * file , yyscan_t yyscanner)
{
int oerrno = errno;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
fts0b_flush_buffer(b ,yyscanner);
b->yy_input_file = file;
b->yy_fill_buffer = 1;
- /* If b is the current buffer, then fts0b_init_buffer was _probably_
- * called from fts0brestart() or through yy_get_next_buffer.
- * In that case, we don't want to reset the lineno or column.
- */
- if (b != YY_CURRENT_BUFFER){
- b->yy_bs_lineno = 1;
- b->yy_bs_column = 0;
- }
-
- b->yy_is_interactive = 0;
-
+ /* If b is the current buffer, then fts0b_init_buffer was _probably_
+ * called from fts0brestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = 0;
+
errno = oerrno;
}
@@ -1394,9 +1395,9 @@ static void fts0b_load_buffer_state (yyscan_t yyscanner)
* @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
* @param yyscanner The scanner object.
*/
- void fts0b_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
+void fts0b_flush_buffer (YY_BUFFER_STATE b , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if ( ! b )
return;
@@ -1426,7 +1427,7 @@ static void fts0b_load_buffer_state (yyscan_t yyscanner)
*/
void fts0bpush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if (new_buffer == NULL)
return;
@@ -1457,7 +1458,7 @@ void fts0bpush_buffer_state (YY_BUFFER_STATE new_buffer , yyscan_t yyscanner)
*/
void fts0bpop_buffer_state (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if (!YY_CURRENT_BUFFER)
return;
@@ -1478,23 +1479,23 @@ void fts0bpop_buffer_state (yyscan_t yyscanner)
static void fts0bensure_buffer_stack (yyscan_t yyscanner)
{
int num_to_alloc;
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
if (!yyg->yy_buffer_stack) {
/* First allocation is just for 2 elements, since we don't know if this
* scanner will even need a stack. We use 2 instead of 1 to avoid an
* immediate realloc on the next call.
- */
+ */
num_to_alloc = 1;
yyg->yy_buffer_stack = (struct yy_buffer_state**)fts0balloc
(num_to_alloc * sizeof(struct yy_buffer_state*)
, yyscanner);
if ( ! yyg->yy_buffer_stack )
YY_FATAL_ERROR( "out of dynamic memory in fts0bensure_buffer_stack()" );
-
+
memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
+
yyg->yy_buffer_stack_max = num_to_alloc;
yyg->yy_buffer_stack_top = 0;
return;
@@ -1505,7 +1506,7 @@ static void fts0bensure_buffer_stack (yyscan_t yyscanner)
/* Increase the buffer to prepare for a possible push. */
int grow_size = 8 /* arbitrary grow size */;
- num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ num_to_alloc = static_cast<int>(yyg->yy_buffer_stack_max + grow_size);
yyg->yy_buffer_stack = (struct yy_buffer_state**)fts0brealloc
(yyg->yy_buffer_stack,
num_to_alloc * sizeof(struct yy_buffer_state*)
@@ -1523,12 +1524,12 @@ static void fts0bensure_buffer_stack (yyscan_t yyscanner)
* @param base the character buffer
* @param size the size in bytes of the character buffer
* @param yyscanner The scanner object.
- * @return the newly allocated buffer state object.
+ * @return the newly allocated buffer state object.
*/
YY_BUFFER_STATE fts0b_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
{
YY_BUFFER_STATE b;
-
+
if ( size < 2 ||
base[size-2] != YY_END_OF_BUFFER_CHAR ||
base[size-1] != YY_END_OF_BUFFER_CHAR )
@@ -1543,7 +1544,7 @@ YY_BUFFER_STATE fts0b_scan_buffer (char * base, yy_size_t size , yyscan_t yysc
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
b->yy_input_file = 0;
- b->yy_n_chars = b->yy_buf_size;
+ b->yy_n_chars = static_cast<int>(b->yy_buf_size);
b->yy_is_interactive = 0;
b->yy_at_bol = 1;
b->yy_fill_buffer = 0;
@@ -1564,8 +1565,7 @@ YY_BUFFER_STATE fts0b_scan_buffer (char * base, yy_size_t size , yyscan_t yysc
*/
YY_BUFFER_STATE fts0b_scan_string (yyconst char * yystr , yyscan_t yyscanner)
{
-
- return fts0b_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+ return fts0b_scan_bytes(yystr,static_cast<int>(strlen(yystr)), yyscanner);
}
/** Setup the input buffer state to scan the given bytes. The next call to fts0blex() will
@@ -1581,7 +1581,7 @@ YY_BUFFER_STATE fts0b_scan_bytes (yyconst char * yybytes, int _yybytes_len , y
char *buf;
yy_size_t n;
int i;
-
+
/* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2;
buf = (char *) fts0balloc(n ,yyscanner );
@@ -1609,9 +1609,9 @@ YY_BUFFER_STATE fts0b_scan_bytes (yyconst char * yybytes, int _yybytes_len , y
#define YY_EXIT_FAILURE 2
#endif
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
- (void) fprintf( stderr, "%s\n", msg );
+ (void) fprintf( stderr, "%s\n", msg );
exit( YY_EXIT_FAILURE );
}
@@ -1622,8 +1622,8 @@ static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attri
do \
{ \
/* Undo effects of setting up yytext. */ \
- int yyless_macro_arg = (n); \
- YY_LESS_LINENO(yyless_macro_arg);\
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
yytext[yyleng] = yyg->yy_hold_char; \
yyg->yy_c_buf_p = yytext + yyless_macro_arg; \
yyg->yy_hold_char = *yyg->yy_c_buf_p; \
@@ -1639,8 +1639,8 @@ static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attri
*/
YY_EXTRA_TYPE fts0bget_extra (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyextra;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyextra;
}
/** Get the current line number.
@@ -1648,12 +1648,12 @@ YY_EXTRA_TYPE fts0bget_extra (yyscan_t yyscanner)
*/
int fts0bget_lineno (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- if (! YY_CURRENT_BUFFER)
- return 0;
-
- return yylineno;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yylineno;
}
/** Get the current column number.
@@ -1661,12 +1661,12 @@ int fts0bget_lineno (yyscan_t yyscanner)
*/
int fts0bget_column (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
- if (! YY_CURRENT_BUFFER)
- return 0;
-
- return yycolumn;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ if (! YY_CURRENT_BUFFER)
+ return 0;
+
+ return yycolumn;
}
/** Get the input stream.
@@ -1674,8 +1674,8 @@ int fts0bget_column (yyscan_t yyscanner)
*/
FILE *fts0bget_in (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyin;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyin;
}
/** Get the output stream.
@@ -1683,8 +1683,8 @@ FILE *fts0bget_in (yyscan_t yyscanner)
*/
FILE *fts0bget_out (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyout;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyout;
}
/** Get the length of the current token.
@@ -1692,8 +1692,8 @@ FILE *fts0bget_out (yyscan_t yyscanner)
*/
int fts0bget_leng (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yyleng;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yyleng;
}
/** Get the current token.
@@ -1702,8 +1702,8 @@ int fts0bget_leng (yyscan_t yyscanner)
char *fts0bget_text (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yytext;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yytext;
}
/** Set the user-defined data. This data is never touched by the scanner.
@@ -1712,8 +1712,8 @@ char *fts0bget_text (yyscan_t yyscanner)
*/
void fts0bset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyextra = user_defined ;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyextra = user_defined ;
}
/** Set the current line number.
@@ -1722,13 +1722,13 @@ void fts0bset_extra (YY_EXTRA_TYPE user_defined , yyscan_t yyscanner)
*/
void fts0bset_lineno (int line_number , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+
+ /* lineno is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "fts0bset_lineno called with no buffer" , yyscanner);
- /* lineno is only valid if an input buffer exists. */
- if (! YY_CURRENT_BUFFER )
- yy_fatal_error( "fts0bset_lineno called with no buffer" , yyscanner);
-
- yylineno = line_number;
+ yylineno = line_number;
}
/** Set the current column.
@@ -1737,13 +1737,13 @@ void fts0bset_lineno (int line_number , yyscan_t yyscanner)
*/
void fts0bset_column (int column_no , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- /* column is only valid if an input buffer exists. */
- if (! YY_CURRENT_BUFFER )
- yy_fatal_error( "fts0bset_column called with no buffer" , yyscanner);
-
- yycolumn = column_no;
+ /* column is only valid if an input buffer exists. */
+ if (! YY_CURRENT_BUFFER )
+ yy_fatal_error( "fts0bset_column called with no buffer" , yyscanner);
+
+ yycolumn = column_no;
}
/** Set the input stream. This does not discard the current
@@ -1754,26 +1754,26 @@ void fts0bset_column (int column_no , yyscan_t yyscanner)
*/
void fts0bset_in (FILE * in_str , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyin = in_str ;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyin = in_str ;
}
void fts0bset_out (FILE * out_str , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yyout = out_str ;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yyout = out_str ;
}
int fts0bget_debug (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- return yy_flex_debug;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ return yy_flex_debug;
}
void fts0bset_debug (int bdebug , yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- yy_flex_debug = bdebug ;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ yy_flex_debug = bdebug ;
}
/* Accessor methods for yylval and yylloc */
@@ -1788,22 +1788,22 @@ void fts0bset_debug (int bdebug , yyscan_t yyscanner)
int fts0blex_init(yyscan_t* ptr_yy_globals)
{
- if (ptr_yy_globals == NULL){
- errno = EINVAL;
- return 1;
- }
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
- *ptr_yy_globals = (yyscan_t) fts0balloc ( sizeof( struct yyguts_t ), NULL );
+ *ptr_yy_globals = (yyscan_t) fts0balloc ( sizeof( struct yyguts_t ), NULL );
- if (*ptr_yy_globals == NULL){
- errno = ENOMEM;
- return 1;
- }
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
- /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
- memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+ /* By setting to 0xAA, we expose bugs in yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
- return yy_init_globals ( *ptr_yy_globals );
+ return yy_init_globals ( *ptr_yy_globals );
}
/* fts0blex_init_extra has the same functionality as fts0blex_init, but follows the
@@ -1817,70 +1817,70 @@ int fts0blex_init(yyscan_t* ptr_yy_globals)
int fts0blex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
{
- struct yyguts_t dummy_yyguts;
-
- fts0bset_extra (yy_user_defined, &dummy_yyguts);
-
- if (ptr_yy_globals == NULL){
- errno = EINVAL;
- return 1;
- }
-
- *ptr_yy_globals = (yyscan_t) fts0balloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-
- if (*ptr_yy_globals == NULL){
- errno = ENOMEM;
- return 1;
- }
-
- /* By setting to 0xAA, we expose bugs in
- yy_init_globals. Leave at 0x00 for releases. */
- memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-
- fts0bset_extra (yy_user_defined, *ptr_yy_globals);
-
- return yy_init_globals ( *ptr_yy_globals );
+ struct yyguts_t dummy_yyguts;
+
+ fts0bset_extra (yy_user_defined, &dummy_yyguts);
+
+ if (ptr_yy_globals == NULL){
+ errno = EINVAL;
+ return 1;
+ }
+
+ *ptr_yy_globals = (yyscan_t) fts0balloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
+
+ if (*ptr_yy_globals == NULL){
+ errno = ENOMEM;
+ return 1;
+ }
+
+ /* By setting to 0xAA, we expose bugs in
+ yy_init_globals. Leave at 0x00 for releases. */
+ memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
+
+ fts0bset_extra (yy_user_defined, *ptr_yy_globals);
+
+ return yy_init_globals ( *ptr_yy_globals );
}
static int yy_init_globals (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- /* Initialization is the same as for the non-reentrant scanner.
- * This function is called from fts0blex_destroy(), so don't allocate here.
- */
-
- yyg->yy_buffer_stack = 0;
- yyg->yy_buffer_stack_top = 0;
- yyg->yy_buffer_stack_max = 0;
- yyg->yy_c_buf_p = (char *) 0;
- yyg->yy_init = 0;
- yyg->yy_start = 0;
-
- yyg->yy_start_stack_ptr = 0;
- yyg->yy_start_stack_depth = 0;
- yyg->yy_start_stack = NULL;
-
-/* Defined in main.c */
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from fts0blex_destroy(), so don't allocate here.
+ */
+
+ yyg->yy_buffer_stack = 0;
+ yyg->yy_buffer_stack_top = 0;
+ yyg->yy_buffer_stack_max = 0;
+ yyg->yy_c_buf_p = (char *) 0;
+ yyg->yy_init = 0;
+ yyg->yy_start = 0;
+
+ yyg->yy_start_stack_ptr = 0;
+ yyg->yy_start_stack_depth = 0;
+ yyg->yy_start_stack = NULL;
+
+ /* Defined in main.c */
#ifdef YY_STDINIT
- yyin = stdin;
- yyout = stdout;
+ yyin = stdin;
+ yyout = stdout;
#else
- yyin = (FILE *) 0;
- yyout = (FILE *) 0;
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
#endif
- /* For future reference: Set errno on error, since we are called by
- * fts0blex_init()
- */
- return 0;
+ /* For future reference: Set errno on error, since we are called by
+ * fts0blex_init()
+ */
+ return 0;
}
/* fts0blex_destroy is for both reentrant and non-reentrant scanners. */
int fts0blex_destroy (yyscan_t yyscanner)
{
- struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
+ struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
- /* Pop the buffer stack, destroying each element. */
+ /* Pop the buffer stack, destroying each element. */
while(YY_CURRENT_BUFFER){
fts0b_delete_buffer(YY_CURRENT_BUFFER ,yyscanner );
YY_CURRENT_BUFFER_LVALUE = NULL;
@@ -1891,18 +1891,18 @@ int fts0blex_destroy (yyscan_t yyscanner)
fts0bfree(yyg->yy_buffer_stack ,yyscanner);
yyg->yy_buffer_stack = NULL;
- /* Destroy the start condition stack. */
- fts0bfree(yyg->yy_start_stack ,yyscanner );
- yyg->yy_start_stack = NULL;
+ /* Destroy the start condition stack. */
+ fts0bfree(yyg->yy_start_stack ,yyscanner );
+ yyg->yy_start_stack = NULL;
- /* Reset the globals. This is important in a non-reentrant scanner so the next time
- * fts0blex() is called, initialization will occur. */
- yy_init_globals( yyscanner);
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * fts0blex() is called, initialization will occur. */
+ yy_init_globals( yyscanner);
- /* Destroy the main struct (reentrant only). */
- fts0bfree ( yyscanner , yyscanner );
- yyscanner = NULL;
- return 0;
+ /* Destroy the main struct (reentrant only). */
+ fts0bfree ( yyscanner , yyscanner );
+ yyscanner = NULL;
+ return 0;
}
/*
@@ -1910,7 +1910,7 @@ int fts0blex_destroy (yyscan_t yyscanner)
*/
#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
register int i;
for ( i = 0; i < n; ++i )
@@ -1919,7 +1919,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
register int n;
for ( n = 0; s[n]; ++n )
@@ -1929,12 +1929,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribu
}
#endif
-void *fts0balloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+void *fts0balloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
return (void *) malloc( size );
}
-void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
@@ -1946,7 +1946,7 @@ void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __at
return (void *) realloc( (char *) ptr, size );
}
-void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
free( (char *) ptr ); /* see fts0brealloc() for (char *) cast */
}
@@ -1955,5 +1955,3 @@ void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __
#line 73 "fts0blex.l"
-
-
diff --git a/storage/xtradb/fts/fts0config.cc b/storage/xtradb/fts/fts0config.cc
index c5cf38ca7f9..5b4ae5c39f7 100644
--- a/storage/xtradb/fts/fts0config.cc
+++ b/storage/xtradb/fts/fts0config.cc
@@ -151,7 +151,9 @@ fts_config_create_index_param_name(
strcpy(name, param);
name[len] = '_';
- fts_write_object_id(index->id, name + len + 1);
+ fts_write_object_id(index->id, name + len + 1,
+ DICT_TF2_FLAG_IS_SET(index->table,
+ DICT_TF2_FTS_AUX_HEX_NAME));
return(name);
}
diff --git a/storage/xtradb/fts/fts0fts.cc b/storage/xtradb/fts/fts0fts.cc
index 1b114adea1f..795f08da966 100644
--- a/storage/xtradb/fts/fts0fts.cc
+++ b/storage/xtradb/fts/fts0fts.cc
@@ -1608,7 +1608,8 @@ fts_rename_aux_tables(
new_name, old_table_name, trx);
DBUG_EXECUTE_IF("fts_rename_failure",
- err = DB_DEADLOCK;);
+ err = DB_DEADLOCK;
+ fts_sql_rollback(trx););
mem_free(old_table_name);
@@ -1949,7 +1950,7 @@ fts_create_one_index_table(
ut_ad(index->type & DICT_FTS);
- new_table = dict_mem_table_create(table_name, 0, 5, 1, 0);
+ new_table = dict_mem_table_create(table_name, 0, 5, 1, 0, false);
field = dict_index_get_nth_field(index, 0);
charset = innobase_get_fts_charset(
@@ -2018,7 +2019,7 @@ fts_create_index_tables_low(
fts_table.index_id = index->id;
fts_table.table_id = table_id;
fts_table.parent = table_name;
- fts_table.table = NULL;
+ fts_table.table = index->table;
#ifdef FTS_DOC_STATS_DEBUG
char* sql;
@@ -4479,7 +4480,7 @@ fts_sync_table(
ut_ad(table->fts);
- if (table->fts->cache) {
+ if (!dict_table_is_discarded(table) && table->fts->cache) {
err = fts_sync(table->fts->cache->sync);
}
@@ -4506,15 +4507,11 @@ fts_process_token(
fts_string_t str;
ulint offset = 0;
fts_doc_t* result_doc;
- byte buf[FTS_MAX_WORD_LEN + 1];
-
- str.f_str = buf;
/* Determine where to save the result. */
result_doc = (result) ? result : doc;
/* The length of a string in characters is set here only. */
-
ret = innobase_mysql_fts_get_token(
doc->charset, doc->text.f_str + start_pos,
doc->text.f_str + doc->text.f_len, &str, &offset);
@@ -4545,6 +4542,7 @@ fts_process_token(
(char*) t_str.f_str, t_str.f_len);
t_str.f_len = newlen;
+ t_str.f_str[newlen] = 0;
/* Add the word to the document statistics. If the word
hasn't been seen before we create a new entry for it. */
@@ -5797,7 +5795,7 @@ fts_is_aux_table_name(
my_name[len] = 0;
end = my_name + len;
- ptr = static_cast<const char*>(memchr(my_name, '/', len));
+ ptr = static_cast<const char*>(memchr(my_name, '/', len));
if (ptr != NULL) {
/* We will start the match after the '/' */
@@ -5940,6 +5938,374 @@ fts_read_tables(
return(TRUE);
}
+/******************************************************************//**
+Callback that sets a hex formatted FTS table's flags2 in
+SYS_TABLES. The flags is stored in MIX_LEN column.
+@return FALSE if all OK */
+static
+ibool
+fts_set_hex_format(
+/*===============*/
+ void* row, /*!< in: sel_node_t* */
+ void* user_arg) /*!< in: bool set/unset flag */
+{
+ sel_node_t* node = static_cast<sel_node_t*>(row);
+ dfield_t* dfield = que_node_get_val(node->select_list);
+
+ ut_ad(dtype_get_mtype(dfield_get_type(dfield)) == DATA_INT);
+ ut_ad(dfield_get_len(dfield) == sizeof(ib_uint32_t));
+ /* There should be at most one matching record. So the value
+ must be the default value. */
+ ut_ad(mach_read_from_4(static_cast<byte*>(user_arg))
+ == ULINT32_UNDEFINED);
+
+ ulint flags2 = mach_read_from_4(
+ static_cast<byte*>(dfield_get_data(dfield)));
+
+ flags2 |= DICT_TF2_FTS_AUX_HEX_NAME;
+
+ mach_write_to_4(static_cast<byte*>(user_arg), flags2);
+
+ return(FALSE);
+}
+
+/*****************************************************************//**
+Update the DICT_TF2_FTS_AUX_HEX_NAME flag in SYS_TABLES.
+@return DB_SUCCESS or error code. */
+UNIV_INTERN
+dberr_t
+fts_update_hex_format_flag(
+/*=======================*/
+ trx_t* trx, /*!< in/out: transaction that
+ covers the update */
+ table_id_t table_id, /*!< in: Table for which we want
+ to set the root table->flags2 */
+ bool dict_locked) /*!< in: set to true if the
+ caller already owns the
+ dict_sys_t::mutex. */
+{
+ pars_info_t* info;
+ ib_uint32_t flags2;
+
+ static const char sql[] =
+ "PROCEDURE UPDATE_HEX_FORMAT_FLAG() IS\n"
+ "DECLARE FUNCTION my_func;\n"
+ "DECLARE CURSOR c IS\n"
+ " SELECT MIX_LEN "
+ " FROM SYS_TABLES "
+ " WHERE ID = :table_id FOR UPDATE;"
+ "\n"
+ "BEGIN\n"
+ "OPEN c;\n"
+ "WHILE 1 = 1 LOOP\n"
+ " FETCH c INTO my_func();\n"
+ " IF c % NOTFOUND THEN\n"
+ " EXIT;\n"
+ " END IF;\n"
+ "END LOOP;\n"
+ "UPDATE SYS_TABLES"
+ " SET MIX_LEN = :flags2"
+ " WHERE ID = :table_id;\n"
+ "CLOSE c;\n"
+ "END;\n";
+
+ flags2 = ULINT32_UNDEFINED;
+
+ info = pars_info_create();
+
+ pars_info_add_ull_literal(info, "table_id", table_id);
+ pars_info_bind_int4_literal(info, "flags2", &flags2);
+
+ pars_info_bind_function(
+ info, "my_func", fts_set_hex_format, &flags2);
+
+ if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) {
+ trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
+ }
+
+ dberr_t err = que_eval_sql(info, sql, !dict_locked, trx);
+
+ ut_a(flags2 != ULINT32_UNDEFINED);
+
+ return (err);
+}
+
+#ifdef _WIN32
+
+/*********************************************************************//**
+Rename an aux table to HEX format. It's called when "%016llu" is used
+to format an object id in table name, which only happens in Windows. */
+static __attribute__((nonnull, warn_unused_result))
+dberr_t
+fts_rename_one_aux_table_to_hex_format(
+/*===================================*/
+ trx_t* trx, /*!< in: transaction */
+ const fts_aux_table_t* aux_table, /*!< in: table info */
+ const dict_table_t* parent_table) /*!< in: parent table name */
+{
+ const char* ptr;
+ fts_table_t fts_table;
+ char* new_name;
+ dberr_t error;
+
+ ptr = strchr(aux_table->name, '/');
+ ut_a(ptr != NULL);
+ ++ptr;
+ /* Skip "FTS_", table id and underscore */
+ for (ulint i = 0; i < 2; ++i) {
+ ptr = strchr(ptr, '_');
+ ut_a(ptr != NULL);
+ ++ptr;
+ }
+
+ fts_table.suffix = NULL;
+ if (aux_table->index_id == 0) {
+ fts_table.type = FTS_COMMON_TABLE;
+
+ for (ulint i = 0; fts_common_tables[i] != NULL; ++i) {
+ if (strcmp(ptr, fts_common_tables[i]) == 0) {
+ fts_table.suffix = fts_common_tables[i];
+ break;
+ }
+ }
+ } else {
+ fts_table.type = FTS_INDEX_TABLE;
+
+ /* Skip index id and underscore */
+ ptr = strchr(ptr, '_');
+ ut_a(ptr != NULL);
+ ++ptr;
+
+ for (ulint i = 0; fts_index_selector[i].value; ++i) {
+ if (strcmp(ptr, fts_get_suffix(i)) == 0) {
+ fts_table.suffix = fts_get_suffix(i);
+ break;
+ }
+ }
+ }
+
+ ut_a(fts_table.suffix != NULL);
+
+ fts_table.parent = parent_table->name;
+ fts_table.table_id = aux_table->parent_id;
+ fts_table.index_id = aux_table->index_id;
+ fts_table.table = parent_table;
+
+ new_name = fts_get_table_name(&fts_table);
+ ut_ad(strcmp(new_name, aux_table->name) != 0);
+
+ if (trx_get_dict_operation(trx) == TRX_DICT_OP_NONE) {
+ trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
+ }
+
+ error = row_rename_table_for_mysql(aux_table->name, new_name, trx,
+ FALSE);
+
+ if (error != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Failed to rename aux table \'%s\' to "
+ "new format \'%s\'. ",
+ aux_table->name, new_name);
+ } else {
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Renamed aux table \'%s\' to \'%s\'.",
+ aux_table->name, new_name);
+ }
+
+ mem_free(new_name);
+
+ return (error);
+}
+
+/**********************************************************************//**
+Rename all aux tables of a parent table to HEX format. Also set aux tables'
+flags2 and parent table's flags2 with DICT_TF2_FTS_AUX_HEX_NAME.
+It's called when "%016llu" is used to format an object id in table name,
+which only happens in Windows.
+Note the ids in tables are correct but the names are old ambiguous ones.
+
+This function should make sure that either all the parent table and aux tables
+are set DICT_TF2_FTS_AUX_HEX_NAME with flags2 or none of them are set */
+static __attribute__((nonnull, warn_unused_result))
+dberr_t
+fts_rename_aux_tables_to_hex_format(
+/*================================*/
+ trx_t* trx, /*!< in: transaction */
+ dict_table_t* parent_table, /*!< in: parent table */
+ ib_vector_t* tables) /*!< in: aux tables to rename. */
+{
+ dberr_t error;
+ ulint count;
+
+ ut_ad(!DICT_TF2_FLAG_IS_SET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME));
+ ut_ad(!ib_vector_is_empty(tables));
+
+ error = fts_update_hex_format_flag(trx, parent_table->id, true);
+
+ if (error != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Setting parent table %s to hex format failed.",
+ parent_table->name);
+
+ fts_sql_rollback(trx);
+ return (error);
+ }
+
+ DICT_TF2_FLAG_SET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME);
+
+ for (count = 0; count < ib_vector_size(tables); ++count) {
+ dict_table_t* table;
+ fts_aux_table_t* aux_table;
+
+ aux_table = static_cast<fts_aux_table_t*>(
+ ib_vector_get(tables, count));
+
+ table = dict_table_open_on_id(aux_table->id, TRUE,
+ DICT_TABLE_OP_NORMAL);
+
+ ut_ad(table != NULL);
+ ut_ad(!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_AUX_HEX_NAME));
+
+ /* Set HEX_NAME flag here to make sure we can get correct
+ new table name in following function */
+ DICT_TF2_FLAG_SET(table, DICT_TF2_FTS_AUX_HEX_NAME);
+ error = fts_rename_one_aux_table_to_hex_format(trx,
+ aux_table, parent_table);
+ /* We will rollback the trx if the error != DB_SUCCESS,
+ so setting the flag here is the same with setting it in
+ row_rename_table_for_mysql */
+ DBUG_EXECUTE_IF("rename_aux_table_fail", error = DB_ERROR;);
+
+ if (error != DB_SUCCESS) {
+ dict_table_close(table, TRUE, FALSE);
+
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Failed to rename one aux table %s "
+ "Will revert all successful rename "
+ "operations.", aux_table->name);
+
+ fts_sql_rollback(trx);
+ break;
+ }
+
+ error = fts_update_hex_format_flag(trx, aux_table->id, true);
+ dict_table_close(table, TRUE, FALSE);
+
+ if (error != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Setting aux table %s to hex format failed.",
+ aux_table->name);
+
+ fts_sql_rollback(trx);
+ break;
+ }
+ }
+
+ if (error != DB_SUCCESS) {
+ ut_ad(count != ib_vector_size(tables));
+ /* If rename fails, thr trx would be rolled back, we can't
+ use it any more, we'll start a new background trx to do
+ the reverting. */
+ ut_a(trx->state == TRX_STATE_NOT_STARTED);
+ bool not_rename = false;
+
+ /* Try to revert those succesful rename operations
+ in order to revert the ibd file rename. */
+ for (ulint i = 0; i <= count; ++i) {
+ dict_table_t* table;
+ fts_aux_table_t* aux_table;
+ trx_t* trx_bg;
+ dberr_t err;
+
+ aux_table = static_cast<fts_aux_table_t*>(
+ ib_vector_get(tables, i));
+
+ table = dict_table_open_on_id(aux_table->id, TRUE,
+ DICT_TABLE_OP_NORMAL);
+ ut_ad(table != NULL);
+
+ if (not_rename) {
+ DICT_TF2_FLAG_UNSET(table,
+ DICT_TF2_FTS_AUX_HEX_NAME);
+ }
+
+ if (!DICT_TF2_FLAG_IS_SET(table,
+ DICT_TF2_FTS_AUX_HEX_NAME)) {
+ dict_table_close(table, TRUE, FALSE);
+ continue;
+ }
+
+ trx_bg = trx_allocate_for_background();
+ trx_bg->op_info = "Revert half done rename";
+ trx_bg->dict_operation_lock_mode = RW_X_LATCH;
+ trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE);
+
+ DICT_TF2_FLAG_UNSET(table, DICT_TF2_FTS_AUX_HEX_NAME);
+ err = row_rename_table_for_mysql(table->name,
+ aux_table->name,
+ trx_bg, FALSE);
+
+ trx_bg->dict_operation_lock_mode = 0;
+ dict_table_close(table, TRUE, FALSE);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_WARN, "Failed to revert "
+ "table %s. Please revert manually.",
+ table->name);
+ fts_sql_rollback(trx_bg);
+ /* Continue to clear aux tables' flags2 */
+ not_rename = true;
+ continue;
+ }
+
+ fts_sql_commit(trx_bg);
+ }
+
+ DICT_TF2_FLAG_UNSET(parent_table, DICT_TF2_FTS_AUX_HEX_NAME);
+ }
+
+ return (error);
+}
+
+/**********************************************************************//**
+Convert an id, which is actually a decimal number but was regard as a HEX
+from a string, to its real value. */
+static
+ib_id_t
+fts_fake_hex_to_dec(
+/*================*/
+ ib_id_t id) /*!< in: number to convert */
+{
+ ib_id_t dec_id = 0;
+ char tmp_id[FTS_AUX_MIN_TABLE_ID_LENGTH];
+ int ret;
+
+ ret = sprintf(tmp_id, UINT64PFx, id);
+ ut_ad(ret == 16);
+ ret = sscanf(tmp_id, "%016llu", &dec_id);
+ ut_ad(ret == 1);
+
+ return dec_id;
+}
+
+/*********************************************************************//**
+Compare two fts_aux_table_t parent_ids.
+@return < 0 if n1 < n2, 0 if n1 == n2, > 0 if n1 > n2 */
+UNIV_INLINE
+int
+fts_check_aux_table_parent_id_cmp(
+/*==============================*/
+ const void* p1, /*!< in: id1 */
+ const void* p2) /*!< in: id2 */
+{
+ const fts_aux_table_t* fa1 = static_cast<const fts_aux_table_t*>(p1);
+ const fts_aux_table_t* fa2 = static_cast<const fts_aux_table_t*>(p2);
+
+ return static_cast<int>(fa1->parent_id - fa2->parent_id);
+}
+
+#endif /* _WIN32 */
+
/**********************************************************************//**
Check and drop all orphaned FTS auxiliary tables, those that don't have
a parent table or FTS index defined on them.
@@ -5951,18 +6317,75 @@ fts_check_and_drop_orphaned_tables(
trx_t* trx, /*!< in: transaction */
ib_vector_t* tables) /*!< in: tables to check */
{
+#ifdef _WIN32
+ mem_heap_t* heap;
+ ib_vector_t* aux_tables_to_rename;
+ ib_alloc_t* heap_alloc;
+
+ heap = mem_heap_create(1024);
+ heap_alloc = ib_heap_allocator_create(heap);
+
+ /* We store all aux tables belonging to the same parent table here,
+ and rename all these tables in a batch mode. */
+ aux_tables_to_rename = ib_vector_create(heap_alloc,
+ sizeof(fts_aux_table_t), 128);
+
+ /* Sort by parent_id first, in case rename will fail */
+ ib_vector_sort(tables, fts_check_aux_table_parent_id_cmp);
+#endif /* _WIN32 */
+
for (ulint i = 0; i < ib_vector_size(tables); ++i) {
- dict_table_t* table;
+ dict_table_t* parent_table;
fts_aux_table_t* aux_table;
bool drop = false;
+#ifdef _WIN32
+ dict_table_t* table;
+ fts_aux_table_t* next_aux_table = NULL;
+ ib_id_t orig_parent_id = 0;
+ bool rename = false;
+#endif /* _WIN32 */
aux_table = static_cast<fts_aux_table_t*>(
ib_vector_get(tables, i));
+#ifdef _WIN32
table = dict_table_open_on_id(
+ aux_table->id, TRUE, DICT_TABLE_OP_NORMAL);
+ orig_parent_id = aux_table->parent_id;
+
+ if (table == NULL || strcmp(table->name, aux_table->name)) {
+ /* Skip these aux tables, which are common tables
+ with wrong table ids */
+ if (table) {
+ dict_table_close(table, TRUE, FALSE);
+ }
+
+ continue;
+
+ } else if (!DICT_TF2_FLAG_IS_SET(table,
+ DICT_TF2_FTS_AUX_HEX_NAME)) {
+
+ aux_table->parent_id = fts_fake_hex_to_dec(
+ aux_table->parent_id);
+
+ if (aux_table->index_id != 0) {
+ aux_table->index_id = fts_fake_hex_to_dec(
+ aux_table->index_id);
+ }
+
+ ut_ad(aux_table->id > aux_table->parent_id);
+ rename = true;
+ }
+
+ if (table) {
+ dict_table_close(table, TRUE, FALSE);
+ }
+#endif /* _WIN32 */
+
+ parent_table = dict_table_open_on_id(
aux_table->parent_id, TRUE, DICT_TABLE_OP_NORMAL);
- if (table == NULL || table->fts == NULL) {
+ if (parent_table == NULL || parent_table->fts == NULL) {
drop = true;
@@ -5971,7 +6394,7 @@ fts_check_and_drop_orphaned_tables(
fts_t* fts;
drop = true;
- fts = table->fts;
+ fts = parent_table->fts;
id = aux_table->index_id;
/* Search for the FT index in the table's list. */
@@ -5979,33 +6402,28 @@ fts_check_and_drop_orphaned_tables(
j < ib_vector_size(fts->indexes);
++j) {
- const dict_index_t* index;
+ const dict_index_t* index;
index = static_cast<const dict_index_t*>(
ib_vector_getp_const(fts->indexes, j));
if (index->id == id) {
-
drop = false;
break;
}
}
}
- if (table) {
- dict_table_close(table, TRUE, FALSE);
- }
-
if (drop) {
ib_logf(IB_LOG_LEVEL_WARN,
"Parent table of FTS auxiliary table %s not "
"found.", aux_table->name);
- dberr_t err = fts_drop_table(trx, aux_table->name);
+ dberr_t err = fts_drop_table(trx, aux_table->name);
if (err == DB_FAIL) {
- char* path;
+ char* path;
path = fil_make_ibd_name(
aux_table->name, false);
@@ -6016,7 +6434,120 @@ fts_check_and_drop_orphaned_tables(
mem_free(path);
}
}
+#ifdef _WIN32
+ if (!drop && rename) {
+ ib_vector_push(aux_tables_to_rename, aux_table);
+ }
+
+ if (i + 1 < ib_vector_size(tables)) {
+ next_aux_table = static_cast<fts_aux_table_t*>(
+ ib_vector_get(tables, i + 1));
+ }
+
+ if ((next_aux_table == NULL
+ || orig_parent_id != next_aux_table->parent_id)
+ && !ib_vector_is_empty(aux_tables_to_rename)) {
+ /* All aux tables of parent table, whose id is
+ last_parent_id, have been checked, try to rename
+ them if necessary. We had better use a new background
+ trx to rename rather than the original trx, in case
+ any failure would cause a complete rollback. */
+ dberr_t err;
+ trx_t* trx_rename = trx_allocate_for_background();
+ trx_rename->op_info = "Rename aux tables to "
+ "hex format";
+ trx_rename->dict_operation_lock_mode = RW_X_LATCH;
+ trx_start_for_ddl(trx_rename, TRX_DICT_OP_TABLE);
+
+ err = fts_rename_aux_tables_to_hex_format(trx_rename,
+ parent_table, aux_tables_to_rename);
+
+ trx_rename->dict_operation_lock_mode = 0;
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Rollback operations on all "
+ "aux tables of table %s. "
+ "Please check why renaming aux tables "
+ "failed, and restart the server to "
+ "upgrade again to "
+ "get the table work.",
+ parent_table->name);
+
+ fts_sql_rollback(trx_rename);
+ } else {
+ fts_sql_commit(trx_rename);
+ }
+
+ trx_free_for_background(trx_rename);
+ ib_vector_reset(aux_tables_to_rename);
+ }
+#else /* _WIN32 */
+ if (!drop) {
+ dict_table_t* table;
+
+ table = dict_table_open_on_id(
+ aux_table->id, TRUE, DICT_TABLE_OP_NORMAL);
+ if (table != NULL
+ && strcmp(table->name, aux_table->name)) {
+ dict_table_close(table, TRUE, FALSE);
+ table = NULL;
+ }
+
+ if (table != NULL
+ && !DICT_TF2_FLAG_IS_SET(
+ table,
+ DICT_TF2_FTS_AUX_HEX_NAME)) {
+ dberr_t err = fts_update_hex_format_flag(
+ trx, table->id, true);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Setting aux table %s to hex "
+ "format failed.", table->name);
+ } else {
+ DICT_TF2_FLAG_SET(table,
+ DICT_TF2_FTS_AUX_HEX_NAME);
+ }
+ }
+
+ if (table != NULL) {
+ dict_table_close(table, TRUE, FALSE);
+ }
+
+ ut_ad(parent_table != NULL);
+ if (!DICT_TF2_FLAG_IS_SET(parent_table,
+ DICT_TF2_FTS_AUX_HEX_NAME)) {
+ dberr_t err = fts_update_hex_format_flag(
+ trx, parent_table->id, true);
+
+ if (err != DB_SUCCESS) {
+ ib_logf(IB_LOG_LEVEL_WARN,
+ "Setting parent table %s of "
+ "FTS auxiliary %s to hex "
+ "format failed.",
+ parent_table->name,
+ aux_table->name);
+ } else {
+ DICT_TF2_FLAG_SET(parent_table,
+ DICT_TF2_FTS_AUX_HEX_NAME);
+ }
+ }
+ }
+
+#endif /* _WIN32 */
+
+ if (parent_table) {
+ dict_table_close(parent_table, TRUE, FALSE);
+ }
+ }
+
+#ifdef _WIN32
+ /* Free the memory allocated at the beginning */
+ if (heap != NULL) {
+ mem_heap_free(heap);
}
+#endif /* _WIN32 */
}
/**********************************************************************//**
@@ -6216,7 +6747,7 @@ fts_valid_stopword_table(
return(innobase_get_fts_charset(
static_cast<int>(col->prtype & DATA_MYSQL_TYPE_MASK),
- static_cast<ulint>(dtype_get_charset_coll(col->prtype))));
+ static_cast<uint>(dtype_get_charset_coll(col->prtype))));
}
/**********************************************************************//**
diff --git a/storage/xtradb/fts/fts0opt.cc b/storage/xtradb/fts/fts0opt.cc
index 7cdad522564..a9f3a25530d 100644
--- a/storage/xtradb/fts/fts0opt.cc
+++ b/storage/xtradb/fts/fts0opt.cc
@@ -620,7 +620,7 @@ fts_zip_read_word(
zip->zp->avail_in =
FTS_MAX_WORD_LEN;
} else {
- zip->zp->avail_in = zip->block_sz;
+ zip->zp->avail_in = static_cast<uInt>(zip->block_sz);
}
++zip->pos;
@@ -721,7 +721,7 @@ fts_fetch_index_words(
ib_vector_push(zip->blocks, &block);
zip->zp->next_out = block;
- zip->zp->avail_out = zip->block_sz;
+ zip->zp->avail_out = static_cast<uInt>(zip->block_sz);
}
switch (zip->status = deflate(zip->zp, Z_NO_FLUSH)) {
@@ -1099,10 +1099,10 @@ fts_optimize_lookup(
doc_id_t last_doc_id) /*!< in: doc id to lookup */
{
int pos;
- int upper = ib_vector_size(doc_ids);
+ int upper = static_cast<int>(ib_vector_size(doc_ids));
fts_update_t* array = (fts_update_t*) doc_ids->data;
- pos = fts_bsearch(array, lower, upper, first_doc_id);
+ pos = fts_bsearch(array, static_cast<int>(lower), upper, first_doc_id);
ut_a(abs(pos) <= upper + 1);
@@ -1624,10 +1624,12 @@ fts_optimize_create(
optim->fts_common_table.parent = table->name;
optim->fts_common_table.table_id = table->id;
optim->fts_common_table.type = FTS_COMMON_TABLE;
+ optim->fts_common_table.table = table;
optim->fts_index_table.parent = table->name;
optim->fts_index_table.table_id = table->id;
optim->fts_index_table.type = FTS_INDEX_TABLE;
+ optim->fts_index_table.table = table;
/* The common prefix for all this parent table's aux tables. */
optim->name_prefix = fts_get_table_name_prefix(
diff --git a/storage/xtradb/fts/fts0pars.cc b/storage/xtradb/fts/fts0pars.cc
index a4009106c83..83d465b0988 100644
--- a/storage/xtradb/fts/fts0pars.cc
+++ b/storage/xtradb/fts/fts0pars.cc
@@ -1,19 +1,19 @@
/* A Bison parser, made by GNU Bison 2.5. */
/* Bison implementation for Yacc-like parsers in C
-
+
Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-
+
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 Foundation, either version 3 of the License, or
(at your option) any later version.
-
+
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
-
+
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
@@ -26,7 +26,7 @@
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
-
+
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
@@ -467,9 +467,9 @@ static const yytype_int8 yyrhs[] =
/* YYRLINE[YYN] -- source line where rule number YYN was defined. */
static const yytype_uint8 yyrline[] =
{
- 0, 79, 79, 85, 89, 99, 111, 115, 124, 128,
- 132, 136, 141, 147, 152, 159, 165, 169, 173, 177,
- 181, 186, 191, 197, 202
+ 0, 79, 79, 85, 89, 99, 111, 119, 129, 133,
+ 137, 141, 146, 152, 157, 164, 170, 174, 178, 182,
+ 186, 191, 196, 202, 207
};
#endif
@@ -1458,7 +1458,7 @@ yyreduce:
(yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node));
if (!(yyval.node)) {
- (yyval.node) = fts_ast_create_node_subexp_list(state, (yyvsp[(2) - (2)].node));
+ (yyval.node) = (yyvsp[(2) - (2)].node);
} else {
fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node));
}
@@ -1471,18 +1471,23 @@ yyreduce:
#line 111 "fts0pars.y"
{
(yyval.node) = (yyvsp[(2) - (3)].node);
+
+ if ((yyval.node)) {
+ (yyval.node) = fts_ast_create_node_subexp_list(state, (yyval.node));
+ }
}
break;
case 7:
/* Line 1806 of yacc.c */
-#line 115 "fts0pars.y"
+#line 119 "fts0pars.y"
{
- (yyval.node) = fts_ast_create_node_subexp_list(state, (yyvsp[(1) - (4)].node));
+ (yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (4)].node));
if ((yyvsp[(3) - (4)].node)) {
- fts_ast_add_node((yyval.node), (yyvsp[(3) - (4)].node));
+ fts_ast_add_node((yyval.node),
+ fts_ast_create_node_subexp_list(state, (yyvsp[(3) - (4)].node)));
}
}
break;
@@ -1490,7 +1495,7 @@ yyreduce:
case 8:
/* Line 1806 of yacc.c */
-#line 124 "fts0pars.y"
+#line 129 "fts0pars.y"
{
(yyval.node) = (yyvsp[(1) - (1)].node);
}
@@ -1499,7 +1504,7 @@ yyreduce:
case 9:
/* Line 1806 of yacc.c */
-#line 128 "fts0pars.y"
+#line 133 "fts0pars.y"
{
(yyval.node) = (yyvsp[(1) - (1)].node);
}
@@ -1508,7 +1513,7 @@ yyreduce:
case 10:
/* Line 1806 of yacc.c */
-#line 132 "fts0pars.y"
+#line 137 "fts0pars.y"
{
fts_ast_term_set_wildcard((yyvsp[(1) - (2)].node));
}
@@ -1517,7 +1522,7 @@ yyreduce:
case 11:
/* Line 1806 of yacc.c */
-#line 136 "fts0pars.y"
+#line 141 "fts0pars.y"
{
fts_ast_term_set_distance((yyvsp[(1) - (3)].node), strtoul((yyvsp[(3) - (3)].token), NULL, 10));
free((yyvsp[(3) - (3)].token));
@@ -1527,7 +1532,7 @@ yyreduce:
case 12:
/* Line 1806 of yacc.c */
-#line 141 "fts0pars.y"
+#line 146 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (3)].node));
fts_ast_add_node((yyval.node), (yyvsp[(2) - (3)].node));
@@ -1538,7 +1543,7 @@ yyreduce:
case 13:
/* Line 1806 of yacc.c */
-#line 147 "fts0pars.y"
+#line 152 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node));
fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node));
@@ -1548,7 +1553,7 @@ yyreduce:
case 14:
/* Line 1806 of yacc.c */
-#line 152 "fts0pars.y"
+#line 157 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (4)].node));
fts_ast_add_node((yyval.node), (yyvsp[(2) - (4)].node));
@@ -1560,7 +1565,7 @@ yyreduce:
case 15:
/* Line 1806 of yacc.c */
-#line 159 "fts0pars.y"
+#line 164 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_list(state, (yyvsp[(1) - (2)].node));
fts_ast_add_node((yyval.node), (yyvsp[(2) - (2)].node));
@@ -1570,7 +1575,7 @@ yyreduce:
case 16:
/* Line 1806 of yacc.c */
-#line 165 "fts0pars.y"
+#line 170 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_oper(state, FTS_IGNORE);
}
@@ -1579,7 +1584,7 @@ yyreduce:
case 17:
/* Line 1806 of yacc.c */
-#line 169 "fts0pars.y"
+#line 174 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_oper(state, FTS_EXIST);
}
@@ -1588,7 +1593,7 @@ yyreduce:
case 18:
/* Line 1806 of yacc.c */
-#line 173 "fts0pars.y"
+#line 178 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_oper(state, FTS_NEGATE);
}
@@ -1597,7 +1602,7 @@ yyreduce:
case 19:
/* Line 1806 of yacc.c */
-#line 177 "fts0pars.y"
+#line 182 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_oper(state, FTS_DECR_RATING);
}
@@ -1606,7 +1611,7 @@ yyreduce:
case 20:
/* Line 1806 of yacc.c */
-#line 181 "fts0pars.y"
+#line 186 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_oper(state, FTS_INCR_RATING);
}
@@ -1615,7 +1620,7 @@ yyreduce:
case 21:
/* Line 1806 of yacc.c */
-#line 186 "fts0pars.y"
+#line 191 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token));
free((yyvsp[(1) - (1)].token));
@@ -1625,7 +1630,7 @@ yyreduce:
case 22:
/* Line 1806 of yacc.c */
-#line 191 "fts0pars.y"
+#line 196 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_term(state, (yyvsp[(1) - (1)].token));
free((yyvsp[(1) - (1)].token));
@@ -1635,7 +1640,7 @@ yyreduce:
case 23:
/* Line 1806 of yacc.c */
-#line 197 "fts0pars.y"
+#line 202 "fts0pars.y"
{
(yyval.node) = (yyvsp[(2) - (2)].node);
}
@@ -1644,7 +1649,7 @@ yyreduce:
case 24:
/* Line 1806 of yacc.c */
-#line 202 "fts0pars.y"
+#line 207 "fts0pars.y"
{
(yyval.node) = fts_ast_create_node_text(state, (yyvsp[(1) - (1)].token));
free((yyvsp[(1) - (1)].token));
@@ -1654,7 +1659,7 @@ yyreduce:
/* Line 1806 of yacc.c */
-#line 1658 "fts0pars.cc"
+#line 1663 "fts0pars.cc"
default: break;
}
/* User semantic actions sometimes alter yychar, and that requires
@@ -1885,7 +1890,7 @@ yyreturn:
/* Line 2067 of yacc.c */
-#line 207 "fts0pars.y"
+#line 212 "fts0pars.y"
/********************************************************************
@@ -1914,14 +1919,20 @@ fts_lexer_create(
if (boolean_mode) {
fts0blex_init(&fts_lexer->yyscanner);
- fts0b_scan_bytes((char*) query, query_len, fts_lexer->yyscanner);
- fts_lexer->scanner = (fts_scan) fts_blexer;
+ fts0b_scan_bytes(
+ reinterpret_cast<const char*>(query),
+ static_cast<int>(query_len),
+ fts_lexer->yyscanner);
+ fts_lexer->scanner = reinterpret_cast<fts_scan>(fts_blexer);
/* FIXME: Debugging */
/* fts0bset_debug(1 , fts_lexer->yyscanner); */
} else {
fts0tlex_init(&fts_lexer->yyscanner);
- fts0t_scan_bytes((char*) query, query_len, fts_lexer->yyscanner);
- fts_lexer->scanner = (fts_scan) fts_tlexer;
+ fts0t_scan_bytes(
+ reinterpret_cast<const char*>(query),
+ static_cast<int>(query_len),
+ fts_lexer->yyscanner);
+ fts_lexer->scanner = reinterpret_cast<fts_scan>(fts_tlexer);
}
return(fts_lexer);
diff --git a/storage/xtradb/fts/fts0pars.y b/storage/xtradb/fts/fts0pars.y
index 73d71bc87c5..ff22e9a9873 100644
--- a/storage/xtradb/fts/fts0pars.y
+++ b/storage/xtradb/fts/fts0pars.y
@@ -101,7 +101,7 @@ expr_lst: /* Empty */ {
$$ = fts_ast_create_node_list(state, $1);
if (!$$) {
- $$ = fts_ast_create_node_subexp_list(state, $2);
+ $$ = $2;
} else {
fts_ast_add_node($$, $2);
}
@@ -110,13 +110,18 @@ expr_lst: /* Empty */ {
sub_expr: '(' expr_lst ')' {
$$ = $2;
+
+ if ($$) {
+ $$ = fts_ast_create_node_subexp_list(state, $$);
+ }
}
| prefix '(' expr_lst ')' {
- $$ = fts_ast_create_node_subexp_list(state, $1);
+ $$ = fts_ast_create_node_list(state, $1);
if ($3) {
- fts_ast_add_node($$, $3);
+ fts_ast_add_node($$,
+ fts_ast_create_node_subexp_list(state, $3));
}
}
;
diff --git a/storage/xtradb/fts/fts0que.cc b/storage/xtradb/fts/fts0que.cc
index 7da60c0d166..c5c5f954789 100644
--- a/storage/xtradb/fts/fts0que.cc
+++ b/storage/xtradb/fts/fts0que.cc
@@ -40,18 +40,14 @@ Completed 2011/7/10 Sunny and Jimmy Yang
#include "fts0vlc.ic"
#endif
-#include <string>
#include <vector>
-#include <map>
#define FTS_ELEM(t, n, i, j) (t[(i) * n + (j)])
#define RANK_DOWNGRADE (-1.0F)
#define RANK_UPGRADE (1.0F)
-/* Maximum number of words supported in a proximity search.
-FIXME, this limitation can be removed easily. Need to see
-if we want to enforce such limitation */
+/* Maximum number of words supported in a phrase or proximity search. */
#define MAX_PROXIMITY_ITEM 128
/* Memory used by rbt itself for create and node add */
@@ -66,8 +62,7 @@ static const double FTS_NORMALIZE_COEFF = 0.0115F;
// FIXME: Need to have a generic iterator that traverses the ilist.
-typedef std::map<std::string, ulint> word_map_t;
-typedef std::vector<std::string> word_vector_t;
+typedef std::vector<fts_string_t> word_vector_t;
struct fts_word_freq_t;
@@ -92,7 +87,7 @@ struct fts_query_t {
fts_ast_node_t* cur_node; /*!< Current tree node */
- word_map_t* word_map; /*!< Matched word map for
+ ib_rbt_t* word_map; /*!< Matched word map for
searching by word*/
word_vector_t* word_vector; /*!< Matched word vector for
@@ -186,6 +181,8 @@ struct fts_select_t {
the FTS index */
};
+typedef std::vector<ulint> pos_vector_t;
+
/** structure defines a set of ranges for original documents, each of which
has a minimum position and maximum position. Text in such range should
contain all words in the proximity search. We will need to count the
@@ -195,9 +192,9 @@ struct fts_proximity_t {
ulint n_pos; /*!< number of position set, defines
a range (min to max) containing all
matching words */
- ulint* min_pos; /*!< the minimum position (in bytes)
+ pos_vector_t min_pos; /*!< the minimum position (in bytes)
of the range */
- ulint* max_pos; /*!< the maximum position (in bytes)
+ pos_vector_t max_pos; /*!< the maximum position (in bytes)
of the range */
};
@@ -229,7 +226,7 @@ struct fts_doc_freq_t {
/** To determine the word frequency per document. */
struct fts_word_freq_t {
- byte* word; /*!< Word for which we need the freq,
+ fts_string_t word; /*!< Word for which we need the freq,
it's allocated on the query heap */
ib_rbt_t* doc_freqs; /*!< RB Tree for storing per document
@@ -257,15 +254,14 @@ static
dberr_t
fts_query_filter_doc_ids(
/*=====================*/
- fts_query_t* query, /*!< in: query instance */
- const byte* word, /*!< in: the current word */
- fts_word_freq_t*word_freq, /*!< in/out: word frequency */
- const fts_node_t*
- node, /*!< in: current FTS node */
- void* data, /*!< in: doc id ilist */
- ulint len, /*!< in: doc id ilist size */
- ibool calc_doc_count);/*!< in: whether to remember doc
- count */
+ fts_query_t* query, /*!< in: query instance */
+ const fts_string_t* word, /*!< in: the current word */
+ fts_word_freq_t* word_freq, /*!< in/out: word frequency */
+ const fts_node_t* node, /*!< in: current FTS node */
+ void* data, /*!< in: doc id ilist */
+ ulint len, /*!< in: doc id ilist size */
+ ibool calc_doc_count);/*!< in: whether to remember doc
+ count */
#if 0
/*****************************************************************//***
@@ -575,27 +571,41 @@ static
void
fts_ranking_words_add(
/*==================*/
- fts_query_t* query, /*!< in: query instance */
- fts_ranking_t* ranking, /*!< in: ranking instance */
- const char* word) /*!< in: term/word to add */
+ fts_query_t* query, /*!< in: query instance */
+ fts_ranking_t* ranking, /*!< in: ranking instance */
+ const fts_string_t* word) /*!< in: term/word to add */
{
ulint pos;
ulint byte_offset;
ulint bit_offset;
- word_map_t::iterator it;
-
- /* Note: we suppose the word map and vector are append-only */
- /* Check if need to add it to word map */
- it = query->word_map->lower_bound(word);
- if (it != query->word_map->end()
- && !query->word_map->key_comp()(word, it->first)) {
- pos = it->second;
+ ib_rbt_bound_t parent;
+
+ /* Note: we suppose the word map and vector are append-only. */
+ ut_ad(query->word_vector->size() == rbt_size(query->word_map));
+
+ /* We use ib_rbt to simulate a map, f_n_char means position. */
+ if (rbt_search(query->word_map, &parent, word) == 0) {
+ fts_string_t* result_word;
+
+ result_word = rbt_value(fts_string_t, parent.last);
+ pos = result_word->f_n_char;
+ ut_ad(pos < rbt_size(query->word_map));
} else {
- pos = query->word_map->size();
- query->word_map->insert(it,
- std::pair<std::string, ulint>(word, pos));
+ /* Add the word to map. */
+ fts_string_t new_word;
+
+ pos = rbt_size(query->word_map);
+
+ new_word.f_str = static_cast<byte*>(mem_heap_alloc(query->heap,
+ word->f_len + 1));
+ memcpy(new_word.f_str, word->f_str, word->f_len);
+ new_word.f_str[word->f_len] = 0;
+ new_word.f_len = word->f_len;
+ new_word.f_n_char = pos;
- query->word_vector->push_back(word);
+ rbt_add_node(query->word_map, &parent, &new_word);
+ ut_ad(rbt_validate(query->word_map));
+ query->word_vector->push_back(new_word);
}
/* Check words len */
@@ -630,7 +640,7 @@ fts_ranking_words_get_next(
const fts_query_t* query, /*!< in: query instance */
fts_ranking_t* ranking,/*!< in: ranking instance */
ulint* pos, /*!< in/out: word start pos */
- byte** word) /*!< in/out: term/word to add */
+ fts_string_t* word) /*!< in/out: term/word to add */
{
bool ret = false;
ulint max_pos = ranking->words_len * CHAR_BIT;
@@ -651,7 +661,7 @@ fts_ranking_words_get_next(
/* Get next word from word vector */
if (ret) {
ut_ad(*pos < query->word_vector->size());
- *word = (byte*)query->word_vector->at((size_t)*pos).c_str();
+ *word = query->word_vector->at((size_t)*pos);
*pos += 1;
}
@@ -666,23 +676,22 @@ static
fts_word_freq_t*
fts_query_add_word_freq(
/*====================*/
- fts_query_t* query, /*!< in: query instance */
- const byte* word) /*!< in: term/word to add */
+ fts_query_t* query, /*!< in: query instance */
+ const fts_string_t* word) /*!< in: term/word to add */
{
ib_rbt_bound_t parent;
/* Lookup the word in our rb tree and add if it doesn't exist. */
if (rbt_search(query->word_freqs, &parent, word) != 0) {
fts_word_freq_t word_freq;
- ulint len = ut_strlen((char*) word) + 1;
memset(&word_freq, 0, sizeof(word_freq));
- word_freq.word = static_cast<byte*>(
- mem_heap_alloc(query->heap, len));
-
- /* Need to copy the NUL character too. */
- memcpy(word_freq.word, word, len);
+ word_freq.word.f_str = static_cast<byte*>(
+ mem_heap_alloc(query->heap, word->f_len + 1));
+ memcpy(word_freq.word.f_str, word->f_str, word->f_len);
+ word_freq.word.f_str[word->f_len] = 0;
+ word_freq.word.f_len = word->f_len;
word_freq.doc_count = 0;
@@ -692,7 +701,7 @@ fts_query_add_word_freq(
parent.last = rbt_add_node(
query->word_freqs, &parent, &word_freq);
- query->total_size += len
+ query->total_size += word->f_len
+ SIZEOF_RBT_CREATE
+ SIZEOF_RBT_NODE_ADD
+ sizeof(fts_word_freq_t);
@@ -749,7 +758,7 @@ fts_query_union_doc_id(
fts_update_t* array = (fts_update_t*) query->deleted->doc_ids->data;
/* Check if the doc id is deleted and it's not already in our set. */
- if (fts_bsearch(array, 0, size, doc_id) < 0
+ if (fts_bsearch(array, 0, static_cast<int>(size), doc_id) < 0
&& rbt_search(query->doc_ids, &parent, &doc_id) != 0) {
fts_ranking_t ranking;
@@ -780,7 +789,7 @@ fts_query_remove_doc_id(
fts_update_t* array = (fts_update_t*) query->deleted->doc_ids->data;
/* Check if the doc id is deleted and it's in our set. */
- if (fts_bsearch(array, 0, size, doc_id) < 0
+ if (fts_bsearch(array, 0, static_cast<int>(size), doc_id) < 0
&& rbt_search(query->doc_ids, &parent, &doc_id) == 0) {
ut_free(rbt_remove_node(query->doc_ids, parent.last));
@@ -810,7 +819,7 @@ fts_query_change_ranking(
fts_update_t* array = (fts_update_t*) query->deleted->doc_ids->data;
/* Check if the doc id is deleted and it's in our set. */
- if (fts_bsearch(array, 0, size, doc_id) < 0
+ if (fts_bsearch(array, 0, static_cast<int>(size), doc_id) < 0
&& rbt_search(query->doc_ids, &parent, &doc_id) == 0) {
fts_ranking_t* ranking;
@@ -856,7 +865,7 @@ fts_query_intersect_doc_id(
if it matches 'b' and it's in doc_ids.(multi_exist = true). */
/* Check if the doc id is deleted and it's in our set */
- if (fts_bsearch(array, 0, size, doc_id) < 0) {
+ if (fts_bsearch(array, 0, static_cast<int>(size), doc_id) < 0) {
fts_ranking_t new_ranking;
if (rbt_search(query->doc_ids, &parent, &doc_id) != 0) {
@@ -956,7 +965,7 @@ fts_query_add_word_to_document(
/*===========================*/
fts_query_t* query, /*!< in: query to update */
doc_id_t doc_id, /*!< in: the document to update */
- const byte* word) /*!< in: the token to add */
+ const fts_string_t* word) /*!< in: the token to add */
{
ib_rbt_bound_t parent;
fts_ranking_t* ranking = NULL;
@@ -980,7 +989,7 @@ fts_query_add_word_to_document(
}
if (ranking != NULL) {
- fts_ranking_words_add(query, ranking, (char*)word);
+ fts_ranking_words_add(query, ranking, word);
}
}
@@ -1010,13 +1019,13 @@ fts_query_check_node(
fts_word_freq_t*word_freqs;
/* The word must exist. */
- ret = rbt_search(query->word_freqs, &parent, token->f_str);
+ ret = rbt_search(query->word_freqs, &parent, token);
ut_a(ret == 0);
word_freqs = rbt_value(fts_word_freq_t, parent.last);
query->error = fts_query_filter_doc_ids(
- query, token->f_str, word_freqs, node,
+ query, token, word_freqs, node,
node->ilist, ilist_size, TRUE);
}
}
@@ -1073,7 +1082,7 @@ fts_cache_find_wildcard(
ret = rbt_search(query->word_freqs,
&freq_parent,
- srch_text.f_str);
+ &srch_text);
ut_a(ret == 0);
@@ -1082,7 +1091,7 @@ fts_cache_find_wildcard(
freq_parent.last);
query->error = fts_query_filter_doc_ids(
- query, srch_text.f_str,
+ query, &srch_text,
word_freqs, node,
node->ilist, node->ilist_size, TRUE);
@@ -1542,7 +1551,7 @@ fts_merge_doc_ids(
for (node = rbt_first(doc_ids); node; node = rbt_next(doc_ids, node)) {
fts_ranking_t* ranking;
ulint pos = 0;
- byte* word = NULL;
+ fts_string_t word;
ranking = rbt_value(fts_ranking_t, node);
@@ -1557,7 +1566,7 @@ fts_merge_doc_ids(
ut_a(ranking->words);
while (fts_ranking_words_get_next(query, ranking, &pos, &word)) {
fts_query_add_word_to_document(query, ranking->doc_id,
- word);
+ &word);
}
}
@@ -1696,6 +1705,9 @@ fts_proximity_is_word_in_range(
{
fts_proximity_t* proximity_pos = phrase->proximity_pos;
+ ut_ad(proximity_pos->n_pos == proximity_pos->min_pos.size());
+ ut_ad(proximity_pos->n_pos == proximity_pos->max_pos.size());
+
/* Search each matched position pair (with min and max positions)
and count the number of words in the range */
for (ulint i = 0; i < proximity_pos->n_pos; i++) {
@@ -1913,6 +1925,7 @@ fts_query_fetch_document(
if (cur_len != UNIV_SQL_NULL && cur_len != 0) {
if (phrase->proximity_pos) {
+ ut_ad(prev_len + cur_len <= total_len);
memcpy(document_text + prev_len, data, cur_len);
} else {
/* For phrase search */
@@ -1923,17 +1936,18 @@ fts_query_fetch_document(
cur_len, prev_len,
phrase->heap);
}
+
+ /* Document positions are calculated from the beginning
+ of the first field, need to save the length for each
+ searched field to adjust the doc position when search
+ phrases. */
+ prev_len += cur_len + 1;
}
if (phrase->found) {
break;
}
- /* Document positions are calculated from the beginning
- of the first field, need to save the length for each
- searched field to adjust the doc position when search
- phrases. */
- prev_len += cur_len + 1;
exp = que_node_get_next(exp);
}
@@ -2472,8 +2486,7 @@ fts_query_search_phrase(
token = static_cast<fts_string_t*>(
ib_vector_get(tokens, z));
fts_query_add_word_to_document(
- query, match->doc_id,
- token->f_str);
+ query, match->doc_id, token);
}
}
}
@@ -2562,7 +2575,7 @@ fts_query_phrase_search(
&& result_str.f_n_char <= fts_max_token_size) {
/* Add the word to the RB tree so that we can
calculate it's frequencey within a document. */
- fts_query_add_word_freq(query, token->f_str);
+ fts_query_add_word_freq(query, token);
} else {
ib_vector_pop(tokens);
}
@@ -2580,6 +2593,11 @@ fts_query_phrase_search(
}
num_token = ib_vector_size(tokens);
+ if (num_token > MAX_PROXIMITY_ITEM) {
+ query->error = DB_FTS_TOO_MANY_WORDS_IN_PHRASE;
+ goto func_exit;
+ }
+
ut_ad(ib_vector_size(orig_tokens) >= num_token);
/* Ignore empty strings. */
@@ -2605,7 +2623,7 @@ fts_query_phrase_search(
heap_alloc, sizeof(fts_match_t),
64);
} else {
- ut_a(num_token < MAX_PROXIMITY_ITEM);
+ ut_a(num_token <= MAX_PROXIMITY_ITEM);
query->match_array =
(ib_vector_t**) mem_heap_alloc(
heap,
@@ -2687,7 +2705,7 @@ fts_query_phrase_search(
}
fts_query_add_word_to_document(
- query, match->doc_id, token->f_str);
+ query, match->doc_id, token);
}
query->oper = oper;
goto func_exit;
@@ -2837,6 +2855,8 @@ fts_query_visitor(
ut_ad(query->intersection == NULL);
query->intersection = rbt_create(
sizeof(fts_ranking_t), fts_ranking_doc_id_cmp);
+
+ query->total_size += SIZEOF_RBT_CREATE;
}
/* Set the current proximity distance. */
@@ -2858,10 +2878,12 @@ fts_query_visitor(
break;
case FTS_AST_TERM:
+ token.f_str = node->term.ptr;
+ token.f_len = ut_strlen(reinterpret_cast<char*>(token.f_str));
/* Add the word to our RB tree that will be used to
calculate this terms per document frequency. */
- fts_query_add_word_freq(query, node->term.ptr);
+ fts_query_add_word_freq(query, &token);
ptr = fts_query_get_token(node, &token);
query->error = fts_query_execute(query, &token);
@@ -2871,6 +2893,10 @@ fts_query_visitor(
}
break;
+ case FTS_AST_SUBEXP_LIST:
+ query->error = fts_ast_visit_sub_exp(node, fts_query_visitor, arg);
+ break;
+
default:
ut_error;
}
@@ -2905,13 +2931,7 @@ fts_ast_visit_sub_exp(
ut_a(node->type == FTS_AST_SUBEXP_LIST);
- node = node->list.head;
-
- if (!node || !node->next) {
- return(error);
- }
-
- cur_oper = node->oper;
+ cur_oper = query->oper;
/* Save current result set */
parent_doc_ids = query->doc_ids;
@@ -2927,26 +2947,20 @@ fts_ast_visit_sub_exp(
query->multi_exist = false;
/* Process nodes in current sub-expression and store its
result set in query->doc_ids we created above. */
- error = fts_ast_visit(FTS_NONE, node->next, visitor,
+ error = fts_ast_visit(FTS_NONE, node, visitor,
arg, &will_be_ignored);
- /* Reinstate parent node state and prepare for merge. */
+ /* Reinstate parent node state */
query->multi_exist = multi_exist;
query->oper = cur_oper;
- subexpr_doc_ids = query->doc_ids;
-
- /* Restore current result set. */
- query->doc_ids = parent_doc_ids;
/* Merge the sub-expression result with the parent result set. */
+ subexpr_doc_ids = query->doc_ids;
+ query->doc_ids = parent_doc_ids;
if (error == DB_SUCCESS && !rbt_empty(subexpr_doc_ids)) {
error = fts_merge_doc_ids(query, subexpr_doc_ids);
}
- if (query->oper == FTS_EXIST) {
- query->multi_exist = true;
- }
-
/* Free current result set. Result already merged into parent. */
fts_query_free_doc_ids(query, subexpr_doc_ids);
@@ -3033,14 +3047,13 @@ static
dberr_t
fts_query_filter_doc_ids(
/*=====================*/
- fts_query_t* query, /*!< in: query instance */
- const byte* word, /*!< in: the current word */
- fts_word_freq_t*word_freq, /*!< in/out: word frequency */
- const fts_node_t*
- node, /*!< in: current FTS node */
- void* data, /*!< in: doc id ilist */
- ulint len, /*!< in: doc id ilist size */
- ibool calc_doc_count) /*!< in: whether to remember doc count */
+ fts_query_t* query, /*!< in: query instance */
+ const fts_string_t* word, /*!< in: the current word */
+ fts_word_freq_t* word_freq, /*!< in/out: word frequency */
+ const fts_node_t* node, /*!< in: current FTS node */
+ void* data, /*!< in: doc id ilist */
+ ulint len, /*!< in: doc id ilist size */
+ ibool calc_doc_count) /*!< in: whether to remember doc count */
{
byte* ptr = static_cast<byte*>(data);
doc_id_t doc_id = 0;
@@ -3163,13 +3176,15 @@ fts_query_read_node(
ib_rbt_bound_t parent;
fts_word_freq_t* word_freq;
ibool skip = FALSE;
- byte term[FTS_MAX_WORD_LEN + 1];
+ fts_string_t term;
+ byte buf[FTS_MAX_WORD_LEN + 1];
dberr_t error = DB_SUCCESS;
ut_a(query->cur_node->type == FTS_AST_TERM ||
query->cur_node->type == FTS_AST_TEXT);
memset(&node, 0, sizeof(node));
+ term.f_str = buf;
/* Need to consider the wildcard search case, the word frequency
is created on the search string not the actual word. So we need
@@ -3179,15 +3194,18 @@ fts_query_read_node(
/* These cast are safe since we only care about the
terminating NUL character as an end of string marker. */
- ut_strcpy((char*) term, (char*) query->cur_node->term.ptr);
+ term.f_len = ut_strlen(reinterpret_cast<char*>
+ (query->cur_node->term.ptr));
+ ut_ad(FTS_MAX_WORD_LEN >= term.f_len);
+ memcpy(term.f_str, query->cur_node->term.ptr, term.f_len);
} else {
- /* Need to copy the NUL character too. */
- memcpy(term, word->f_str, word->f_len);
- term[word->f_len] = 0;
+ term.f_len = word->f_len;
+ ut_ad(FTS_MAX_WORD_LEN >= word->f_len);
+ memcpy(term.f_str, word->f_str, word->f_len);
}
/* Lookup the word in our rb tree, it must exist. */
- ret = rbt_search(query->word_freqs, &parent, term);
+ ret = rbt_search(query->word_freqs, &parent, &term);
ut_a(ret == 0);
@@ -3239,7 +3257,7 @@ fts_query_read_node(
case 4: /* ILIST */
error = fts_query_filter_doc_ids(
- query, word_freq->word, word_freq,
+ query, &word_freq->word, word_freq,
&node, data, len, FALSE);
break;
@@ -3332,7 +3350,7 @@ fts_query_calculate_idf(
if (fts_enable_diag_print) {
fprintf(stderr,"'%s' -> " UINT64PF "/" UINT64PF
" %6.5lf\n",
- word_freq->word,
+ word_freq->word.f_str,
query->total_docs, word_freq->doc_count,
word_freq->idf);
}
@@ -3349,12 +3367,12 @@ fts_query_calculate_ranking(
fts_ranking_t* ranking) /*!< in: Document to rank */
{
ulint pos = 0;
- byte* word = NULL;
+ fts_string_t word;
/* At this stage, ranking->rank should not exceed the 1.0
bound */
ut_ad(ranking->rank <= 1.0 && ranking->rank >= -1.0);
- ut_ad(query->word_map->size() == query->word_vector->size());
+ ut_ad(rbt_size(query->word_map) == query->word_vector->size());
while (fts_ranking_words_get_next(query, ranking, &pos, &word)) {
int ret;
@@ -3363,8 +3381,7 @@ fts_query_calculate_ranking(
fts_doc_freq_t* doc_freq;
fts_word_freq_t* word_freq;
- ut_ad(word != NULL);
- ret = rbt_search(query->word_freqs, &parent, word);
+ ret = rbt_search(query->word_freqs, &parent, &word);
/* It must exist. */
ut_a(ret == 0);
@@ -3490,14 +3507,14 @@ fts_query_prepare_result(
doc_freq = rbt_value(fts_doc_freq_t, node);
/* Don't put deleted docs into result */
- if (fts_bsearch(array, 0, size, doc_freq->doc_id)
+ if (fts_bsearch(array, 0, static_cast<int>(size), doc_freq->doc_id)
>= 0) {
continue;
}
ranking.doc_id = doc_freq->doc_id;
- ranking.rank = doc_freq->freq * word_freq->idf
- * word_freq->idf;
+ ranking.rank = static_cast<fts_rank_t>(
+ doc_freq->freq * word_freq->idf * word_freq->idf);
ranking.words = NULL;
fts_query_add_ranking(query, result->rankings_by_id,
@@ -3620,18 +3637,18 @@ fts_query_free(
ut_a(!query->intersection);
- if (query->heap) {
- mem_heap_free(query->heap);
- }
-
if (query->word_map) {
- delete query->word_map;
+ rbt_free(query->word_map);
}
if (query->word_vector) {
delete query->word_vector;
}
+ if (query->heap) {
+ mem_heap_free(query->heap);
+ }
+
memset(query, 0, sizeof(*query));
}
@@ -3820,6 +3837,7 @@ fts_query(
query.fts_common_table.type = FTS_COMMON_TABLE;
query.fts_common_table.table_id = index->table->id;
query.fts_common_table.parent = index->table->name;
+ query.fts_common_table.table = index->table;
charset = fts_index_get_charset(index);
@@ -3828,15 +3846,17 @@ fts_query(
query.fts_index_table.table_id = index->table->id;
query.fts_index_table.parent = index->table->name;
query.fts_index_table.charset = charset;
+ query.fts_index_table.table = index->table;
- query.word_map = new word_map_t;
+ query.word_map = rbt_create_arg_cmp(
+ sizeof(fts_string_t), innobase_fts_text_cmp, (void*) charset);
query.word_vector = new word_vector_t;
query.error = DB_SUCCESS;
/* Setup the RB tree that will be used to collect per term
statistics. */
query.word_freqs = rbt_create_arg_cmp(
- sizeof(fts_word_freq_t), innobase_fts_string_cmp, (void*) charset);
+ sizeof(fts_word_freq_t), innobase_fts_text_cmp, (void*) charset);
query.total_size += SIZEOF_RBT_CREATE;
@@ -4060,13 +4080,14 @@ fts_print_doc_id(
fts_ranking_t* ranking;
ranking = rbt_value(fts_ranking_t, node);
- fprintf(stderr, "doc_ids info, doc_id: %ld \n",
+ ib_logf(IB_LOG_LEVEL_INFO, "doc_ids info, doc_id: %ld \n",
(ulint) ranking->doc_id);
- ulint pos = 0;
- byte* value = NULL;
- while (fts_ranking_words_get_next(query, ranking, &pos, &value)) {
- fprintf(stderr, "doc_ids info, value: %s \n", value);
+ ulint pos = 0;
+ fts_string_t word;
+
+ while (fts_ranking_words_get_next(query, ranking, &pos, &word)) {
+ ib_logf(IB_LOG_LEVEL_INFO, "doc_ids info, value: %s \n", word.f_str);
}
}
}
@@ -4122,7 +4143,7 @@ fts_expand_query(
fts_ranking_t* ranking;
ulint pos;
- byte* word;
+ fts_string_t word;
ulint prev_token_size;
ulint estimate_size;
@@ -4144,22 +4165,17 @@ fts_expand_query(
/* Remove words that have already been searched in the
first pass */
pos = 0;
- word = NULL;
while (fts_ranking_words_get_next(query, ranking, &pos,
- &word)) {
- fts_string_t str;
+ &word)) {
ibool ret;
- /* FIXME: We are discarding a const qualifier here. */
- str.f_str = word;
- str.f_len = ut_strlen((const char*) str.f_str);
- ret = rbt_delete(result_doc.tokens, &str);
+ ret = rbt_delete(result_doc.tokens, &word);
/* The word must exist in the doc we found */
if (!ret) {
- fprintf(stderr, " InnoDB: Error: Did not "
+ ib_logf(IB_LOG_LEVEL_ERROR, "Did not "
"find word %s in doc %ld for query "
- "expansion search.\n", str.f_str,
+ "expansion search.\n", word.f_str,
(ulint) ranking->doc_id);
}
}
@@ -4184,7 +4200,8 @@ fts_expand_query(
fts_token_t* mytoken;
mytoken = rbt_value(fts_token_t, token_node);
- fts_query_add_word_freq(query, mytoken->text.f_str);
+ ut_ad(mytoken->text.f_str[mytoken->text.f_len] == 0);
+ fts_query_add_word_freq(query, &mytoken->text);
error = fts_query_union(query, &mytoken->text);
if (error != DB_SUCCESS) {
@@ -4229,10 +4246,6 @@ fts_phrase_or_proximity_search(
ulint j;
ulint k = 0;
fts_proximity_t qualified_pos;
- ulint qualified_pos_buf[MAX_PROXIMITY_ITEM * 2];
-
- qualified_pos.min_pos = &qualified_pos_buf[0];
- qualified_pos.max_pos = &qualified_pos_buf[MAX_PROXIMITY_ITEM];
match[0] = static_cast<fts_match_t*>(
ib_vector_get(query->match_array[0], i));
@@ -4323,8 +4336,7 @@ fts_phrase_or_proximity_search(
token = static_cast<fts_string_t*>(
ib_vector_get(tokens, z));
fts_query_add_word_to_document(
- query, match[0]->doc_id,
- token->f_str);
+ query, match[0]->doc_id, token);
}
}
}
@@ -4365,7 +4377,7 @@ fts_proximity_get_positions(
qualified_pos->n_pos = 0;
- ut_a(num_match < MAX_PROXIMITY_ITEM);
+ ut_a(num_match <= MAX_PROXIMITY_ITEM);
/* Each word could appear multiple times in a doc. So
we need to walk through each word's position list, and find
@@ -4420,8 +4432,8 @@ fts_proximity_get_positions(
length encoding, record the min_pos and
max_pos, we will need to verify the actual
number of characters */
- qualified_pos->min_pos[qualified_pos->n_pos] = min_pos;
- qualified_pos->max_pos[qualified_pos->n_pos] = max_pos;
+ qualified_pos->min_pos.push_back(min_pos);
+ qualified_pos->max_pos.push_back(max_pos);
qualified_pos->n_pos++;
}
@@ -4430,7 +4442,5 @@ fts_proximity_get_positions(
idx[min_idx]++;
}
- ut_ad(qualified_pos->n_pos <= MAX_PROXIMITY_ITEM);
-
return(qualified_pos->n_pos != 0);
}
diff --git a/storage/xtradb/fts/fts0sql.cc b/storage/xtradb/fts/fts0sql.cc
index 03c19d93af6..cb8eff3cacc 100644
--- a/storage/xtradb/fts/fts0sql.cc
+++ b/storage/xtradb/fts/fts0sql.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2007, 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
@@ -61,21 +61,28 @@ fts_get_table_id(
long */
{
int len;
+ bool hex_name = DICT_TF2_FLAG_IS_SET(fts_table->table,
+ DICT_TF2_FTS_AUX_HEX_NAME);
+
+ ut_a(fts_table->table != NULL);
switch (fts_table->type) {
case FTS_COMMON_TABLE:
- len = fts_write_object_id(fts_table->table_id, table_id);
+ len = fts_write_object_id(fts_table->table_id, table_id,
+ hex_name);
break;
case FTS_INDEX_TABLE:
- len = fts_write_object_id(fts_table->table_id, table_id);
+ len = fts_write_object_id(fts_table->table_id, table_id,
+ hex_name);
table_id[len] = '_';
++len;
table_id += len;
- len += fts_write_object_id(fts_table->index_id, table_id);
+ len += fts_write_object_id(fts_table->index_id, table_id,
+ hex_name);
break;
default:
@@ -110,7 +117,7 @@ fts_get_table_name_prefix(
if (slash) {
/* Print up to and including the separator. */
- dbname_len = (slash - fts_table->parent) + 1;
+ dbname_len = static_cast<int>(slash - fts_table->parent) + 1;
}
len = fts_get_table_id(fts_table, table_id);
@@ -145,7 +152,8 @@ fts_get_table_name(
prefix_name = fts_get_table_name_prefix(fts_table);
- name_len = strlen(prefix_name) + 1 + strlen(fts_table->suffix) + 1;
+ name_len = static_cast<int>(
+ strlen(prefix_name) + 1 + strlen(fts_table->suffix) + 1);
name = static_cast<char*>(mem_alloc(name_len));
@@ -191,7 +199,7 @@ fts_parse_sql(
str = ut_str3cat(fts_sql_begin, str_tmp, fts_sql_end);
mem_free(str_tmp);
- dict_locked = (fts_table && fts_table->table
+ dict_locked = (fts_table && fts_table->table->fts
&& (fts_table->table->fts->fts_status
& TABLE_DICT_LOCKED));
diff --git a/storage/xtradb/fts/fts0tlex.cc b/storage/xtradb/fts/fts0tlex.cc
index 717ddb8a77e..ef17ab1acf2 100644
--- a/storage/xtradb/fts/fts0tlex.cc
+++ b/storage/xtradb/fts/fts0tlex.cc
@@ -35,7 +35,7 @@
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
+ * if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
@@ -52,7 +52,7 @@ typedef uint32_t flex_uint32_t;
typedef signed char flex_int8_t;
typedef short int flex_int16_t;
typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t;
+typedef unsigned char flex_uint8_t;
typedef unsigned short int flex_uint16_t;
typedef unsigned int flex_uint32_t;
@@ -185,7 +185,7 @@ typedef struct yy_buffer_state *YY_BUFFER_STATE;
#define EOB_ACT_LAST_MATCH 2
#define YY_LESS_LINENO(n)
-
+
/* Return all but the first "n" matched characters back to the input stream. */
#define yyless(n) \
do \
@@ -247,7 +247,7 @@ struct yy_buffer_state
int yy_bs_lineno; /**< The line count. */
int yy_bs_column; /**< The column count. */
-
+
/* Whether to try to fill the input buffer when we reach the
* end of it.
*/
@@ -305,9 +305,9 @@ YY_BUFFER_STATE fts0t_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner
YY_BUFFER_STATE fts0t_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
YY_BUFFER_STATE fts0t_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
-void *fts0talloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
-void *fts0trealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
-void fts0tfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
+void *fts0talloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
+void *fts0trealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
+void fts0tfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
#define yy_new_buffer fts0t_create_buffer
@@ -347,14 +347,14 @@ typedef int yy_state_type;
static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
static int yy_get_next_buffer (yyscan_t yyscanner );
-static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
+static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
/* Done after the current pattern has been matched and before the
* corresponding action - sets up yytext.
*/
#define YY_DO_BEFORE_ACTION \
yyg->yytext_ptr = yy_bp; \
- yyleng = (size_t) (yy_cp - yy_bp); \
+ yyleng = static_cast<int>(yy_cp - yy_bp); \
yyg->yy_hold_char = *yy_cp; \
*yy_cp = '\0'; \
yyg->yy_c_buf_p = yy_cp;
@@ -575,11 +575,11 @@ extern int fts0twrap (yyscan_t yyscanner );
#endif
#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
+static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
+static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
#endif
#ifndef YY_NO_INPUT
@@ -618,8 +618,8 @@ static int input (yyscan_t yyscanner );
if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
{ \
int c = '*'; \
- size_t n; \
- for ( n = 0; n < max_size && \
+ int n; \
+ for ( n = 0; n < static_cast<int>(max_size) && \
(c = getc( yyin )) != EOF && c != '\n'; ++n ) \
buf[n] = (char) c; \
if ( c == '\n' ) \
@@ -631,7 +631,8 @@ static int input (yyscan_t yyscanner );
else \
{ \
errno=0; \
- while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
+ while ( (result = static_cast<int>(fread(buf, 1, max_size, yyin)))==0 \
+ && ferror(yyin)) \
{ \
if( errno != EINTR) \
{ \
@@ -1019,8 +1020,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
else
{
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+ int num_to_read =static_cast<int>(
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1);
while ( num_to_read <= 0 )
{ /* Not enough room in the buffer - grow it. */
@@ -1033,7 +1034,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
if ( b->yy_is_our_buffer )
{
- int new_size = b->yy_buf_size * 2;
+ int new_size = static_cast<int>(b->yy_buf_size * 2);
if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8;
@@ -1054,8 +1055,8 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
yyg->yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
- num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
- number_to_move - 1;
+ num_to_read = static_cast<int>(
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1);
}
@@ -1064,7 +1065,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner)
/* Read in more data. */
YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
- yyg->yy_n_chars, (size_t) num_to_read );
+ yyg->yy_n_chars, num_to_read);
YY_CURRENT_BUFFER_LVALUE->yy_n_chars = yyg->yy_n_chars;
}
@@ -1312,7 +1313,7 @@ static void fts0t_load_buffer_state (yyscan_t yyscanner)
YY_BUFFER_STATE fts0t_create_buffer (FILE * file, int size , yyscan_t yyscanner)
{
YY_BUFFER_STATE b;
-
+
b = (YY_BUFFER_STATE) fts0talloc(sizeof( struct yy_buffer_state ) ,yyscanner );
if ( ! b )
YY_FATAL_ERROR( "out of dynamic memory in fts0t_create_buffer()" );
@@ -1378,7 +1379,7 @@ static void fts0t_load_buffer_state (yyscan_t yyscanner)
}
b->yy_is_interactive = 0;
-
+
errno = oerrno;
}
@@ -1484,9 +1485,9 @@ static void fts0tensure_buffer_stack (yyscan_t yyscanner)
, yyscanner);
if ( ! yyg->yy_buffer_stack )
YY_FATAL_ERROR( "out of dynamic memory in fts0tensure_buffer_stack()" );
-
+
memset(yyg->yy_buffer_stack, 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-
+
yyg->yy_buffer_stack_max = num_to_alloc;
yyg->yy_buffer_stack_top = 0;
return;
@@ -1497,7 +1498,7 @@ static void fts0tensure_buffer_stack (yyscan_t yyscanner)
/* Increase the buffer to prepare for a possible push. */
int grow_size = 8 /* arbitrary grow size */;
- num_to_alloc = yyg->yy_buffer_stack_max + grow_size;
+ num_to_alloc = static_cast<int>(yyg->yy_buffer_stack_max + grow_size);
yyg->yy_buffer_stack = (struct yy_buffer_state**)fts0trealloc
(yyg->yy_buffer_stack,
num_to_alloc * sizeof(struct yy_buffer_state*)
@@ -1515,12 +1516,12 @@ static void fts0tensure_buffer_stack (yyscan_t yyscanner)
* @param base the character buffer
* @param size the size in bytes of the character buffer
* @param yyscanner The scanner object.
- * @return the newly allocated buffer state object.
+ * @return the newly allocated buffer state object.
*/
YY_BUFFER_STATE fts0t_scan_buffer (char * base, yy_size_t size , yyscan_t yyscanner)
{
YY_BUFFER_STATE b;
-
+
if ( size < 2 ||
base[size-2] != YY_END_OF_BUFFER_CHAR ||
base[size-1] != YY_END_OF_BUFFER_CHAR )
@@ -1535,7 +1536,7 @@ YY_BUFFER_STATE fts0t_scan_buffer (char * base, yy_size_t size , yyscan_t yysc
b->yy_buf_pos = b->yy_ch_buf = base;
b->yy_is_our_buffer = 0;
b->yy_input_file = 0;
- b->yy_n_chars = b->yy_buf_size;
+ b->yy_n_chars = static_cast<int>(b->yy_buf_size);
b->yy_is_interactive = 0;
b->yy_at_bol = 1;
b->yy_fill_buffer = 0;
@@ -1556,8 +1557,8 @@ YY_BUFFER_STATE fts0t_scan_buffer (char * base, yy_size_t size , yyscan_t yysc
*/
YY_BUFFER_STATE fts0t_scan_string (yyconst char * yystr , yyscan_t yyscanner)
{
-
- return fts0t_scan_bytes(yystr,strlen(yystr) ,yyscanner);
+
+ return fts0t_scan_bytes(yystr,static_cast<int>(strlen(yystr)) ,yyscanner);
}
/** Setup the input buffer state to scan the given bytes. The next call to fts0tlex() will
@@ -1573,7 +1574,7 @@ YY_BUFFER_STATE fts0t_scan_bytes (yyconst char * yybytes, int _yybytes_len , y
char *buf;
yy_size_t n;
int i;
-
+
/* Get memory for full buffer, including space for trailing EOB's. */
n = _yybytes_len + 2;
buf = (char *) fts0talloc(n ,yyscanner );
@@ -1601,7 +1602,7 @@ YY_BUFFER_STATE fts0t_scan_bytes (yyconst char * yybytes, int _yybytes_len , y
#define YY_EXIT_FAILURE 2
#endif
-static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
(void) fprintf( stderr, "%s\n", msg );
exit( YY_EXIT_FAILURE );
@@ -1641,10 +1642,10 @@ YY_EXTRA_TYPE fts0tget_extra (yyscan_t yyscanner)
int fts0tget_lineno (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
+
if (! YY_CURRENT_BUFFER)
return 0;
-
+
return yylineno;
}
@@ -1654,10 +1655,10 @@ int fts0tget_lineno (yyscan_t yyscanner)
int fts0tget_column (yyscan_t yyscanner)
{
struct yyguts_t * yyg = (struct yyguts_t*)yyscanner;
-
+
if (! YY_CURRENT_BUFFER)
return 0;
-
+
return yycolumn;
}
@@ -1718,8 +1719,8 @@ void fts0tset_lineno (int line_number , yyscan_t yyscanner)
/* lineno is only valid if an input buffer exists. */
if (! YY_CURRENT_BUFFER )
- yy_fatal_error( "fts0tset_lineno called with no buffer" , yyscanner);
-
+ yy_fatal_error( "fts0tset_lineno called with no buffer" , yyscanner);
+
yylineno = line_number;
}
@@ -1733,8 +1734,8 @@ void fts0tset_column (int column_no , yyscan_t yyscanner)
/* column is only valid if an input buffer exists. */
if (! YY_CURRENT_BUFFER )
- yy_fatal_error( "fts0tset_column called with no buffer" , yyscanner);
-
+ yy_fatal_error( "fts0tset_column called with no buffer" , yyscanner);
+
yycolumn = column_no;
}
@@ -1817,20 +1818,20 @@ int fts0tlex_init_extra(YY_EXTRA_TYPE yy_user_defined,yyscan_t* ptr_yy_globals )
errno = EINVAL;
return 1;
}
-
+
*ptr_yy_globals = (yyscan_t) fts0talloc ( sizeof( struct yyguts_t ), &dummy_yyguts );
-
+
if (*ptr_yy_globals == NULL){
errno = ENOMEM;
return 1;
}
-
+
/* By setting to 0xAA, we expose bugs in
yy_init_globals. Leave at 0x00 for releases. */
memset(*ptr_yy_globals,0x00,sizeof(struct yyguts_t));
-
+
fts0tset_extra (yy_user_defined, *ptr_yy_globals);
-
+
return yy_init_globals ( *ptr_yy_globals );
}
@@ -1902,7 +1903,7 @@ int fts0tlex_destroy (yyscan_t yyscanner)
*/
#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
register int i;
for ( i = 0; i < n; ++i )
@@ -1911,7 +1912,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t
#endif
#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
register int n;
for ( n = 0; s[n]; ++n )
@@ -1921,12 +1922,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribu
}
#endif
-void *fts0talloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+void *fts0talloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
return (void *) malloc( size );
}
-void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
/* The cast to (char *) in the following accommodates both
* implementations that use char* generic pointers, and those
@@ -1938,7 +1939,7 @@ void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __at
return (void *) realloc( (char *) ptr, size );
}
-void fts0tfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
+void fts0tfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
{
free( (char *) ptr ); /* see fts0trealloc() for (char *) cast */
}
diff --git a/storage/xtradb/handler/ha_innodb.cc b/storage/xtradb/handler/ha_innodb.cc
index 1b3a4805e78..8d4458bde70 100644
--- a/storage/xtradb/handler/ha_innodb.cc
+++ b/storage/xtradb/handler/ha_innodb.cc
@@ -1,9 +1,10 @@
/*****************************************************************************
-Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2000, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
Copyright (c) 2012, Facebook Inc.
+Copyright (c) 2013, 2014 SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -97,6 +98,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include "fts0types.h"
#include "row0import.h"
#include "row0quiesce.h"
+#include "row0mysql.h"
#ifdef UNIV_DEBUG
#include "trx0purge.h"
#endif /* UNIV_DEBUG */
@@ -469,6 +471,7 @@ static PSI_thread_info all_innodb_threads[] = {
{&srv_master_thread_key, "srv_master_thread", 0},
{&srv_purge_thread_key, "srv_purge_thread", 0},
{&buf_page_cleaner_thread_key, "page_cleaner_thread", 0},
+ {&buf_lru_manager_thread_key, "lru_manager_thread", 0},
{&recv_writer_thread_key, "recv_writer_thread", 0},
{&srv_log_tracking_thread_key, "srv_redo_log_follow_thread", 0}
};
@@ -547,6 +550,7 @@ ib_cb_t innodb_api_cb[] = {
(ib_cb_t) ib_cursor_open_index_using_name,
(ib_cb_t) ib_close_thd,
(ib_cb_t) ib_cfg_get_cfg,
+ (ib_cb_t) ib_cursor_set_memcached_sync,
(ib_cb_t) ib_cursor_set_cluster_access,
(ib_cb_t) ib_cursor_commit_trx,
(ib_cb_t) ib_cfg_trx_level,
@@ -965,6 +969,19 @@ innobase_rollback_to_savepoint(
void* savepoint); /*!< in: savepoint data */
/*****************************************************************//**
+Check whether innodb state allows to safely release MDL locks after
+rollback to savepoint.
+@return true if it is safe, false if its not safe. */
+static
+bool
+innobase_rollback_to_savepoint_can_release_mdl(
+/*===========================================*/
+ handlerton* hton, /*!< in/out: InnoDB handlerton */
+ THD* thd); /*!< in: handle to the MySQL thread of
+ the user whose XA transaction should
+ be rolled back to savepoint */
+
+/*****************************************************************//**
Sets a transaction savepoint.
@return always 0, that is, always succeeds */
static
@@ -1802,6 +1819,8 @@ convert_error_code_to_mysql(
return(HA_ERR_TABLESPACE_EXISTS);
case DB_IDENTIFIER_TOO_LONG:
return(HA_ERR_INTERNAL_ERROR);
+ case DB_FTS_TOO_MANY_WORDS_IN_PHRASE:
+ return(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE);
}
}
@@ -1909,11 +1928,11 @@ innobase_check_identifier_length(
CHARSET_INFO *cs = system_charset_info;
DBUG_ENTER("innobase_check_identifier_length");
- uint res = cs->cset->well_formed_len(cs, id, id + strlen(id),
- NAME_CHAR_LEN,
- &well_formed_error);
+ size_t len = cs->cset->well_formed_len(
+ cs, id, id + strlen(id),
+ NAME_CHAR_LEN, &well_formed_error);
- if (well_formed_error || res == NAME_CHAR_LEN) {
+ if (well_formed_error || len == NAME_CHAR_LEN) {
my_error(ER_TOO_LONG_IDENT, MYF(0), id);
DBUG_RETURN(true);
}
@@ -2768,7 +2787,7 @@ innobase_query_caching_of_table_permitted(
store a result to the query cache or
retrieve it */
char* full_name, /*!< in: normalized path to the table */
- uint full_name_len, /*!< in: length of the normalized path
+ uint full_name_len, /*!< in: length of the normalized path
to the table */
ulonglong *unused) /*!< unused for this engine */
{
@@ -3190,6 +3209,8 @@ innobase_init(
innobase_hton->close_connection = innobase_close_connection;
innobase_hton->savepoint_set = innobase_savepoint;
innobase_hton->savepoint_rollback = innobase_rollback_to_savepoint;
+ innobase_hton->savepoint_rollback_can_release_mdl =
+ innobase_rollback_to_savepoint_can_release_mdl;
innobase_hton->savepoint_release = innobase_release_savepoint;
innobase_hton->commit_ordered=innobase_commit_ordered;
innobase_hton->commit = innobase_commit;
@@ -3339,7 +3360,8 @@ innobase_init(
internal_innobase_data_file_path);
if (ret == FALSE) {
sql_print_error(
- "InnoDB: syntax error in innodb_data_file_path");
+ "InnoDB: syntax error in innodb_data_file_path"
+ " or size specified is less than 1 megabyte");
mem_free_and_error:
srv_free_paths_and_sizes();
my_free(internal_innobase_data_file_path);
@@ -3491,8 +3513,8 @@ innobase_change_buffering_inited_ok:
} else {
/* The user has not set the value. We should
set it based on innodb_io_capacity. */
- srv_max_io_capacity =
- ut_max(2 * srv_io_capacity, 2000);
+ srv_max_io_capacity = static_cast<ulong>(
+ ut_max(2 * srv_io_capacity, 2000));
}
} else if (srv_max_io_capacity < srv_io_capacity) {
@@ -3744,8 +3766,8 @@ innobase_change_buffering_inited_ok:
/* Adjust the innodb_undo_logs config object */
innobase_undo_logs_init_default_max();
- innobase_old_blocks_pct = buf_LRU_old_ratio_update(
- innobase_old_blocks_pct, TRUE);
+ innobase_old_blocks_pct = static_cast<uint>(
+ buf_LRU_old_ratio_update(innobase_old_blocks_pct, TRUE));
ibuf_max_size_update(innobase_change_buffer_max_size);
@@ -4462,6 +4484,38 @@ innobase_rollback_to_savepoint(
}
/*****************************************************************//**
+Check whether innodb state allows to safely release MDL locks after
+rollback to savepoint.
+When binlog is on, MDL locks acquired after savepoint unit are not
+released if there are any locks held in InnoDB.
+@return true if it is safe, false if its not safe. */
+static
+bool
+innobase_rollback_to_savepoint_can_release_mdl(
+/*===========================================*/
+ handlerton* hton, /*!< in: InnoDB handlerton */
+ THD* thd) /*!< in: handle to the MySQL thread
+ of the user whose transaction should
+ be rolled back to savepoint */
+{
+ trx_t* trx;
+
+ DBUG_ENTER("innobase_rollback_to_savepoint_can_release_mdl");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
+ trx = check_trx_exists(thd);
+ ut_ad(trx);
+
+ /* If transaction has not acquired any locks then it is safe
+ to release MDL after rollback to savepoint */
+ if (!(UT_LIST_GET_LEN(trx->lock.trx_locks))) {
+ DBUG_RETURN(true);
+ }
+
+ DBUG_RETURN(false);
+}
+
+/*****************************************************************//**
Release transaction savepoint name.
@return 0 if success, HA_ERR_NO_SAVEPOINT if no savepoint with the
given name */
@@ -4650,12 +4704,15 @@ innobase_kill_connection(
DBUG_ENTER("innobase_kill_connection");
DBUG_ASSERT(hton == innodb_hton_ptr);
- lock_mutex_enter();
-
trx = thd_to_trx(thd);
- if (trx)
- {
+ if (trx) {
+ THD *cur = current_thd;
+ THD *owner = trx->current_lock_mutex_owner;
+
+ if (owner != cur) {
+ lock_mutex_enter();
+ }
trx_mutex_enter(trx);
/* Cancel a pending lock request. */
@@ -4663,10 +4720,11 @@ innobase_kill_connection(
lock_cancel_waiting_and_release(trx->lock.wait_lock);
trx_mutex_exit(trx);
+ if (owner != cur) {
+ lock_mutex_exit();
+ }
}
- lock_mutex_exit();
-
DBUG_VOID_RETURN;
}
@@ -4680,14 +4738,11 @@ handler::Table_flags
ha_innobase::table_flags() const
/*============================*/
{
- THD *thd = ha_thd();
/* Need to use tx_isolation here since table flags is (also)
called before prebuilt is inited. */
- ulong const tx_isolation = thd_tx_isolation(thd);
+ ulong const tx_isolation = thd_tx_isolation(ha_thd());
- if (tx_isolation <= ISO_READ_COMMITTED &&
- !(tx_isolation == ISO_READ_COMMITTED &&
- thd_rpl_is_parallel(thd))) {
+ if (tx_isolation <= ISO_READ_COMMITTED) {
return(int_table_flags);
}
@@ -5705,7 +5760,7 @@ table_opened:
/* Find corresponding cluster index
key length in MySQL's key_info[] array */
- for (ulint i = 0; i < table->s->keys; i++) {
+ for (uint i = 0; i < table->s->keys; i++) {
dict_index_t* index;
index = innobase_get_index(i);
if (dict_index_is_clust(index)) {
@@ -6071,8 +6126,9 @@ innobase_fts_text_cmp(
const fts_string_t* s1 = (const fts_string_t*) p1;
const fts_string_t* s2 = (const fts_string_t*) p2;
- return(ha_compare_text(charset, s1->f_str, s1->f_len,
- s2->f_str, s2->f_len, 0, 0));
+ return(ha_compare_text(
+ charset, s1->f_str, static_cast<uint>(s1->f_len),
+ s2->f_str, static_cast<uint>(s2->f_len), 0, 0));
}
/******************************************************************//**
compare two character string case insensitively according to their charset. */
@@ -6093,8 +6149,9 @@ innobase_fts_text_case_cmp(
newlen = strlen((const char*) s2->f_str);
- return(ha_compare_text(charset, s1->f_str, s1->f_len,
- s2->f_str, newlen, 0, 0));
+ return(ha_compare_text(
+ charset, s1->f_str, static_cast<uint>(s1->f_len),
+ s2->f_str, static_cast<uint>(newlen), 0, 0));
}
/******************************************************************//**
Get the first character's code position for FTS index partition. */
@@ -6140,30 +6197,15 @@ innobase_fts_text_cmp_prefix(
const fts_string_t* s2 = (const fts_string_t*) p2;
int result;
- result = ha_compare_text(charset, s2->f_str, s2->f_len,
- s1->f_str, s1->f_len, 1, 0);
+ result = ha_compare_text(
+ charset, s2->f_str, static_cast<uint>(s2->f_len),
+ s1->f_str, static_cast<uint>(s1->f_len), 1, 0);
/* We switched s1, s2 position in ha_compare_text. So we need
to negate the result */
return(-result);
}
-/******************************************************************//**
-compare two character string according to their charset. */
-UNIV_INTERN
-int
-innobase_fts_string_cmp(
-/*====================*/
- const void* cs, /*!< in: Character set */
- const void* p1, /*!< in: key */
- const void* p2) /*!< in: node */
-{
- const CHARSET_INFO* charset = (const CHARSET_INFO*) cs;
- uchar* s1 = (uchar*) p1;
- uchar* s2 = *(uchar**) p2;
- return(ha_compare_text(charset, s1, strlen((const char*) s1),
- s2, strlen((const char*) s2), 0, 0));
-}
/******************************************************************//**
Makes all characters in a string lower case. */
UNIV_INTERN
@@ -6727,8 +6769,8 @@ build_template_needs_field(
return(field);
}
- if (bitmap_is_set(table->read_set, sql_idx)
- || bitmap_is_set(table->write_set, sql_idx)) {
+ if (bitmap_is_set(table->read_set, static_cast<uint>(sql_idx))
+ || bitmap_is_set(table->write_set, static_cast<uint>(sql_idx))) {
/* This field is needed in the query */
return(field);
@@ -8431,6 +8473,29 @@ ha_innobase::innobase_get_index(
index = innobase_index_lookup(share, keynr);
if (index) {
+
+ if (!key || ut_strcmp(index->name, key->name) != 0) {
+ fprintf(stderr, "InnoDB: [Error] Index for key no %u"
+ " mysql name %s , InnoDB name %s for table %s\n",
+ keynr, key ? key->name : "NULL",
+ index->name,
+ prebuilt->table->name);
+
+ for(ulint i=0; i < table->s->keys; i++) {
+ index = innobase_index_lookup(share, i);
+ key = table->key_info + keynr;
+
+ if (index) {
+
+ fprintf(stderr, "InnoDB: [Note] Index for key no %u"
+ " mysql name %s , InnoDB name %s for table %s\n",
+ keynr, key ? key->name : "NULL",
+ index->name,
+ prebuilt->table->name);
+ }
+ }
+ }
+
ut_a(ut_strcmp(index->name, key->name) == 0);
} else {
/* Can't find index with keynr in the translation
@@ -9237,12 +9302,6 @@ ha_innobase::position(
}
}
-/* limit innodb monitor access to users with PROCESS privilege.
-See http://bugs.mysql.com/32710 for expl. why we choose PROCESS. */
-#define IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(table_name, thd) \
- (row_is_magic_monitor_table(table_name) \
- && check_global_access(thd, PROCESS_ACL))
-
/*****************************************************************//**
Check whether there exist a column named as "FTS_DOC_ID", which is
reserved for InnoDB FTS Doc ID
@@ -9357,16 +9416,6 @@ create_table_def(
DBUG_RETURN(ER_TABLE_NAME);
}
- /* table_name must contain '/'. Later in the code we assert if it
- does not */
- if (strcmp(strchr(table_name, '/') + 1,
- "innodb_table_monitor") == 0) {
- push_warning(
- thd, Sql_condition::WARN_LEVEL_WARN,
- HA_ERR_WRONG_COMMAND,
- DEPRECATED_MSG_INNODB_TABLE_MONITOR);
- }
-
n_cols = form->s->fields;
s_cols = form->s->stored_fields;
@@ -9391,18 +9440,18 @@ create_table_def(
/* Adjust for the FTS hidden field */
if (!has_doc_id_col) {
table = dict_mem_table_create(table_name, 0, s_cols + 1,
- flags, flags2);
+ flags, flags2, false);
/* Set the hidden doc_id column. */
table->fts->doc_col = s_cols;
} else {
table = dict_mem_table_create(table_name, 0, s_cols,
- flags, flags2);
+ flags, flags2, false);
table->fts->doc_col = doc_id_col;
}
} else {
table = dict_mem_table_create(table_name, 0, s_cols,
- flags, flags2);
+ flags, flags2, false);
}
if (flags2 & DICT_TF2_TEMPORARY) {
@@ -9466,7 +9515,7 @@ create_table_def(
/* we assume in dtype_form_prtype() that this fits in
two bytes */
- ut_a(field->type() <= MAX_CHAR_COLL_NUM);
+ ut_a(static_cast<uint>(field->type()) <= MAX_CHAR_COLL_NUM);
col_len = field->pack_length();
/* The MySQL pack length contains 1 or 2 bytes length field
@@ -9740,6 +9789,7 @@ get_row_format_name(
return("FIXED");
case ROW_TYPE_PAGE:
case ROW_TYPE_NOT_USED:
+ default:
break;
}
return("NOT USED");
@@ -9885,6 +9935,7 @@ create_options_are_invalid(
case ROW_TYPE_FIXED:
case ROW_TYPE_PAGE:
case ROW_TYPE_NOT_USED:
+ default:
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION, \
@@ -10252,6 +10303,7 @@ index_bad:
case ROW_TYPE_NOT_USED:
case ROW_TYPE_FIXED:
case ROW_TYPE_PAGE:
+ default:
push_warning(
thd, Sql_condition::WARN_LEVEL_WARN,
ER_ILLEGAL_HA_CREATE_OPTION,
@@ -10282,6 +10334,11 @@ index_bad:
*flags2 |= DICT_TF2_USE_TABLESPACE;
}
+ /* Set the flags2 when create table or alter tables */
+ *flags2 |= DICT_TF2_FTS_AUX_HEX_NAME;
+ DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
+ *flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;);
+
DBUG_RETURN(true);
}
@@ -10373,8 +10430,23 @@ ha_innobase::create(
DBUG_RETURN(-1);
}
- if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
- DBUG_RETURN(HA_ERR_GENERIC);
+ if (row_is_magic_monitor_table(norm_name)) {
+ push_warning_printf(thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_WRONG_COMMAND,
+ "Using the table name %s to enable "
+ "diagnostic output is deprecated "
+ "and may be removed in future releases. "
+ "Use INFORMATION_SCHEMA or "
+ "PERFORMANCE_SCHEMA tables or "
+ "SET GLOBAL innodb_status_output=ON.",
+ dict_remove_db_name(norm_name));
+
+ /* Limit innodb monitor access to users with PROCESS privilege.
+ See http://bugs.mysql.com/32710 why we chose PROCESS. */
+ if (check_global_access(thd, PROCESS_ACL)) {
+ DBUG_RETURN(HA_ERR_GENERIC);
+ }
}
/* Get the transaction associated with the current thd, or create one
@@ -10836,7 +10908,8 @@ ha_innobase::delete_table(
if (srv_read_only_mode) {
DBUG_RETURN(HA_ERR_TABLE_READONLY);
- } else if (IS_MAGIC_TABLE_AND_USER_DENIED_ACCESS(norm_name, thd)) {
+ } else if (row_is_magic_monitor_table(norm_name)
+ && check_global_access(thd, PROCESS_ACL)) {
DBUG_RETURN(HA_ERR_GENERIC);
}
@@ -11085,17 +11158,7 @@ innobase_rename_table(
}
}
- if (error != DB_SUCCESS) {
- if (!srv_read_only_mode) {
- FILE* ef = dict_foreign_err_file;
-
- fputs("InnoDB: Renaming table ", ef);
- ut_print_name(ef, trx, TRUE, norm_from);
- fputs(" to ", ef);
- ut_print_name(ef, trx, TRUE, norm_to);
- fputs(" failed!\n", ef);
- }
- } else {
+ if (error == DB_SUCCESS) {
#ifndef __WIN__
sql_print_warning("Rename partition table %s "
"succeeds after converting to lower "
@@ -11973,6 +12036,35 @@ ha_innobase::info_low(
break;
}
+ DBUG_EXECUTE_IF("ib_ha_innodb_stat_not_initialized",
+ index->table->stat_initialized = FALSE;);
+
+ if (!ib_table->stat_initialized ||
+ (index->table != ib_table ||
+ !index->table->stat_initialized)) {
+ fprintf(stderr,
+ "InnoDB: Warning: Index %s points to table %s"
+ " and ib_table %s statistics is initialized %d "
+ " but index table %s initialized %d "
+ " mysql table is %s. Have you mixed "
+ "up .frm files from different "
+ "installations? "
+ "See " REFMAN
+ "innodb-troubleshooting.html\n",
+ index->name,
+ index->table->name,
+ ib_table->name,
+ ib_table->stat_initialized,
+ index->table->name,
+ index->table->stat_initialized,
+ table->s->table_name.str
+ );
+
+ /* This is better than
+ assert on below function */
+ dict_stats_init(index->table);
+ }
+
rec_per_key = innodb_rec_per_key(
index, j, stats.records);
@@ -12101,7 +12193,8 @@ ha_innobase::optimize(
calls to OPTIMIZE, which is undesirable. */
if (innodb_optimize_fulltext_only) {
- if (prebuilt->table->fts && prebuilt->table->fts->cache) {
+ if (prebuilt->table->fts && prebuilt->table->fts->cache
+ && !dict_table_is_discarded(prebuilt->table)) {
fts_sync_table(prebuilt->table);
fts_optimize_table(prebuilt->table);
}
@@ -12532,12 +12625,14 @@ get_foreign_key_info(
tmp_buff[len] = 0;
len = filename_to_tablename(tmp_buff, name_buff, sizeof(name_buff));
- f_key_info.referenced_db = thd_make_lex_string(thd, 0, name_buff, len, 1);
+ f_key_info.referenced_db = thd_make_lex_string(
+ thd, 0, name_buff, static_cast<unsigned int>(len), 1);
/* Referenced (parent) table name */
ptr = dict_remove_db_name(foreign->referenced_table_name);
len = filename_to_tablename(ptr, name_buff, sizeof(name_buff));
- f_key_info.referenced_table = thd_make_lex_string(thd, 0, name_buff, len, 1);
+ f_key_info.referenced_table = thd_make_lex_string(
+ thd, 0, name_buff, static_cast<unsigned int>(len), 1);
/* Dependent (child) database name */
len = dict_get_db_name_len(foreign->foreign_table_name);
@@ -12546,12 +12641,14 @@ get_foreign_key_info(
tmp_buff[len] = 0;
len = filename_to_tablename(tmp_buff, name_buff, sizeof(name_buff));
- f_key_info.foreign_db = thd_make_lex_string(thd, 0, name_buff, len, 1);
+ f_key_info.foreign_db = thd_make_lex_string(
+ thd, 0, name_buff, static_cast<unsigned int>(len), 1);
/* Dependent (child) table name */
ptr = dict_remove_db_name(foreign->foreign_table_name);
len = filename_to_tablename(ptr, name_buff, sizeof(name_buff));
- f_key_info.foreign_table = thd_make_lex_string(thd, 0, name_buff, len, 1);
+ f_key_info.foreign_table = thd_make_lex_string(
+ thd, 0, name_buff, static_cast<unsigned int>(len), 1);
do {
ptr = foreign->foreign_col_names[i];
@@ -12578,9 +12675,9 @@ get_foreign_key_info(
ptr = "RESTRICT";
}
- f_key_info.delete_method = thd_make_lex_string(thd,
- f_key_info.delete_method,
- ptr, len, 1);
+ f_key_info.delete_method = thd_make_lex_string(
+ thd, f_key_info.delete_method, ptr,
+ static_cast<unsigned int>(len), 1);
if (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE) {
len = 7;
@@ -12596,9 +12693,9 @@ get_foreign_key_info(
ptr = "RESTRICT";
}
- f_key_info.update_method = thd_make_lex_string(thd,
- f_key_info.update_method,
- ptr, len, 1);
+ f_key_info.update_method = thd_make_lex_string(
+ thd, f_key_info.update_method, ptr,
+ static_cast<unsigned int>(len), 1);
if (foreign->referenced_index && foreign->referenced_index->name) {
referenced_key_name = thd_make_lex_string(thd,
@@ -13399,7 +13496,8 @@ innodb_show_status(
memcpy(str + len, truncated_msg, sizeof truncated_msg - 1);
len += sizeof truncated_msg - 1;
usable_len = (MAX_STATUS_SIZE - 1) - len;
- fseek(srv_monitor_file, flen - usable_len, SEEK_SET);
+ fseek(srv_monitor_file,
+ static_cast<long>(flen - usable_len), SEEK_SET);
len += fread(str + len, 1, usable_len, srv_monitor_file);
flen = len;
} else {
@@ -13409,9 +13507,10 @@ innodb_show_status(
mutex_exit(&srv_monitor_file_mutex);
- ret_val= stat_print(thd, innobase_hton_name,
- (uint) strlen(innobase_hton_name),
- STRING_WITH_LEN(""), str, flen);
+ ret_val= stat_print(
+ thd, innobase_hton_name,
+ static_cast<uint>(strlen(innobase_hton_name)),
+ STRING_WITH_LEN(""), str, static_cast<uint>(flen));
my_free(str);
@@ -13515,10 +13614,12 @@ innodb_mutex_show_status(
continue;
}
- buf1len = my_snprintf(buf1, sizeof buf1, "%s",
- lock->lock_name);
- buf2len = my_snprintf(buf2, sizeof buf2, "os_waits=%lu",
- (ulong) lock->count_os_wait);
+ buf1len = (uint) my_snprintf(
+ buf1, sizeof buf1, "%s",
+ lock->lock_name);
+ buf2len = (uint) my_snprintf(
+ buf2, sizeof buf2, "os_waits=%lu",
+ static_cast<ulong>(lock->count_os_wait));
if (stat_print(thd, innobase_hton_name,
hton_name_len, buf1, buf1len,
@@ -13547,7 +13648,7 @@ innodb_mutex_show_status(
mutex_exit(&rw_lock_list_mutex);
#ifdef UNIV_DEBUG
- buf2len = my_snprintf(buf2, sizeof buf2,
+ buf2len = static_cast<uint>(my_snprintf(buf2, sizeof buf2,
"count=%lu, spin_waits=%lu, spin_rounds=%lu, "
"os_waits=%lu, os_yields=%lu, os_wait_times=%lu",
(ulong) rw_lock_count,
@@ -13555,7 +13656,7 @@ innodb_mutex_show_status(
(ulong) rw_lock_count_spin_rounds,
(ulong) rw_lock_count_os_wait,
(ulong) rw_lock_count_os_yield,
- (ulong) (rw_lock_wait_time / 1000));
+ (ulong) (rw_lock_wait_time / 1000)));
if (stat_print(thd, innobase_hton_name, hton_name_len,
STRING_WITH_LEN("rw_lock_mutexes"), buf2, buf2len)) {
@@ -14088,6 +14189,21 @@ ha_innobase::get_auto_increment(
current = *first_value;
+ /* If the increment step of the auto increment column
+ decreases then it is not affecting the immediate
+ next value in the series. */
+ if (prebuilt->autoinc_increment > increment) {
+
+ current = autoinc - prebuilt->autoinc_increment;
+
+ current = innobase_next_autoinc(
+ current, 1, increment, 1, col_max_value);
+
+ dict_table_autoinc_initialize(prebuilt->table, current);
+
+ *first_value = current;
+ }
+
/* Compute the last value in the interval */
next_value = innobase_next_autoinc(
current, *nb_reserved_values, increment, offset,
@@ -14307,7 +14423,7 @@ my_bool
ha_innobase::register_query_cache_table(
/*====================================*/
THD* thd, /*!< in: user thread handle */
- char* table_key, /*!< in: normalized path to the
+ char* table_key, /*!< in: normalized path to the
table */
uint key_length, /*!< in: length of the normalized
path to the table */
@@ -15305,8 +15421,9 @@ innodb_old_blocks_pct_update(
const void* save) /*!< in: immediate result
from check function */
{
- innobase_old_blocks_pct = buf_LRU_old_ratio_update(
- *static_cast<const uint*>(save), TRUE);
+ innobase_old_blocks_pct = static_cast<uint>(
+ buf_LRU_old_ratio_update(
+ *static_cast<const uint*>(save), TRUE));
}
/****************************************************************//**
@@ -15329,6 +15446,66 @@ innodb_change_buffer_max_size_update(
ibuf_max_size_update(innobase_change_buffer_max_size);
}
+#ifdef UNIV_DEBUG
+ulong srv_fil_make_page_dirty_debug = 0;
+ulong srv_saved_page_number_debug = 0;
+
+/****************************************************************//**
+Save an InnoDB page number. */
+static
+void
+innodb_save_page_no(
+/*================*/
+ 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_saved_page_number_debug = *static_cast<const ulong*>(save);
+
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Saving InnoDB page number: %lu",
+ srv_saved_page_number_debug);
+}
+
+/****************************************************************//**
+Make the first page of given user tablespace dirty. */
+static
+void
+innodb_make_page_dirty(
+/*===================*/
+ 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 */
+{
+ mtr_t mtr;
+ ulong space_id = *static_cast<const ulong*>(save);
+
+ mtr_start(&mtr);
+
+ buf_block_t* block = buf_page_get(
+ space_id, 0, srv_saved_page_number_debug, RW_X_LATCH, &mtr);
+
+ if (block) {
+ byte* page = block->frame;
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Dirtying page:%lu of space:%lu",
+ page_get_page_no(page),
+ page_get_space_id(page));
+ mlog_write_ulint(page + FIL_PAGE_TYPE,
+ fil_page_get_type(page),
+ MLOG_2BYTES, &mtr);
+ }
+ mtr_commit(&mtr);
+}
+#endif // UNIV_DEBUG
/*************************************************************//**
Find the corresponding ibuf_use_t value that indexes into
@@ -16105,7 +16282,7 @@ innodb_enable_monitor_at_startup(
/****************************************************************//**
Update the innodb_sched_priority_cleaner variable and set the thread
-priority accordingly. */
+priorities accordingly. */
static
void
innodb_sched_priority_cleaner_update(
@@ -16121,6 +16298,24 @@ innodb_sched_priority_cleaner_update(
ulint priority = *static_cast<const ulint *>(save);
ulint actual_priority;
+ /* Set the priority for the LRU manager thread */
+ ut_ad(buf_lru_manager_is_active);
+ actual_priority = os_thread_set_priority(srv_lru_manager_tid,
+ priority);
+ if (UNIV_UNLIKELY(actual_priority != priority)) {
+
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_ARGUMENTS,
+ "Failed to set the LRU manager thread "
+ "priority to %lu, "
+ "the current priority is %lu", priority,
+ actual_priority);
+ } else {
+
+ srv_sched_priority_cleaner = priority;
+ }
+
+ /* Set the priority for the page cleaner thread */
if (srv_read_only_mode) {
return;
@@ -16136,9 +16331,6 @@ innodb_sched_priority_cleaner_update(
"priority to %lu, "
"the current priority is %lu", priority,
actual_priority);
- } else {
-
- srv_sched_priority_cleaner = priority;
}
}
@@ -16443,6 +16635,7 @@ innobase_fts_find_ranking(
static my_bool innodb_purge_run_now = TRUE;
static my_bool innodb_purge_stop_now = TRUE;
static my_bool innodb_log_checkpoint_now = TRUE;
+static my_bool innodb_buf_flush_list_now = TRUE;
static my_bool innodb_track_redo_log_now = TRUE;
/****************************************************************//**
@@ -16519,19 +16712,42 @@ checkpoint_now_set(
}
/****************************************************************//**
+Force a dirty pages flush now. */
+static
+void
+buf_flush_list_now_set(
+/*===================*/
+ THD* thd /*!< in: thread handle */
+ __attribute__((unused)),
+ struct st_mysql_sys_var* var /*!< in: pointer to system
+ variable */
+ __attribute__((unused)),
+ void* var_ptr /*!< out: where the formal
+ string goes */
+ __attribute__((unused)),
+ const void* save) /*!< in: immediate result from
+ check function */
+{
+ if (*(my_bool*) save) {
+ buf_flush_list(ULINT_MAX, LSN_MAX, NULL);
+ buf_flush_wait_batch_end(NULL, BUF_FLUSH_LIST);
+ }
+}
+
+/****************************************************************//**
Force log tracker to track the log synchronously. */
static
void
track_redo_log_now_set(
/*===================*/
THD* thd /*!< in: thread handle */
- __attribute__((unused)),
+ __attribute__((unused)),
struct st_mysql_sys_var* var /*!< in: pointer to system
variable */
- __attribute__((unused)),
+ __attribute__((unused)),
void* var_ptr /*!< out: where the formal
string goes */
- __attribute__((unused)),
+ __attribute__((unused)),
const void* save) /*!< in: immediate result from
check function */
{
@@ -16541,7 +16757,6 @@ track_redo_log_now_set(
}
}
-
#endif /* UNIV_DEBUG */
/***********************************************************************
@@ -16702,6 +16917,26 @@ buffer_pool_load_abort(
}
}
+/** Update innodb_status_output or innodb_status_output_locks,
+which control InnoDB "status monitor" output to the error log.
+@param[in] thd thread handle
+@param[in] var system variable
+@param[out] var_ptr current value
+@param[in] save to-be-assigned value */
+static
+void
+innodb_status_output_update(
+ THD* thd __attribute__((unused)),
+ struct st_mysql_sys_var* var __attribute__((unused)),
+ void* var_ptr __attribute__((unused)),
+ const void* save __attribute__((unused)))
+{
+ *static_cast<my_bool*>(var_ptr) = *static_cast<const my_bool*>(save);
+ /* The lock timeout monitor thread also takes care of this
+ output. */
+ os_event_set(lock_sys->timeout_event);
+}
+
static SHOW_VAR innodb_status_variables_export[]= {
{"Innodb", (char*) &show_innodb_vars, SHOW_FUNC},
{NullS, NullS, SHOW_LONG}
@@ -16830,11 +17065,17 @@ static MYSQL_SYSVAR_BOOL(log_checkpoint_now, innodb_log_checkpoint_now,
"Force checkpoint now",
NULL, checkpoint_now_set, FALSE);
+static MYSQL_SYSVAR_BOOL(buf_flush_list_now, innodb_buf_flush_list_now,
+ PLUGIN_VAR_OPCMDARG,
+ "Force dirty page flush now",
+ NULL, buf_flush_list_now_set, FALSE);
+
static MYSQL_SYSVAR_BOOL(track_redo_log_now,
innodb_track_redo_log_now,
PLUGIN_VAR_OPCMDARG,
"Force log tracker to catch up with checkpoint now",
NULL, track_redo_log_now_set, FALSE);
+
#endif /* UNIV_DEBUG */
static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size,
@@ -17137,7 +17378,7 @@ static MYSQL_SYSVAR_ENUM(foreground_preflush, srv_foreground_preflush,
static MYSQL_SYSVAR_ULONG(sched_priority_cleaner, srv_sched_priority_cleaner,
PLUGIN_VAR_RQCMDARG,
- "Nice value for the cleaner thread scheduling",
+ "Nice value for the cleaner and LRU manager thread scheduling",
NULL, innodb_sched_priority_cleaner_update, 19, 0, 39, 0);
#endif /* UNIV_LINUX */
@@ -17182,7 +17423,8 @@ static MYSQL_SYSVAR_BOOL(priority_io, srv_io_thread_priority,
static MYSQL_SYSVAR_BOOL(priority_cleaner, srv_cleaner_thread_priority,
PLUGIN_VAR_OPCMDARG,
- "Make buffer pool cleaner thread acquire shared resources with priority",
+ "Make buffer pool cleaner and LRU manager threads acquire shared resources "
+ "with priority",
NULL, NULL, FALSE);
static MYSQL_SYSVAR_BOOL(priority_master, srv_master_thread_priority,
@@ -17356,7 +17598,7 @@ static MYSQL_SYSVAR_ULONG(ft_total_cache_size, fts_max_total_cache_size,
static MYSQL_SYSVAR_ULONG(ft_result_cache_limit, fts_result_cache_limit,
PLUGIN_VAR_RQCMDARG,
"InnoDB Fulltext search query result cache limit in bytes",
- NULL, NULL, 2000000000L, 1000000L, ~0UL, 0);
+ NULL, NULL, 2000000000L, 1000000L, 4294967295UL, 0);
static MYSQL_SYSVAR_ULONG(ft_min_token_size, fts_min_token_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -17494,7 +17736,7 @@ static MYSQL_SYSVAR_ULONG(thread_sleep_delay, srv_thread_sleep_delay,
NULL, NULL,
10000L,
0L,
- ~0UL, 0);
+ 1000000L, 0);
static MYSQL_SYSVAR_STR(data_file_path, innobase_data_file_path,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -17684,6 +17926,15 @@ static MYSQL_SYSVAR_STR(monitor_reset_all, innobase_reset_all_monitor_counter,
innodb_monitor_validate,
innodb_reset_all_monitor_update, NULL);
+static MYSQL_SYSVAR_BOOL(status_output, srv_print_innodb_monitor,
+ PLUGIN_VAR_OPCMDARG, "Enable InnoDB monitor output to the error log.",
+ NULL, innodb_status_output_update, FALSE);
+
+static MYSQL_SYSVAR_BOOL(status_output_locks, srv_print_innodb_lock_monitor,
+ PLUGIN_VAR_OPCMDARG, "Enable InnoDB lock monitor output to the error log."
+ " Requires innodb_status_output=ON.",
+ NULL, innodb_status_output_update, FALSE);
+
static MYSQL_SYSVAR_BOOL(print_all_deadlocks, srv_print_all_deadlocks,
PLUGIN_VAR_OPCMDARG,
"Print all deadlocks to MySQL error log (off by default)",
@@ -17730,8 +17981,23 @@ static MYSQL_SYSVAR_BOOL(trx_purge_view_update_only_debug,
"It is to create artificially the situation the purge view have been updated "
"but the each purges were not done yet.",
NULL, NULL, FALSE);
+
+static MYSQL_SYSVAR_ULONG(fil_make_page_dirty_debug,
+ srv_fil_make_page_dirty_debug, PLUGIN_VAR_OPCMDARG,
+ "Make the first page of the given tablespace dirty.",
+ NULL, innodb_make_page_dirty, 0, 0, UINT_MAX32, 0);
+
+static MYSQL_SYSVAR_ULONG(saved_page_number_debug,
+ srv_saved_page_number_debug, PLUGIN_VAR_OPCMDARG,
+ "An InnoDB page number.",
+ NULL, innodb_save_page_no, 0, 0, UINT_MAX32, 0);
#endif /* UNIV_DEBUG */
+static MYSQL_SYSVAR_UINT(simulate_comp_failures, srv_simulate_comp_failures,
+ PLUGIN_VAR_NOCMDARG,
+ "Simulate compression failures.",
+ NULL, NULL, 0, 0, 99, 0);
+
const char *corrupt_table_action_names[]=
{
"assert", /* 0 */
@@ -17909,6 +18175,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(purge_run_now),
MYSQL_SYSVAR(purge_stop_now),
MYSQL_SYSVAR(log_checkpoint_now),
+ MYSQL_SYSVAR(buf_flush_list_now),
MYSQL_SYSVAR(track_redo_log_now),
#endif /* UNIV_DEBUG */
#ifdef UNIV_LINUX
@@ -17933,6 +18200,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(cleaner_free_list_lwm),
MYSQL_SYSVAR(cleaner_eviction_factor),
#endif /* defined UNIV_DEBUG || defined UNIV_PERF_DEBUG */
+ MYSQL_SYSVAR(status_output),
+ MYSQL_SYSVAR(status_output_locks),
MYSQL_SYSVAR(cleaner_lsn_age_factor),
MYSQL_SYSVAR(foreground_preflush),
MYSQL_SYSVAR(empty_free_list_algorithm),
@@ -17949,11 +18218,14 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(trx_rseg_n_slots_debug),
MYSQL_SYSVAR(limit_optimistic_insert_debug),
MYSQL_SYSVAR(trx_purge_view_update_only_debug),
+ MYSQL_SYSVAR(fil_make_page_dirty_debug),
+ MYSQL_SYSVAR(saved_page_number_debug),
#endif /* UNIV_DEBUG */
MYSQL_SYSVAR(corrupt_table_action),
MYSQL_SYSVAR(fake_changes),
MYSQL_SYSVAR(locking_fake_changes),
MYSQL_SYSVAR(use_stacktrace),
+ MYSQL_SYSVAR(simulate_comp_failures),
NULL
};
@@ -18037,7 +18309,7 @@ innobase_undo_logs_init_default_max()
{
MYSQL_SYSVAR_NAME(undo_logs).max_val
= MYSQL_SYSVAR_NAME(undo_logs).def_val
- = srv_available_undo_logs;
+ = static_cast<unsigned long>(srv_available_undo_logs);
}
#ifdef UNIV_COMPILE_TEST_FUNCS
@@ -18232,7 +18504,7 @@ ib_senderrf(
va_start(args, code);
- myf l;
+ myf l=0;
switch(level) {
case IB_LOG_LEVEL_INFO:
@@ -18294,7 +18566,9 @@ ib_errf(
str[size - 1] = 0x0;
vsnprintf(str, size, format, args);
#elif HAVE_VASPRINTF
- (void) vasprintf(&str, format, args);
+ int ret;
+ ret = vasprintf(&str, format, args);
+ ut_a(ret != -1);
#else
/* Use a fixed length string. */
str = static_cast<char*>(malloc(BUFSIZ));
@@ -18328,7 +18602,9 @@ ib_logf(
str[size - 1] = 0x0;
vsnprintf(str, size, format, args);
#elif HAVE_VASPRINTF
- (void) vasprintf(&str, format, args);
+ int ret;
+ ret = vasprintf(&str, format, args);
+ ut_a(ret != -1);
#else
/* Use a fixed length string. */
str = static_cast<char*>(malloc(BUFSIZ));
@@ -18372,7 +18648,8 @@ innobase_convert_to_filename_charset(
CHARSET_INFO* cs_to = &my_charset_filename;
CHARSET_INFO* cs_from = system_charset_info;
- return(strconvert(cs_from, from, strlen(from), cs_to, to, len, &errors));
+ return(strconvert(cs_from, from, strlen(from), cs_to, to,
+ static_cast<uint>(len), &errors));
}
/**********************************************************************
@@ -18389,7 +18666,8 @@ innobase_convert_to_system_charset(
CHARSET_INFO* cs1 = &my_charset_filename;
CHARSET_INFO* cs2 = system_charset_info;
- return(strconvert(cs1, from, strlen(from), cs2, to, len, errors));
+ return(strconvert(cs1, from, strlen(from), cs2, to,
+ static_cast<uint>(len), errors));
}
diff --git a/storage/xtradb/handler/handler0alter.cc b/storage/xtradb/handler/handler0alter.cc
index 21859cb5447..090bc22b93e 100644
--- a/storage/xtradb/handler/handler0alter.cc
+++ b/storage/xtradb/handler/handler0alter.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2005, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2005, 2014, 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
@@ -46,7 +46,7 @@ Smart ALTER TABLE
#include "srv0mon.h"
#include "fts0priv.h"
#include "pars0pars.h"
-
+#include "row0sel.h"
#include "ha_innodb.h"
/** Operations for creating secondary indexes (no rebuild needed) */
@@ -65,6 +65,7 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_REBUILD
| Alter_inplace_info::ALTER_COLUMN_ORDER
| Alter_inplace_info::DROP_COLUMN
| Alter_inplace_info::ADD_COLUMN
+ | Alter_inplace_info::RECREATE_TABLE
/*
| Alter_inplace_info::ALTER_COLUMN_TYPE
| Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH
@@ -78,6 +79,7 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_DATA
/** Operations for altering a table that InnoDB does not care about */
static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_INPLACE_IGNORE
= Alter_inplace_info::ALTER_COLUMN_DEFAULT
+ | Alter_inplace_info::ALTER_PARTITIONED
| Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT
| Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE
| Alter_inplace_info::ALTER_RENAME;
@@ -240,6 +242,7 @@ ha_innobase::check_if_supported_inplace_alter(
innobase_get_err_msg(ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
} else if (srv_created_new_raw || srv_force_recovery) {
+
ha_alter_info->unsupported_reason =
innobase_get_err_msg(ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
@@ -348,10 +351,14 @@ ha_innobase::check_if_supported_inplace_alter(
Don't do online ALTER if mtype/unsigned_flag are wrong.
*/
- for (ulint i = 0; i < table->s->fields; i++) {
+ for (ulint i = 0, icol= 0; i < table->s->fields; i++) {
const Field* field = table->field[i];
- const dict_col_t* col = dict_table_get_nth_col(prebuilt->table, i);
+ const dict_col_t* col = dict_table_get_nth_col(prebuilt->table, icol);
ulint unsigned_flag;
+ if (!field->stored_in_db)
+ continue;
+ icol++;
+
if (col->mtype != get_innobase_type_from_mysql_type(&unsigned_flag, field)) {
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
@@ -897,7 +904,7 @@ innobase_get_foreign_key_info(
/* Check whether there exist such
index in the the index create clause */
if (!index && !innobase_find_equiv_index(
- column_names, i,
+ column_names, static_cast<uint>(i),
ha_alter_info->key_info_buffer,
ha_alter_info->index_add_buffer,
ha_alter_info->index_add_count)) {
@@ -1004,6 +1011,12 @@ innobase_get_foreign_key_info(
}
referenced_num_col = i;
+ } else {
+ /* Not possible to add a foreign key without a
+ referenced column */
+ mutex_exit(&dict_sys->mutex);
+ my_error(ER_CANNOT_ADD_FOREIGN, MYF(0), tbl_namep);
+ goto err_exit;
}
if (!innobase_init_foreign(
@@ -1123,16 +1136,16 @@ innobase_col_to_mysql(
/* These column types should never be shipped to MySQL. */
ut_ad(0);
- case DATA_FIXBINARY:
case DATA_FLOAT:
case DATA_DOUBLE:
case DATA_DECIMAL:
/* Above are the valid column types for MySQL data. */
ut_ad(flen == len);
/* fall through */
+ case DATA_FIXBINARY:
case DATA_CHAR:
/* We may have flen > len when there is a shorter
- prefix on a CHAR column. */
+ prefix on the CHAR and BINARY column. */
ut_ad(flen >= len);
#else /* UNIV_DEBUG */
default:
@@ -2532,15 +2545,16 @@ innobase_drop_fts_index_table(
/** Get the new column names if any columns were renamed
@param ha_alter_info Data used during in-place alter
@param altered_table MySQL table that is being altered
+@param table MySQL table as it is before the ALTER operation
@param user_table InnoDB table as it is before the ALTER operation
@param heap Memory heap for the allocation
@return array of new column names in rebuilt_table, or NULL if not renamed */
static __attribute__((nonnull, warn_unused_result))
const char**
innobase_get_col_names(
-/*===================*/
Alter_inplace_info* ha_alter_info,
const TABLE* altered_table,
+ const TABLE* table,
const dict_table_t* user_table,
mem_heap_t* heap)
{
@@ -2548,19 +2562,31 @@ innobase_get_col_names(
uint i;
DBUG_ENTER("innobase_get_col_names");
- DBUG_ASSERT(user_table->n_def > altered_table->s->fields);
+ DBUG_ASSERT(user_table->n_def > table->s->fields);
DBUG_ASSERT(ha_alter_info->handler_flags
& Alter_inplace_info::ALTER_COLUMN_NAME);
cols = static_cast<const char**>(
- mem_heap_alloc(heap, user_table->n_def * sizeof *cols));
+ mem_heap_zalloc(heap, user_table->n_def * sizeof *cols));
+
+ i = 0;
+ List_iterator_fast<Create_field> cf_it(
+ ha_alter_info->alter_info->create_list);
+ while (const Create_field* new_field = cf_it++) {
+ DBUG_ASSERT(i < altered_table->s->fields);
+
+ for (uint old_i = 0; table->field[old_i]; old_i++) {
+ if (new_field->field == table->field[old_i]) {
+ cols[old_i] = new_field->field_name;
+ break;
+ }
+ }
- for (i = 0; i < altered_table->s->fields; i++) {
- const Field* field = altered_table->field[i];
- cols[i] = field->field_name;
+ i++;
}
/* Copy the internal column names. */
+ i = table->s->fields;
cols[i] = dict_table_get_col_name(user_table, i);
while (++i < user_table->n_def) {
@@ -2776,7 +2802,7 @@ prepare_inplace_alter_table_dict(
/* The initial space id 0 may be overridden later. */
ctx->new_table = dict_mem_table_create(
- new_table_name, 0, n_cols, flags, flags2);
+ new_table_name, 0, n_cols, flags, flags2, false);
/* The rebuilt indexed_table will use the renamed
column names. */
ctx->col_names = NULL;
@@ -3141,6 +3167,9 @@ error_handling:
case DB_DUPLICATE_KEY:
my_error(ER_DUP_KEY, MYF(0), "SYS_INDEXES");
break;
+ case DB_OUT_OF_FILE_SPACE:
+ my_error_innodb(error, table_name, user_table->flags);
+ break;
default:
my_error_innodb(error, table_name, user_table->flags);
}
@@ -3346,6 +3375,9 @@ ha_innobase::prepare_inplace_alter_table(
ulint fts_doc_col_no = ULINT_UNDEFINED;
bool add_fts_doc_id = false;
bool add_fts_doc_id_idx = false;
+#ifdef _WIN32
+ bool add_fts_idx = false;
+#endif /* _WIN32 */
DBUG_ENTER("prepare_inplace_alter_table");
DBUG_ASSERT(!ha_alter_info->handler_ctx);
@@ -3494,6 +3526,9 @@ check_if_ok_to_rename:
& ~(HA_FULLTEXT
| HA_PACK_KEY
| HA_BINARY_PACK_KEY)));
+#ifdef _WIN32
+ add_fts_idx = true;
+#endif /* _WIN32 */
continue;
}
@@ -3504,6 +3539,20 @@ check_if_ok_to_rename:
}
}
+#ifdef _WIN32
+ /* We won't be allowed to add fts index to a table with
+ fts indexes already but without AUX_HEX_NAME set.
+ This means the aux tables of the table failed to
+ rename to hex format but new created aux tables
+ shall be in hex format, which is contradictory.
+ It's only for Windows. */
+ if (!DICT_TF2_FLAG_IS_SET(indexed_table, DICT_TF2_FTS_AUX_HEX_NAME)
+ && indexed_table->fts != NULL && add_fts_idx) {
+ my_error(ER_INNODB_FT_AUX_NOT_HEX_ID, MYF(0));
+ goto err_exit_no_heap;
+ }
+#endif /* _WIN32 */
+
/* Check existing index definitions for too-long column
prefixes as well, in case max_col_len shrunk. */
for (const dict_index_t* index
@@ -3537,8 +3586,8 @@ check_if_ok_to_rename:
if (ha_alter_info->handler_flags
& Alter_inplace_info::ALTER_COLUMN_NAME) {
col_names = innobase_get_col_names(
- ha_alter_info, altered_table, indexed_table,
- heap);
+ ha_alter_info, altered_table, table,
+ indexed_table, heap);
} else {
col_names = NULL;
}
@@ -4608,16 +4657,39 @@ commit_get_autoinc(
& Alter_inplace_info::CHANGE_CREATE_OPTION)
&& (ha_alter_info->create_info->used_fields
& HA_CREATE_USED_AUTO)) {
- /* An AUTO_INCREMENT value was supplied, but the table
- was not rebuilt. Get the user-supplied value or the
- last value from the sequence. */
- ut_ad(old_table->found_next_number_field);
+ /* An AUTO_INCREMENT value was supplied, but the table was not
+ rebuilt. Get the user-supplied value or the last value from the
+ sequence. */
+ ib_uint64_t max_value_table;
+ dberr_t err;
+
+ Field* autoinc_field =
+ old_table->found_next_number_field;
+
+ dict_index_t* index = dict_table_get_index_on_first_col(
+ ctx->old_table, autoinc_field->field_index);
max_autoinc = ha_alter_info->create_info->auto_increment_value;
dict_table_autoinc_lock(ctx->old_table);
- if (max_autoinc < ctx->old_table->autoinc) {
- max_autoinc = ctx->old_table->autoinc;
+
+ err = row_search_max_autoinc(
+ index, autoinc_field->field_name, &max_value_table);
+
+ if (err != DB_SUCCESS) {
+ ut_ad(0);
+ max_autoinc = 0;
+ } else if (max_autoinc <= max_value_table) {
+ ulonglong col_max_value;
+ ulonglong offset;
+
+ col_max_value = innobase_get_int_col_max_value(
+ old_table->found_next_number_field);
+
+ offset = ctx->prebuilt->autoinc_offset;
+ max_autoinc = innobase_next_autoinc(
+ max_value_table, 1, 1, offset,
+ col_max_value);
}
dict_table_autoinc_unlock(ctx->old_table);
} else {
@@ -5339,6 +5411,7 @@ ha_innobase::commit_inplace_alter_table(
if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) {
DBUG_ASSERT(!ctx0);
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
+ ha_alter_info->group_commit_ctx = NULL;
DBUG_RETURN(false);
}
@@ -5347,12 +5420,17 @@ ha_innobase::commit_inplace_alter_table(
inplace_alter_handler_ctx** ctx_array;
inplace_alter_handler_ctx* ctx_single[2];
+ if (ha_alter_info->group_commit_ctx) {
+ ctx_array = ha_alter_info->group_commit_ctx;
+ } else {
ctx_single[0] = ctx0;
ctx_single[1] = NULL;
ctx_array = ctx_single;
+ }
DBUG_ASSERT(ctx0 == ctx_array[0]);
ut_ad(prebuilt->table == ctx0->old_table);
+ ha_alter_info->group_commit_ctx = NULL;
/* Free the ctx->trx of other partitions, if any. We will only
use the ctx0->trx here. Others may have been allocated in
diff --git a/storage/xtradb/handler/i_s.cc b/storage/xtradb/handler/i_s.cc
index 5603f8cfbe4..4a66065788f 100644
--- a/storage/xtradb/handler/i_s.cc
+++ b/storage/xtradb/handler/i_s.cc
@@ -283,7 +283,7 @@ field_store_string(
if (str != NULL) {
- ret = field->store(str, strlen(str),
+ ret = field->store(str, static_cast<uint>(strlen(str)),
system_charset_info);
field->set_notnull();
} else {
@@ -320,11 +320,13 @@ field_store_index_name(
char buf[NAME_LEN + 1];
buf[0] = '?';
memcpy(buf + 1, index_name + 1, strlen(index_name));
- ret = field->store(buf, strlen(buf),
- system_charset_info);
+ ret = field->store(
+ buf, static_cast<uint>(strlen(buf)),
+ system_charset_info);
} else {
- ret = field->store(index_name, strlen(index_name),
- system_charset_info);
+ ret = field->store(
+ index_name, static_cast<uint>(strlen(index_name)),
+ system_charset_info);
}
field->set_notnull();
@@ -347,7 +349,7 @@ field_store_ulint(
if (n != ULINT_UNDEFINED) {
- ret = field->store(n);
+ ret = field->store(static_cast<double>(n));
field->set_notnull();
} else {
@@ -653,14 +655,15 @@ fill_innodb_trx_from_cache(
/* trx_mysql_thread_id */
OK(fields[IDX_TRX_MYSQL_THREAD_ID]->store(
- row->trx_mysql_thread_id));
+ static_cast<double>(row->trx_mysql_thread_id)));
/* trx_query */
if (row->trx_query) {
/* store will do appropriate character set
conversion check */
fields[IDX_TRX_QUERY]->store(
- row->trx_query, strlen(row->trx_query),
+ row->trx_query,
+ static_cast<uint>(strlen(row->trx_query)),
row->trx_query_cs);
fields[IDX_TRX_QUERY]->set_notnull();
} else {
@@ -705,11 +708,11 @@ fill_innodb_trx_from_cache(
/* trx_unique_checks */
OK(fields[IDX_TRX_UNIQUE_CHECKS]->store(
- row->trx_unique_checks));
+ static_cast<double>(row->trx_unique_checks)));
/* trx_foreign_key_checks */
OK(fields[IDX_TRX_FOREIGN_KEY_CHECKS]->store(
- row->trx_foreign_key_checks));
+ static_cast<double>(row->trx_foreign_key_checks)));
/* trx_last_foreign_key_error */
OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR],
@@ -717,7 +720,7 @@ fill_innodb_trx_from_cache(
/* trx_adaptive_hash_latched */
OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store(
- row->trx_has_search_latch));
+ static_cast<double>(row->trx_has_search_latch)));
/* trx_adaptive_hash_timeout */
OK(fields[IDX_TRX_ADAPTIVE_HASH_TIMEOUT]->store(
@@ -725,11 +728,11 @@ fill_innodb_trx_from_cache(
/* trx_is_read_only*/
OK(fields[IDX_TRX_READ_ONLY]->store(
- (long) row->trx_is_read_only, true));
+ (longlong) row->trx_is_read_only, true));
/* trx_is_autocommit_non_locking */
OK(fields[IDX_TRX_AUTOCOMMIT_NON_LOCKING]->store(
- (long) row->trx_is_autocommit_non_locking,
+ (longlong) row->trx_is_autocommit_non_locking,
true));
OK(schema_table_store_record(thd, table));
@@ -967,8 +970,9 @@ fill_innodb_locks_from_cache(
row->lock_table,
strlen(row->lock_table),
thd, TRUE);
- OK(fields[IDX_LOCK_TABLE]->store(buf, bufend - buf,
- system_charset_info));
+ OK(fields[IDX_LOCK_TABLE]->store(
+ buf, static_cast<uint>(bufend - buf),
+ system_charset_info));
/* lock_index */
if (row->lock_index != NULL) {
@@ -1448,13 +1452,16 @@ i_s_cmp_fill_low(
clear it. We could introduce mutex protection, but it
could cause a measureable performance hit in
page0zip.cc. */
- table->field[1]->store(zip_stat->compressed);
- table->field[2]->store(zip_stat->compressed_ok);
+ table->field[1]->store(
+ static_cast<double>(zip_stat->compressed));
+ table->field[2]->store(
+ static_cast<double>(zip_stat->compressed_ok));
table->field[3]->store(
- (ulong) (zip_stat->compressed_usec / 1000000));
- table->field[4]->store(zip_stat->decompressed);
+ static_cast<double>(zip_stat->compressed_usec / 1000000));
+ table->field[4]->store(
+ static_cast<double>(zip_stat->decompressed));
table->field[5]->store(
- (ulong) (zip_stat->decompressed_usec / 1000000));
+ static_cast<double>(zip_stat->decompressed_usec / 1000000));
if (reset) {
memset(zip_stat, 0, sizeof *zip_stat);
@@ -1777,19 +1784,19 @@ i_s_cmp_per_index_fill_low(
}
fields[IDX_COMPRESS_OPS]->store(
- iter->second.compressed);
+ static_cast<double>(iter->second.compressed));
fields[IDX_COMPRESS_OPS_OK]->store(
- iter->second.compressed_ok);
+ static_cast<double>(iter->second.compressed_ok));
fields[IDX_COMPRESS_TIME]->store(
- (long) (iter->second.compressed_usec / 1000000));
+ static_cast<double>(iter->second.compressed_usec / 1000000));
fields[IDX_UNCOMPRESS_OPS]->store(
- iter->second.decompressed);
+ static_cast<double>(iter->second.decompressed));
fields[IDX_UNCOMPRESS_TIME]->store(
- (long) (iter->second.decompressed_usec / 1000000));
+ static_cast<double>(iter->second.decompressed_usec / 1000000));
if (schema_table_store_record(thd, table)) {
status = 1;
@@ -2072,15 +2079,17 @@ i_s_cmpmem_fill_low(
buddy_stat = &buf_pool->buddy_stat[x];
table->field[0]->store(BUF_BUDDY_LOW << x);
- table->field[1]->store(i);
- table->field[2]->store(buddy_stat->used);
- table->field[3]->store(UNIV_LIKELY(x < BUF_BUDDY_SIZES)
+ table->field[1]->store(static_cast<double>(i));
+ table->field[2]->store(static_cast<double>(
+ buddy_stat->used));
+ table->field[3]->store(static_cast<double>(
+ (x < BUF_BUDDY_SIZES)
? UT_LIST_GET_LEN(buf_pool->zip_free[x])
- : 0);
+ : 0));
table->field[4]->store(
(longlong) buddy_stat->relocated, true);
table->field[5]->store(
- (ulong) (buddy_stat->relocated_usec / 1000000));
+ static_cast<double>(buddy_stat->relocated_usec / 1000000));
if (reset) {
/* This is protected by
@@ -2627,8 +2636,8 @@ i_s_metrics_fill(
if (time_diff) {
OK(fields[METRIC_AVG_VALUE_RESET]->store(
- (double )MONITOR_VALUE(count)
- / time_diff));
+ static_cast<double>(
+ MONITOR_VALUE(count) / time_diff)));
fields[METRIC_AVG_VALUE_RESET]->set_notnull();
} else {
fields[METRIC_AVG_VALUE_RESET]->set_null();
@@ -3253,9 +3262,11 @@ i_s_fts_index_cache_fill_one_index(
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,
+ static_cast<uint32>(conv_str.f_len),
+ system_charset_info,
reinterpret_cast<char*>(word->text.f_str),
- word->text.f_len, index_charset, &dummy_errors);
+ static_cast<uint32>(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);
@@ -3296,13 +3307,13 @@ i_s_fts_index_cache_fill_one_index(
true));
OK(fields[I_S_FTS_DOC_COUNT]->store(
- node->doc_count));
+ static_cast<double>(node->doc_count)));
OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
(longlong) doc_id, true));
OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
- pos));
+ static_cast<double>(pos)));
OK(schema_table_store_record(
thd, table));
@@ -3604,9 +3615,11 @@ i_s_fts_index_table_fill_one_fetch(
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,
+ static_cast<uint32>(conv_str->f_len),
+ system_charset_info,
reinterpret_cast<char*>(word->text.f_str),
- word->text.f_len, index_charset, &dummy_errors);
+ static_cast<uint32>(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);
@@ -3648,13 +3661,13 @@ i_s_fts_index_table_fill_one_fetch(
true));
OK(fields[I_S_FTS_DOC_COUNT]->store(
- node->doc_count));
+ static_cast<double>(node->doc_count)));
OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
(longlong) doc_id, true));
OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
- pos));
+ static_cast<double>(pos)));
OK(schema_table_store_record(
thd, table));
@@ -4376,31 +4389,41 @@ i_s_innodb_stats_fill(
fields = table->field;
- OK(fields[IDX_BUF_STATS_POOL_ID]->store(info->pool_unique_id));
+ OK(fields[IDX_BUF_STATS_POOL_ID]->store(
+ static_cast<double>(info->pool_unique_id)));
- OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(info->pool_size));
+ OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(
+ static_cast<double>(info->pool_size)));
- OK(fields[IDX_BUF_STATS_LRU_LEN]->store(info->lru_len));
+ OK(fields[IDX_BUF_STATS_LRU_LEN]->store(
+ static_cast<double>(info->lru_len)));
- OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(info->old_lru_len));
+ OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(
+ static_cast<double>(info->old_lru_len)));
- OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(info->free_list_len));
+ OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(
+ static_cast<double>(info->free_list_len)));
OK(fields[IDX_BUF_STATS_FLUSH_LIST_LEN]->store(
- info->flush_list_len));
+ static_cast<double>(info->flush_list_len)));
- OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(info->n_pend_unzip));
+ OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(
+ static_cast<double>(info->n_pend_unzip)));
- OK(fields[IDX_BUF_STATS_PENDING_READ]->store(info->n_pend_reads));
+ OK(fields[IDX_BUF_STATS_PENDING_READ]->store(
+ static_cast<double>(info->n_pend_reads)));
- OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(info->n_pending_flush_lru));
+ OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(
+ static_cast<double>(info->n_pending_flush_lru)));
- OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(info->n_pending_flush_list));
+ OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(
+ static_cast<double>(info->n_pending_flush_list)));
- OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(info->n_pages_made_young));
+ OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(
+ static_cast<double>(info->n_pages_made_young)));
OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG]->store(
- info->n_pages_not_made_young));
+ static_cast<double>(info->n_pages_not_made_young)));
OK(fields[IDX_BUF_STATS_PAGE_YOUNG_RATE]->store(
info->page_made_young_rate));
@@ -4408,42 +4431,53 @@ i_s_innodb_stats_fill(
OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE]->store(
info->page_not_made_young_rate));
- OK(fields[IDX_BUF_STATS_PAGE_READ]->store(info->n_pages_read));
+ OK(fields[IDX_BUF_STATS_PAGE_READ]->store(
+ static_cast<double>(info->n_pages_read)));
- OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(info->n_pages_created));
+ OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(
+ static_cast<double>(info->n_pages_created)));
- OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(info->n_pages_written));
+ OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(
+ static_cast<double>(info->n_pages_written)));
- OK(fields[IDX_BUF_STATS_GET]->store(info->n_page_gets));
+ OK(fields[IDX_BUF_STATS_GET]->store(
+ static_cast<double>(info->n_page_gets)));
- OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(info->pages_read_rate));
+ OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(
+ info->pages_read_rate));
- OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(info->pages_created_rate));
+ OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(
+ info->pages_created_rate));
- OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(info->pages_written_rate));
+ OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(
+ info->pages_written_rate));
if (info->n_page_get_delta) {
OK(fields[IDX_BUF_STATS_HIT_RATE]->store(
- 1000 - (1000 * info->page_read_delta
- / info->n_page_get_delta)));
+ static_cast<double>(
+ 1000 - (1000 * info->page_read_delta
+ / info->n_page_get_delta))));
OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(
- 1000 * info->young_making_delta
- / info->n_page_get_delta));
+ static_cast<double>(
+ 1000 * info->young_making_delta
+ / info->n_page_get_delta)));
OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(
- 1000 * info->not_young_making_delta
- / info->n_page_get_delta));
+ static_cast<double>(
+ 1000 * info->not_young_making_delta
+ / info->n_page_get_delta)));
} else {
OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0));
OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0));
OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0));
}
- OK(fields[IDX_BUF_STATS_READ_AHREAD]->store(info->n_ra_pages_read));
+ OK(fields[IDX_BUF_STATS_READ_AHREAD]->store(
+ static_cast<double>(info->n_ra_pages_read)));
OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICTED]->store(
- info->n_ra_pages_evicted));
+ static_cast<double>(info->n_ra_pages_evicted)));
OK(fields[IDX_BUF_STATS_READ_AHEAD_RATE]->store(
info->pages_readahead_rate));
@@ -4451,13 +4485,17 @@ i_s_innodb_stats_fill(
OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICT_RATE]->store(
info->pages_evicted_rate));
- OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(info->io_sum));
+ OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(
+ static_cast<double>(info->io_sum)));
- OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(info->io_cur));
+ OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(
+ static_cast<double>(info->io_cur)));
- OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(info->unzip_sum));
+ OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(
+ static_cast<double>(info->unzip_sum)));
- OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store( info->unzip_cur));
+ OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store(
+ static_cast<double>(info->unzip_cur)));
DBUG_RETURN(schema_table_store_record(thd, table));
}
@@ -4800,13 +4838,17 @@ i_s_innodb_buffer_page_fill(
state_str = NULL;
- OK(fields[IDX_BUFFER_POOL_ID]->store(page_info->pool_id));
+ OK(fields[IDX_BUFFER_POOL_ID]->store(
+ static_cast<double>(page_info->pool_id)));
- OK(fields[IDX_BUFFER_BLOCK_ID]->store(page_info->block_id));
+ OK(fields[IDX_BUFFER_BLOCK_ID]->store(
+ static_cast<double>(page_info->block_id)));
- OK(fields[IDX_BUFFER_PAGE_SPACE]->store(page_info->space_id));
+ OK(fields[IDX_BUFFER_PAGE_SPACE]->store(
+ static_cast<double>(page_info->space_id)));
- OK(fields[IDX_BUFFER_PAGE_NUM]->store(page_info->page_num));
+ OK(fields[IDX_BUFFER_PAGE_NUM]->store(
+ static_cast<double>(page_info->page_num)));
OK(field_store_string(
fields[IDX_BUFFER_PAGE_TYPE],
@@ -4858,7 +4900,7 @@ i_s_innodb_buffer_page_fill(
OK(fields[IDX_BUFFER_PAGE_TABLE_NAME]->store(
table_name,
- table_name_end - table_name,
+ static_cast<uint>(table_name_end - table_name),
system_charset_info));
fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_notnull();
@@ -5512,23 +5554,27 @@ i_s_innodb_buf_page_lru_fill(
page_info = info_array + i;
- OK(fields[IDX_BUF_LRU_POOL_ID]->store(page_info->pool_id));
+ OK(fields[IDX_BUF_LRU_POOL_ID]->store(
+ static_cast<double>(page_info->pool_id)));
- OK(fields[IDX_BUF_LRU_POS]->store(page_info->block_id));
+ OK(fields[IDX_BUF_LRU_POS]->store(
+ static_cast<double>(page_info->block_id)));
- OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(page_info->space_id));
+ OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(
+ static_cast<double>(page_info->space_id)));
- OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(page_info->page_num));
+ OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(
+ static_cast<double>(page_info->page_num)));
OK(field_store_string(
fields[IDX_BUF_LRU_PAGE_TYPE],
i_s_page_type[page_info->page_type].type_str));
OK(fields[IDX_BUF_LRU_PAGE_FLUSH_TYPE]->store(
- page_info->flush_type));
+ static_cast<double>(page_info->flush_type)));
OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store(
- page_info->fix_count));
+ static_cast<double>(page_info->fix_count)));
if (page_info->hashed) {
OK(field_store_string(
@@ -5570,7 +5616,7 @@ i_s_innodb_buf_page_lru_fill(
OK(fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->store(
table_name,
- table_name_end - table_name,
+ static_cast<uint>(table_name_end - table_name),
system_charset_info));
fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_notnull();
@@ -5972,7 +6018,8 @@ i_s_dict_fill_sys_tables(
OK(field_store_string(fields[SYS_TABLES_ROW_FORMAT], row_format));
- OK(fields[SYS_TABLES_ZIP_PAGE_SIZE]->store(zip_size));
+ OK(fields[SYS_TABLES_ZIP_PAGE_SIZE]->store(
+ static_cast<double>(zip_size)));
OK(schema_table_store_record(thd, table_to_fill));
@@ -6240,13 +6287,13 @@ i_s_dict_fill_sys_tablestats(
TRUE));
OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(
- table->stat_clustered_index_size));
+ static_cast<double>(table->stat_clustered_index_size)));
OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(
- table->stat_sum_of_other_index_sizes));
+ static_cast<double>(table->stat_sum_of_other_index_sizes)));
OK(fields[SYS_TABLESTATS_MODIFIED]->store(
- (ulint) table->stat_modified_counter));
+ static_cast<double>(table->stat_modified_counter)));
} else {
OK(field_store_string(fields[SYS_TABLESTATS_INIT],
"Uninitialized"));
@@ -6265,7 +6312,7 @@ i_s_dict_fill_sys_tablestats(
OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, TRUE));
OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(
- table->n_ref_count));
+ static_cast<double>(table->n_ref_count)));
OK(schema_table_store_record(thd, table_to_fill));
@@ -6951,7 +6998,7 @@ i_s_dict_fill_sys_fields(
OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
- OK(fields[SYS_FIELD_POS]->store(pos));
+ OK(fields[SYS_FIELD_POS]->store(static_cast<double>(pos)));
OK(schema_table_store_record(thd, table_to_fill));
@@ -7395,7 +7442,7 @@ i_s_dict_fill_sys_foreign_cols(
OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name));
- OK(fields[SYS_FOREIGN_COL_POS]->store(pos));
+ OK(fields[SYS_FOREIGN_COL_POS]->store(static_cast<double>(pos)));
OK(schema_table_store_record(thd, table_to_fill));
@@ -7644,11 +7691,13 @@ i_s_dict_fill_sys_tablespaces(
fields = table_to_fill->field;
- OK(fields[SYS_TABLESPACES_SPACE]->store(space));
+ OK(fields[SYS_TABLESPACES_SPACE]->store(
+ static_cast<double>(space)));
OK(field_store_string(fields[SYS_TABLESPACES_NAME], name));
- OK(fields[SYS_TABLESPACES_FLAGS]->store(flags));
+ OK(fields[SYS_TABLESPACES_FLAGS]->store(
+ static_cast<double>(flags)));
OK(field_store_string(fields[SYS_TABLESPACES_FILE_FORMAT],
file_format));
@@ -7656,9 +7705,11 @@ i_s_dict_fill_sys_tablespaces(
OK(field_store_string(fields[SYS_TABLESPACES_ROW_FORMAT],
row_format));
- OK(fields[SYS_TABLESPACES_PAGE_SIZE]->store(page_size));
+ OK(fields[SYS_TABLESPACES_PAGE_SIZE]->store(
+ static_cast<double>(page_size)));
- OK(fields[SYS_TABLESPACES_ZIP_PAGE_SIZE]->store(zip_size));
+ OK(fields[SYS_TABLESPACES_ZIP_PAGE_SIZE]->store(
+ static_cast<double>(zip_size)));
OK(schema_table_store_record(thd, table_to_fill));
@@ -8154,38 +8205,47 @@ limit_lsn_range_from_condition(
if (left->type() == Item::FIELD_ITEM
&& right->type() == Item::INT_ITEM) {
- /* The case of start_lsn|end_lsn <|<= const, i.e. the
- upper bound. */
+ /* The case of start_lsn|end_lsn <|<= const
+ "end_lsn <=? const" gives a valid upper bound.
+ "start_lsn <=? const" is not a valid upper bound.
+ */
- tmp_result = right->val_int();
- if (((func_type == Item_func::LE_FUNC)
- || (func_type == Item_func::GE_FUNC))
- && (tmp_result != IB_UINT64_MAX)) {
+ if (is_end_lsn) {
+ tmp_result = right->val_int();
+ if (((func_type == Item_func::LE_FUNC)
+ || (func_type == Item_func::GE_FUNC))
+ && (tmp_result != IB_UINT64_MAX)) {
- tmp_result++;
- }
- if (tmp_result < *end_lsn) {
- *end_lsn = tmp_result;
+ tmp_result++;
+ }
+ if (tmp_result < *end_lsn) {
+ *end_lsn = tmp_result;
+ }
}
} else if (left->type() == Item::INT_ITEM
&& right->type() == Item::FIELD_ITEM) {
- /* The case of const <|<= start_lsn|end_lsn, i.e. the
- lower bound */
+ /* The case of const <|<= start_lsn|end_lsn
+ turning it around: start_lsn|end_lsn >|>= const
+ "start_lsn >=? const " is a valid loer bound.
+ "end_lsn >=? const" is not a valid lower bound.
+ */
- tmp_result = left->val_int();
- if (is_end_lsn && tmp_result != 0) {
- tmp_result--;
- }
- if (((func_type == Item_func::LT_FUNC)
- || (func_type == Item_func::GT_FUNC))
- && (tmp_result != IB_UINT64_MAX)) {
+ if (!is_end_lsn) {
+ tmp_result = left->val_int();
+ if (is_end_lsn && tmp_result != 0) {
+ tmp_result--;
+ }
+ if (((func_type == Item_func::LT_FUNC)
+ || (func_type == Item_func::GT_FUNC))
+ && (tmp_result != IB_UINT64_MAX)) {
- tmp_result++;
- }
- if (tmp_result > *start_lsn) {
- *start_lsn = tmp_result;
+ tmp_result++;
+ }
+ if (tmp_result > *start_lsn) {
+ *start_lsn = tmp_result;
+ }
}
}
diff --git a/storage/xtradb/ibuf/ibuf0ibuf.cc b/storage/xtradb/ibuf/ibuf0ibuf.cc
index 2964fa99c8a..3969d284a97 100644
--- a/storage/xtradb/ibuf/ibuf0ibuf.cc
+++ b/storage/xtradb/ibuf/ibuf0ibuf.cc
@@ -611,7 +611,8 @@ ibuf_init_at_db_start(void)
heap = mem_heap_create(450);
/* Use old-style record format for the insert buffer. */
- table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0, 0);
+ table = dict_mem_table_create(IBUF_TABLE_NAME, IBUF_SPACE_ID, 1, 0, 0,
+ false);
dict_mem_table_add_col(table, heap, "DUMMY_COLUMN", DATA_BINARY, 0, 0);
@@ -1572,7 +1573,7 @@ ibuf_dummy_index_create(
table = dict_mem_table_create("IBUF_DUMMY",
DICT_HDR_SPACE, n,
- comp ? DICT_TF_COMPACT : 0, 0);
+ comp ? DICT_TF_COMPACT : 0, 0, true);
index = dict_mem_index_create("IBUF_DUMMY", "IBUF_DUMMY",
DICT_HDR_SPACE, 0, n);
@@ -2962,7 +2963,8 @@ ibuf_get_volume_buffered_hash(
fold = ut_fold_binary(data, len);
hash += (fold / (CHAR_BIT * sizeof *hash)) % size;
- bitmask = 1 << (fold % (CHAR_BIT * sizeof *hash));
+ bitmask = static_cast<ulint>(
+ 1 << (fold % (CHAR_BIT * sizeof(*hash))));
if (*hash & bitmask) {
@@ -3977,7 +3979,7 @@ skip_watch:
/********************************************************************//**
During merge, inserts to an index page a secondary index entry extracted
-from the insert buffer.
+from the insert buffer.
@return newly inserted record */
static __attribute__((nonnull))
rec_t*
diff --git a/storage/xtradb/include/api0api.h b/storage/xtradb/include/api0api.h
index c294e3f34d5..d77d691becc 100644
--- a/storage/xtradb/include/api0api.h
+++ b/storage/xtradb/include/api0api.h
@@ -1257,6 +1257,16 @@ ib_cfg_get_cfg();
/*============*/
/*****************************************************************//**
+Increase/decrease the memcached sync count of table to sync memcached
+DML with SQL DDLs.
+@return DB_SUCCESS or error number */
+ib_err_t
+ib_cursor_set_memcached_sync(
+/*=========================*/
+ ib_crsr_t ib_crsr, /*!< in: cursor */
+ ib_bool_t flag); /*!< in: true for increasing */
+
+/*****************************************************************//**
Check whether the table name conforms to our requirements. Currently
we only do a simple check for the presence of a '/'.
@return DB_SUCCESS or err code */
diff --git a/storage/xtradb/include/btr0pcur.h b/storage/xtradb/include/btr0pcur.h
index fc008cdd185..cfbaacf4de3 100644
--- a/storage/xtradb/include/btr0pcur.h
+++ b/storage/xtradb/include/btr0pcur.h
@@ -459,6 +459,13 @@ void
btr_pcur_move_to_prev_on_page(
/*==========================*/
btr_pcur_t* cursor);/*!< in/out: persistent cursor */
+/*********************************************************//**
+Moves the persistent cursor to the infimum record on the same page. */
+UNIV_INLINE
+void
+btr_pcur_move_before_first_on_page(
+/*===============================*/
+ btr_pcur_t* cursor); /*!< in/out: persistent cursor */
/** Position state of persistent B-tree cursor. */
enum pcur_pos_t {
diff --git a/storage/xtradb/include/btr0pcur.ic b/storage/xtradb/include/btr0pcur.ic
index 29f2fc722a2..7e355d3709d 100644
--- a/storage/xtradb/include/btr0pcur.ic
+++ b/storage/xtradb/include/btr0pcur.ic
@@ -588,3 +588,19 @@ btr_pcur_close(
cursor->trx_if_known = NULL;
}
+
+/*********************************************************//**
+Moves the persistent cursor to the infimum record on the same page. */
+UNIV_INLINE
+void
+btr_pcur_move_before_first_on_page(
+/*===============================*/
+ btr_pcur_t* cursor) /*!< in/out: persistent cursor */
+{
+ ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
+
+ page_cur_set_before_first(btr_pcur_get_block(cursor),
+ btr_pcur_get_page_cur(cursor));
+
+ cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
+}
diff --git a/storage/xtradb/include/buf0buf.h b/storage/xtradb/include/buf0buf.h
index ba2f413429c..39b06b69924 100644
--- a/storage/xtradb/include/buf0buf.h
+++ b/storage/xtradb/include/buf0buf.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, 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
@@ -596,6 +596,23 @@ buf_block_buf_fix_inc_func(
# endif /* UNIV_SYNC_DEBUG */
buf_block_t* block) /*!< in/out: block to bufferfix */
__attribute__((nonnull));
+
+/*******************************************************************//**
+Increments the bufferfix count. */
+UNIV_INLINE
+void
+buf_block_fix(
+/*===========*/
+ buf_block_t* block); /*!< in/out: block to bufferfix */
+
+/*******************************************************************//**
+Increments the bufferfix count. */
+UNIV_INLINE
+void
+buf_block_unfix(
+/*===========*/
+ buf_block_t* block); /*!< in/out: block to bufferfix */
+
# ifdef UNIV_SYNC_DEBUG
/** Increments the bufferfix count.
@param b in/out: block to bufferfix
@@ -625,6 +642,15 @@ buf_page_is_corrupted(
ulint zip_size) /*!< in: size of compressed page;
0 for uncompressed pages */
__attribute__((nonnull, warn_unused_result));
+/********************************************************************//**
+Checks if a page is all zeroes.
+@return TRUE if the page is all zeroes */
+bool
+buf_page_is_zeroes(
+/*===============*/
+ const byte* read_buf, /*!< in: a database page */
+ const ulint zip_size); /*!< in: size of compressed page;
+ 0 for uncompressed pages */
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
Gets the space id, page offset, and byte offset within page of a
@@ -1437,25 +1463,39 @@ struct buf_page_t{
machine word. */
/* @{ */
- unsigned space:32; /*!< tablespace id. */
- unsigned offset:32; /*!< page number. */
-
+ ib_uint32_t space; /*!< tablespace id. */
+ ib_uint32_t offset; /*!< page number. */
+ /** count of how manyfold this block is currently bufferfixed */
+#ifdef PAGE_ATOMIC_REF_COUNT
+ ib_uint32_t buf_fix_count;
+
+ /** type of pending I/O operation; Transitions from BUF_IO_NONE to
+ BUF_IO_WRITE and back are protected by the buf_page_get_mutex() mutex
+ and the corresponding flush state mutex. The flush state mutex
+ protection for io_fix and flush_type is not strictly required, but it
+ ensures consistent buffer pool instance state snapshots in
+ buf_pool_validate_instance(). @see enum buf_io_fix */
+ byte io_fix;
+
+ byte state;
+#else
+ unsigned buf_fix_count:19;
+
+ /** type of pending I/O operation; also protected by
+ buf_pool->mutex for writes only @see enum buf_io_fix */
+ unsigned io_fix:2;
+
+ /*!< state of the control block.
+ State transitions from BUF_BLOCK_READY_FOR_USE to BUF_BLOCK_MEMORY
+ need not be protected by buf_page_get_mutex(). @see enum buf_page_state.
+ State changes that are relevant to page_hash are additionally protected
+ by the appropriate page_hash mutex i.e.: if a page is in page_hash or
+ is being added to/removed from page_hash then the corresponding changes
+ must also be protected by page_hash mutex. */
unsigned state:BUF_PAGE_STATE_BITS;
- /*!< state of the control block.
- State transitions from
- BUF_BLOCK_READY_FOR_USE to
- BUF_BLOCK_MEMORY need not be
- protected by buf_page_get_mutex().
- @see enum buf_page_state.
- State changes that are relevant
- to page_hash are additionally
- protected by the appropriate
- page_hash mutex i.e.: if a page
- is in page_hash or is being
- added to/removed from page_hash
- then the corresponding changes
- must also be protected by
- page_hash mutex. */
+
+#endif /* PAGE_ATOMIC_REF_COUNT */
+
#ifndef UNIV_HOTBACKUP
unsigned flush_type:2; /*!< if this block is currently being
flushed to disk, this tells the
@@ -1464,18 +1504,6 @@ struct buf_page_t{
mutex and the corresponding flush state
mutex.
@see buf_flush_t */
- unsigned io_fix:2; /*!< type of pending I/O operation.
- Transitions from BUF_IO_NONE to
- BUF_IO_WRITE and back are protected by
- the buf_page_get_mutex() mutex and the
- corresponding flush state mutex. The
- flush state mutex protection for io_fix
- and flush_type is not strictly
- required, but it ensures consistent
- buffer pool instance state snapshots in
- buf_pool_validate_instance(). */
- unsigned buf_fix_count:19;/*!< count of how manyfold this block
- is currently bufferfixed */
unsigned buf_pool_index:6;/*!< index number of the buffer pool
that this block belongs to */
# if MAX_BUFFER_POOLS > 64
@@ -1630,7 +1658,7 @@ struct buf_block_t{
decompressed LRU list;
used in debugging */
#endif /* UNIV_DEBUG */
- ib_mutex_t mutex; /*!< mutex protecting this block:
+ ib_mutex_t mutex; /*!< mutex protecting this block:
state, io_fix, buf_fix_count,
and accessed; we introduce this new
mutex in InnoDB-5.1 to relieve
@@ -1816,7 +1844,7 @@ struct buf_pool_t{
/** @name General fields */
/* @{ */
- ib_mutex_t zip_mutex; /*!< Zip mutex of this buffer
+ ib_mutex_t zip_mutex; /*!< Zip mutex of this buffer
pool instance, protects compressed
only pages (of type buf_page_t, not
buf_block_t */
@@ -1873,7 +1901,7 @@ struct buf_pool_t{
/* @{ */
- ib_mutex_t flush_list_mutex;/*!< mutex protecting the
+ ib_mutex_t flush_list_mutex;/*!< mutex protecting the
flush list access. This mutex
protects flush_list, flush_rbt
and bpage::list pointers when
@@ -1994,18 +2022,30 @@ Use these instead of accessing buffer pool mutexes directly. */
#define buf_flush_list_mutex_own(b) mutex_own(&b->flush_list_mutex)
/** Acquire the flush list mutex. */
-#define buf_flush_list_mutex_enter(b) do { \
- mutex_enter(&b->flush_list_mutex); \
+#define buf_flush_list_mutex_enter(b) do { \
+ mutex_enter(&b->flush_list_mutex); \
} while (0)
/** Release the flush list mutex. */
-# define buf_flush_list_mutex_exit(b) do { \
- mutex_exit(&b->flush_list_mutex); \
+# define buf_flush_list_mutex_exit(b) do { \
+ mutex_exit(&b->flush_list_mutex); \
+} while (0)
+
+/** Test if block->mutex is owned. */
+#define buf_block_mutex_own(b) mutex_own(&(b)->mutex)
+
+/** Acquire the block->mutex. */
+#define buf_block_mutex_enter(b) do { \
+ mutex_enter(&(b)->mutex); \
} while (0)
+/** Release the trx->mutex. */
+#define buf_block_mutex_exit(b) do { \
+ mutex_exit(&(b)->mutex); \
+} while (0)
/** Get appropriate page_hash_lock. */
-# define buf_page_hash_lock_get(b, f) \
+# define buf_page_hash_lock_get(b, f) \
hash_get_lock(b->page_hash, f)
#ifdef UNIV_SYNC_DEBUG
diff --git a/storage/xtradb/include/buf0buf.ic b/storage/xtradb/include/buf0buf.ic
index 4ef354b11ab..c49061621f3 100644
--- a/storage/xtradb/include/buf0buf.ic
+++ b/storage/xtradb/include/buf0buf.ic
@@ -345,15 +345,16 @@ buf_page_get_mutex(
/*===============*/
const buf_page_t* bpage) /*!< in: pointer to control block */
{
- buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
-
switch (buf_page_get_state(bpage)) {
case BUF_BLOCK_POOL_WATCH:
ut_error;
return(NULL);
case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_ZIP_DIRTY:
+ case BUF_BLOCK_ZIP_DIRTY: {
+ buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
+
return(&buf_pool->zip_mutex);
+ }
default:
return(&((buf_block_t*) bpage)->mutex);
}
@@ -407,8 +408,8 @@ buf_block_set_file_page(
ulint page_no)/*!< in: page number */
{
buf_block_set_state(block, BUF_BLOCK_FILE_PAGE);
- block->page.space = space;
- block->page.offset = page_no;
+ block->page.space = static_cast<ib_uint32_t>(space);
+ block->page.offset = static_cast<ib_uint32_t>(page_no);
}
/*********************************************************************//**
@@ -641,11 +642,12 @@ buf_page_set_accessed(
buf_page_t* bpage) /*!< in/out: control block */
{
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
+
ut_a(buf_page_in_file(bpage));
- if (!bpage->access_time) {
+ if (bpage->access_time == 0) {
/* Make this the time of the first access. */
- bpage->access_time = ut_time_ms();
+ bpage->access_time = static_cast<uint>(ut_time_ms());
}
}
@@ -1014,6 +1016,26 @@ buf_block_get_modify_clock(
Increments the bufferfix count. */
UNIV_INLINE
void
+buf_block_fix(
+/*===========*/
+ buf_block_t* block) /*!< in/out: block to bufferfix */
+{
+ ut_ad(!mutex_own(buf_page_get_mutex(&block->page)));
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_increment_uint32(&block->page.buf_fix_count, 1);
+#else
+ ib_mutex_t* block_mutex = buf_page_get_mutex(&block->page);
+
+ mutex_enter(block_mutex);
+ ++block->page.buf_fix_count;
+ mutex_exit(block_mutex);
+#endif /* PAGE_ATOMIC_REF_COUNT */
+}
+
+/*******************************************************************//**
+Increments the bufferfix count. */
+UNIV_INLINE
+void
buf_block_buf_fix_inc_func(
/*=======================*/
#ifdef UNIV_SYNC_DEBUG
@@ -1028,9 +1050,36 @@ buf_block_buf_fix_inc_func(
ret = rw_lock_s_lock_nowait(&(block->debug_latch), file, line);
ut_a(ret);
#endif /* UNIV_SYNC_DEBUG */
+
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_increment_uint32(&block->page.buf_fix_count, 1);
+#else
ut_ad(mutex_own(&block->mutex));
- block->page.buf_fix_count++;
+ ++block->page.buf_fix_count;
+#endif /* PAGE_ATOMIC_REF_COUNT */
+}
+
+/*******************************************************************//**
+Decrements the bufferfix count. */
+UNIV_INLINE
+void
+buf_block_unfix(
+/*============*/
+ buf_block_t* block) /*!< in/out: block to bufferunfix */
+{
+ ut_ad(block->page.buf_fix_count > 0);
+ ut_ad(!mutex_own(buf_page_get_mutex(&block->page)));
+
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_decrement_uint32(&block->page.buf_fix_count, 1);
+#else
+ ib_mutex_t* block_mutex = buf_page_get_mutex(&block->page);
+
+ mutex_enter(block_mutex);
+ --block->page.buf_fix_count;
+ mutex_exit(block_mutex);
+#endif /* PAGE_ATOMIC_REF_COUNT */
}
/*******************************************************************//**
@@ -1041,9 +1090,16 @@ buf_block_buf_fix_dec(
/*==================*/
buf_block_t* block) /*!< in/out: block to bufferunfix */
{
- ut_ad(mutex_own(&block->mutex));
+ ut_ad(block->page.buf_fix_count > 0);
+
+#ifdef PAGE_ATOMIC_REF_COUNT
+ os_atomic_decrement_uint32(&block->page.buf_fix_count, 1);
+#else
+ mutex_enter(&block->mutex);
+ --block->page.buf_fix_count;
+ mutex_exit(&block->mutex);
+#endif /* PAGE_ATOMIC_REF_COUNT */
- block->page.buf_fix_count--;
#ifdef UNIV_SYNC_DEBUG
rw_lock_s_unlock(&block->debug_latch);
#endif
@@ -1302,27 +1358,20 @@ buf_page_release_zip(
buf_page_t* bpage) /*!< in: buffer block */
{
buf_block_t* block;
- buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
- ut_ad(bpage);
- ut_a(bpage->buf_fix_count > 0);
+ block = (buf_block_t*) bpage;
switch (buf_page_get_state(bpage)) {
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_ZIP_DIRTY:
- mutex_enter(&buf_pool->zip_mutex);
- bpage->buf_fix_count--;
- mutex_exit(&buf_pool->zip_mutex);
- return;
case BUF_BLOCK_FILE_PAGE:
- block = (buf_block_t*) bpage;
- mutex_enter(&block->mutex);
#ifdef UNIV_SYNC_DEBUG
rw_lock_s_unlock(&block->debug_latch);
-#endif
- bpage->buf_fix_count--;
- mutex_exit(&block->mutex);
+#endif /* UNUV_SYNC_DEBUG */
+ /* Fall through */
+ case BUF_BLOCK_ZIP_PAGE:
+ case BUF_BLOCK_ZIP_DIRTY:
+ buf_block_unfix(block);
return;
+
case BUF_BLOCK_POOL_WATCH:
case BUF_BLOCK_NOT_USED:
case BUF_BLOCK_READY_FOR_USE:
@@ -1345,25 +1394,18 @@ buf_page_release(
ulint rw_latch) /*!< in: RW_S_LATCH, RW_X_LATCH,
RW_NO_LATCH */
{
- ut_ad(block);
-
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
- ut_a(block->page.buf_fix_count > 0);
-
- mutex_enter(&block->mutex);
#ifdef UNIV_SYNC_DEBUG
rw_lock_s_unlock(&(block->debug_latch));
#endif
- block->page.buf_fix_count--;
-
- mutex_exit(&block->mutex);
-
if (rw_latch == RW_S_LATCH) {
rw_lock_s_unlock(&(block->lock));
} else if (rw_latch == RW_X_LATCH) {
rw_lock_x_unlock(&(block->lock));
}
+
+ buf_block_unfix(block);
}
#ifdef UNIV_SYNC_DEBUG
@@ -1381,6 +1423,7 @@ buf_block_dbg_add_level(
{
sync_thread_add_level(&block->lock, level, FALSE);
}
+
#endif /* UNIV_SYNC_DEBUG */
/*********************************************************************//**
Get the nth chunk's buffer block in the specified buffer pool.
diff --git a/storage/xtradb/include/buf0dblwr.h b/storage/xtradb/include/buf0dblwr.h
index 1b9336f4002..a62a6400d97 100644
--- a/storage/xtradb/include/buf0dblwr.h
+++ b/storage/xtradb/include/buf0dblwr.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, 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
@@ -29,6 +29,7 @@ Created 2011/12/19 Inaam Rana
#include "univ.i"
#include "ut0byte.h"
#include "log0log.h"
+#include "log0recv.h"
#ifndef UNIV_HOTBACKUP
@@ -44,18 +45,26 @@ UNIV_INTERN
void
buf_dblwr_create(void);
/*==================*/
+
/****************************************************************//**
At a database startup initializes the doublewrite buffer memory structure if
we already have a doublewrite buffer created in the data files. If we are
upgrading to an InnoDB version which supports multiple tablespaces, then this
function performs the necessary update operations. If we are in a crash
-recovery, this function uses a possible doublewrite buffer to restore
-half-written pages in the data files. */
-UNIV_INTERN
+recovery, this function loads the pages from double write buffer into memory. */
+void
+buf_dblwr_init_or_load_pages(
+/*=========================*/
+ os_file_t file,
+ char* path,
+ bool load_corrupt_pages);
+
+/****************************************************************//**
+Process the double write buffer pages. */
void
-buf_dblwr_init_or_restore_pages(
-/*============================*/
- ibool restore_corrupt_pages); /*!< in: TRUE=restore pages */
+buf_dblwr_process(void);
+/*===================*/
+
/****************************************************************//**
frees doublewrite buffer. */
UNIV_INTERN
diff --git a/storage/xtradb/include/buf0flu.h b/storage/xtradb/include/buf0flu.h
index 73525a5bb58..7699e4fda67 100644
--- a/storage/xtradb/include/buf0flu.h
+++ b/storage/xtradb/include/buf0flu.h
@@ -36,6 +36,9 @@ Created 11/5/1995 Heikki Tuuri
/** Flag indicating if the page_cleaner is in active state. */
extern ibool buf_page_cleaner_is_active;
+/** Flag indicating if the lru_manager is in active state. */
+extern bool buf_lru_manager_is_active;
+
/********************************************************************//**
Remove a block from the flush list of modified blocks. */
UNIV_INTERN
@@ -175,7 +178,7 @@ buf_flush_ready_for_replace(
buf_page_in_file(bpage) and in the LRU list */
/******************************************************************//**
page_cleaner thread tasked with flushing dirty pages from the buffer
-pools. As of now we'll have only one instance of this thread.
+pool flush lists. As of now we'll have only one instance of this thread.
@return a dummy parameter */
extern "C" UNIV_INTERN
os_thread_ret_t
@@ -183,6 +186,17 @@ DECLARE_THREAD(buf_flush_page_cleaner_thread)(
/*==========================================*/
void* arg); /*!< in: a dummy parameter required by
os_thread_create */
+/******************************************************************//**
+lru_manager thread tasked with performing LRU flushes and evictions to refill
+the buffer pool free lists. As of now we'll have only one instance of this
+thread.
+@return a dummy parameter */
+extern "C" UNIV_INTERN
+os_thread_ret_t
+DECLARE_THREAD(buf_flush_lru_manager_thread)(
+/*=========================================*/
+ void* arg); /*!< in: a dummy parameter required by
+ os_thread_create */
/*********************************************************************//**
Clears up tail of the LRU lists:
* Put replaceable pages at the tail of LRU to the free list
@@ -233,16 +247,18 @@ Writes a flushable page asynchronously from the buffer pool to a file.
NOTE: in simulated aio we must call
os_aio_simulated_wake_handler_threads after we have posted a batch of
writes! NOTE: buf_page_get_mutex(bpage) must be held upon entering this
-function, and they will be released by this function. */
+function, and they will be released by this function if it returns true.
+LRU_list_mutex must be held iff performing a single page flush and will be
+released by the function if it returns true.
+@return TRUE if the page was flushed */
UNIV_INTERN
-void
+bool
buf_flush_page(
/*===========*/
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
buf_page_t* bpage, /*!< in: buffer control block */
buf_flush_t flush_type, /*!< in: type of flush */
- bool sync) /*!< in: true if sync IO request */
- __attribute__((nonnull));
+ bool sync); /*!< in: true if sync IO request */
/********************************************************************//**
Returns true if the block is modified and ready for flushing.
@return true if can flush immediately */
diff --git a/storage/xtradb/include/buf0types.h b/storage/xtradb/include/buf0types.h
index e19eb04a2ce..4eb5ea18cef 100644
--- a/storage/xtradb/include/buf0types.h
+++ b/storage/xtradb/include/buf0types.h
@@ -26,6 +26,10 @@ Created 11/17/1995 Heikki Tuuri
#ifndef buf0types_h
#define buf0types_h
+#if defined(INNODB_PAGE_ATOMIC_REF_COUNT) && defined(HAVE_ATOMIC_BUILTINS)
+#define PAGE_ATOMIC_REF_COUNT
+#endif /* INNODB_PAGE_ATOMIC_REF_COUNT && HAVE_ATOMIC_BUILTINS */
+
/** Buffer page (uncompressed or compressed) */
struct buf_page_t;
/** Buffer block for which an uncompressed page exists */
diff --git a/storage/xtradb/include/db0err.h b/storage/xtradb/include/db0err.h
index 17fef0dc1f4..744b80ecd05 100644
--- a/storage/xtradb/include/db0err.h
+++ b/storage/xtradb/include/db0err.h
@@ -128,6 +128,8 @@ enum dberr_t {
DB_FTS_EXCEED_RESULT_CACHE_LIMIT, /*!< FTS query memory
exceeds result cache limit */
DB_TEMP_FILE_WRITE_FAILURE, /*!< Temp file write failure */
+ DB_FTS_TOO_MANY_WORDS_IN_PHRASE,
+ /*< Too many words in a phrase */
/* The following are partial failure codes */
DB_FAIL = 1000,
diff --git a/storage/xtradb/include/dict0dict.h b/storage/xtradb/include/dict0dict.h
index 6669f60b95a..0a93f0532f5 100644
--- a/storage/xtradb/include/dict0dict.h
+++ b/storage/xtradb/include/dict0dict.h
@@ -43,6 +43,9 @@ Created 1/8/1996 Heikki Tuuri
#include "trx0types.h"
#include "row0types.h"
+extern bool innodb_table_stats_not_found;
+extern bool innodb_index_stats_not_found;
+
#ifndef UNIV_HOTBACKUP
# include "sync0sync.h"
# include "sync0rw.h"
@@ -1443,20 +1446,16 @@ UNIV_INTERN
void
dict_table_stats_lock(
/*==================*/
- const dict_table_t* table, /*!< in: table */
- ulint latch_mode) /*!< in: RW_S_LATCH or
- RW_X_LATCH */
- __attribute__((nonnull));
+ dict_table_t* table, /*!< in: table */
+ ulint latch_mode); /*!< in: RW_S_LATCH or RW_X_LATCH */
/**********************************************************************//**
Unlock the latch that has been locked by dict_table_stats_lock() */
UNIV_INTERN
void
dict_table_stats_unlock(
/*====================*/
- const dict_table_t* table, /*!< in: table */
- ulint latch_mode) /*!< in: RW_S_LATCH or
- RW_X_LATCH */
- __attribute__((nonnull));
+ dict_table_t* table, /*!< in: table */
+ ulint latch_mode); /*!< in: RW_S_LATCH or RW_X_LATCH */
/********************************************************************//**
Checks if the database name in two table names is the same.
@return TRUE if same db name */
@@ -1802,6 +1801,17 @@ const char*
dict_tf_to_row_format_string(
/*=========================*/
ulint table_flag); /*!< in: row format setting */
+/*****************************************************************//**
+Get index by first field of the index
+@return index which is having first field matches
+with the field present in field_index position of table */
+UNIV_INLINE
+dict_index_t*
+dict_table_get_index_on_first_col(
+/*==============================*/
+ const dict_table_t* table, /*!< in: table */
+ ulint col_index); /*!< in: position of column
+ in table */
#endif /* !UNIV_HOTBACKUP */
/*************************************************************************
diff --git a/storage/xtradb/include/dict0dict.ic b/storage/xtradb/include/dict0dict.ic
index c261d6a3aee..6bfd7f6cdae 100644
--- a/storage/xtradb/include/dict0dict.ic
+++ b/storage/xtradb/include/dict0dict.ic
@@ -1403,4 +1403,31 @@ dict_table_is_temporary(
return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY));
}
+/**********************************************************************//**
+Get index by first field of the index
+@return index which is having first field matches
+with the field present in field_index position of table */
+UNIV_INLINE
+dict_index_t*
+dict_table_get_index_on_first_col(
+/*==============================*/
+ const dict_table_t* table, /*!< in: table */
+ ulint col_index) /*!< in: position of column
+ in table */
+{
+ ut_ad(col_index < table->n_cols);
+
+ dict_col_t* column = dict_table_get_nth_col(table, col_index);
+
+ for (dict_index_t* index = dict_table_get_first_index(table);
+ index != NULL; index = dict_table_get_next_index(index)) {
+
+ if (index->fields[0].col == column) {
+ return(index);
+ }
+ }
+ ut_error;
+ return(0);
+}
+
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/xtradb/include/dict0mem.h b/storage/xtradb/include/dict0mem.h
index bde0ce16094..0dd0ea63f3b 100644
--- a/storage/xtradb/include/dict0mem.h
+++ b/storage/xtradb/include/dict0mem.h
@@ -198,7 +198,7 @@ ROW_FORMAT=REDUNDANT. InnoDB engines do not check these flags
for unknown bits in order to protect backward incompatibility. */
/* @{ */
/** Total number of bits in table->flags2. */
-#define DICT_TF2_BITS 6
+#define DICT_TF2_BITS 7
#define DICT_TF2_BIT_MASK ~(~0 << DICT_TF2_BITS)
/** TEMPORARY; TRUE for tables from CREATE TEMPORARY TABLE. */
@@ -216,6 +216,10 @@ use its own tablespace instead of the system tablespace. */
/** Set when we discard/detach the tablespace */
#define DICT_TF2_DISCARDED 32
+
+/** This bit is set if all aux table names (both common tables and
+index tables) of a FTS table are in HEX format. */
+#define DICT_TF2_FTS_AUX_HEX_NAME 64
/* @} */
#define DICT_TF2_FLAG_SET(table, flag) \
@@ -255,7 +259,10 @@ dict_mem_table_create(
of the table is placed */
ulint n_cols, /*!< in: number of columns */
ulint flags, /*!< in: table flags */
- ulint flags2); /*!< in: table flags2 */
+ ulint flags2, /*!< in: table flags2 */
+ bool nonshared);/*!< in: whether the table object is a dummy
+ one that does not need the initialization of
+ locking-related fields. */
/****************************************************************//**
Free a table memory object. */
UNIV_INTERN
@@ -631,6 +638,9 @@ struct dict_index_t{
ulint stat_n_leaf_pages;
/*!< approximate number of leaf pages in the
index tree */
+ bool stats_error_printed;
+ /*!< has persistent statistics error printed
+ for this index ? */
/* @} */
prio_rw_lock_t lock; /*!< read-write lock protecting the
upper levels of the index tree */
@@ -728,6 +738,11 @@ a foreign key constraint is enforced, therefore RESTRICT just means no flag */
#define DICT_FOREIGN_ON_UPDATE_NO_ACTION 32 /*!< ON UPDATE NO ACTION */
/* @} */
+/* This flag is for sync SQL DDL and memcached DML.
+if table->memcached_sync_count == DICT_TABLE_IN_DDL means there's DDL running on
+the table, DML from memcached will be blocked. */
+#define DICT_TABLE_IN_DDL -1
+
/** Data structure for a database table. Most fields will be
initialized to 0, NULL or FALSE in dict_mem_table_create(). */
struct dict_table_t{
@@ -841,9 +856,29 @@ struct dict_table_t{
initialized in dict_table_add_to_cache() */
/** Statistics for query optimization */
/* @{ */
+ rw_lock_t* stats_latch; /*!< this latch protects:
+ dict_table_t::stat_initialized
+ dict_table_t::stat_n_rows (*)
+ dict_table_t::stat_clustered_index_size
+ dict_table_t::stat_sum_of_other_index_sizes
+ dict_table_t::stat_modified_counter (*)
+ dict_table_t::indexes*::stat_n_diff_key_vals[]
+ dict_table_t::indexes*::stat_index_size
+ dict_table_t::indexes*::stat_n_leaf_pages
+ (*) those are not always protected for
+ performance reasons. NULL for dumy table
+ objects. */
unsigned stat_initialized:1; /*!< TRUE if statistics have
been calculated the first time
after database startup or table creation */
+#define DICT_TABLE_IN_USED -1
+ lint memcached_sync_count;
+ /*!< count of how many handles are opened
+ to this table from memcached; DDL on the
+ table is NOT allowed until this count
+ goes to zero. If it's -1, means there's DDL
+ on the table, DML from memcached will be
+ blocked. */
ib_time_t stats_last_recalc;
/*!< Timestamp of last recalc of the stats */
ib_uint32_t stat_persistent;
@@ -930,6 +965,9 @@ struct dict_table_t{
/*!< see BG_STAT_* above.
Writes are covered by dict_sys->mutex.
Dirty reads are possible. */
+ bool stats_error_printed;
+ /*!< Has persistent stats error beein
+ already printed for this table ? */
/* @} */
/*----------------------*/
/**!< The following fields are used by the
@@ -954,10 +992,12 @@ struct dict_table_t{
and release it without a need to allocate
space from the lock heap of the trx:
otherwise the lock heap would grow rapidly
- if we do a large insert from a select */
+ if we do a large insert from a select. NULL
+ for dummy table objects. */
ib_mutex_t autoinc_mutex;
/*!< mutex protecting the autoincrement
- counter */
+ counter. Not initialized for dummy table
+ objects */
ib_uint64_t autoinc;/*!< autoinc counter value to give to the
next inserted row */
ulong n_waiting_or_granted_auto_inc_locks;
diff --git a/storage/xtradb/include/fil0fil.h b/storage/xtradb/include/fil0fil.h
index 472c57fcbfc..f32dc1f699f 100644
--- a/storage/xtradb/include/fil0fil.h
+++ b/storage/xtradb/include/fil0fil.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, 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
@@ -128,6 +128,8 @@ extern fil_addr_t fil_addr_null;
at least up to this lsn */
#define FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID 34 /*!< starting from 4.1.x this
contains the space id of the page */
+#define FIL_PAGE_SPACE_ID FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID
+
#define FIL_PAGE_DATA 38 /*!< start of the data on the page */
/* @} */
/** File page trailer @{ */
@@ -175,6 +177,17 @@ extern ulint fil_n_pending_tablespace_flushes;
/** Number of files currently open */
extern ulint fil_n_file_opened;
+struct fsp_open_info {
+ ibool success; /*!< Has the tablespace been opened? */
+ const char* check_msg; /*!< fil_check_first_page() message */
+ ibool valid; /*!< Is the tablespace valid? */
+ os_file_t file; /*!< File handle */
+ char* filepath; /*!< File path to open */
+ lsn_t lsn; /*!< Flushed LSN from header page */
+ ulint id; /*!< Space ID */
+ ulint flags; /*!< Tablespace flags */
+};
+
#ifndef UNIV_HOTBACKUP
/*******************************************************************//**
Returns the version number of a tablespace, -1 if not found.
@@ -992,6 +1005,18 @@ fil_mtr_rename_log(
mtr_t* mtr) /*!< in/out: mini-transaction */
__attribute__((nonnull));
+/*******************************************************************//**
+Finds the given page_no of the given space id from the double write buffer,
+and copies it to the corresponding .ibd file.
+@return true if copy was successful, or false. */
+bool
+fil_user_tablespace_restore_page(
+/*==============================*/
+ fsp_open_info* fsp, /* in: contains space id and .ibd
+ file information */
+ ulint page_no); /* in: page_no to obtain from double
+ write buffer */
+
#endif /* !UNIV_INNOCHECKSUM */
/*************************************************************************
diff --git a/storage/xtradb/include/fts0priv.h b/storage/xtradb/include/fts0priv.h
index c6aca27f6ec..b4d9e1d41ec 100644
--- a/storage/xtradb/include/fts0priv.h
+++ b/storage/xtradb/include/fts0priv.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, 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
@@ -569,7 +569,10 @@ int
fts_write_object_id(
/*================*/
ib_id_t id, /*!< in: a table/index id */
- char* str) /*!< in: buffer to write the id to */
+ char* str, /*!< in: buffer to write the id to */
+ bool hex_format __attribute__((unused)))
+ /*!< in: true for fixed hex format,
+ false for old ambiguous format */
__attribute__((nonnull));
/******************************************************************//**
Read the table id from the string generated by fts_write_object_id().
diff --git a/storage/xtradb/include/fts0priv.ic b/storage/xtradb/include/fts0priv.ic
index 268bb7e2227..8ef877f267e 100644
--- a/storage/xtradb/include/fts0priv.ic
+++ b/storage/xtradb/include/fts0priv.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, 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
@@ -32,9 +32,24 @@ int
fts_write_object_id(
/*================*/
ib_id_t id, /* in: a table/index id */
- char* str) /* in: buffer to write the id to */
+ char* str, /* in: buffer to write the id to */
+ bool hex_format __attribute__((unused)))
+ /* in: true for fixed hex format,
+ false for old ambiguous format */
{
- // FIXME: Use ut_snprintf()
+#ifdef _WIN32
+ /* Use this to construct old(5.6.14 and 5.7.3) ambiguous
+ aux table names */
+ DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
+ return(sprintf(str, "%016llu", id)););
+
+ /* As above, but this is only for those tables failing to rename. */
+ if (!hex_format) {
+ // FIXME: Use ut_snprintf(), so does following one.
+ return(sprintf(str, "%016llu", id));
+ }
+#endif /* _WIN32 */
+
return(sprintf(str, UINT64PFx, id));
}
@@ -48,6 +63,9 @@ fts_read_object_id(
ib_id_t* id, /* out: an id */
const char* str) /* in: buffer to read from */
{
+ /* NOTE: this func doesn't care about whether current table
+ is set with HEX_NAME, the user of the id read here will check
+ if the id is HEX or DEC and do the right thing with it. */
return(sscanf(str, UINT64PFx, id) == 1);
}
diff --git a/storage/xtradb/include/ha_prototypes.h b/storage/xtradb/include/ha_prototypes.h
index 4599547439e..66a96282b69 100644
--- a/storage/xtradb/include/ha_prototypes.h
+++ b/storage/xtradb/include/ha_prototypes.h
@@ -420,16 +420,6 @@ innobase_fts_text_case_cmp(
const void* p1, /*!< in: key */
const void* p2); /*!< in: node */
-/******************************************************************//**
-compare two character string according to their charset. */
-UNIV_INTERN
-int
-innobase_fts_string_cmp(
-/*====================*/
- const void* cs, /*!< in: Character set */
- const void* p1, /*!< in: key */
- const void* p2); /*!< in: node */
-
/****************************************************************//**
Get FTS field charset info from the field's prtype
@return charset info */
diff --git a/storage/xtradb/include/lock0lock.h b/storage/xtradb/include/lock0lock.h
index 3a3a28ef525..cb95c58fe3c 100644
--- a/storage/xtradb/include/lock0lock.h
+++ b/storage/xtradb/include/lock0lock.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2014, 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
@@ -291,7 +291,7 @@ lock_rec_insert_check_and_lock(
inserted record maybe should inherit
LOCK_GAP type locks from the successor
record */
- __attribute__((nonnull, warn_unused_result));
+ __attribute__((nonnull(2,3,4,6,7), warn_unused_result));
/*********************************************************************//**
Checks if locks of other transactions prevent an immediate modify (update,
delete mark, or delete unmark) of a clustered index record. If they do,
@@ -904,22 +904,15 @@ lock_trx_has_rec_x_lock(
remains set when the waiting lock is granted,
or if the lock is inherited to a neighboring
record */
-#define LOCK_CONV_BY_OTHER 4096 /*!< this bit is set when the lock is created
- by other transaction */
-#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_CONV_BY_OTHER)&LOCK_MODE_MASK
+
+#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION)&LOCK_MODE_MASK
# error
#endif
-#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION|LOCK_CONV_BY_OTHER)&LOCK_TYPE_MASK
+#if (LOCK_WAIT|LOCK_GAP|LOCK_REC_NOT_GAP|LOCK_INSERT_INTENTION)&LOCK_TYPE_MASK
# error
#endif
/* @} */
-/** Checks if this is a waiting lock created by lock->trx itself.
-@param type_mode lock->type_mode
-@return whether it is a waiting lock belonging to lock->trx */
-#define lock_is_wait_not_by_other(type_mode) \
- ((type_mode & (LOCK_CONV_BY_OTHER | LOCK_WAIT)) == LOCK_WAIT)
-
/** Lock operation struct */
struct lock_op_t{
dict_table_t* table; /*!< table to be locked */
diff --git a/storage/xtradb/include/log0recv.h b/storage/xtradb/include/log0recv.h
index a1653c10999..805b6c66768 100644
--- a/storage/xtradb/include/log0recv.h
+++ b/storage/xtradb/include/log0recv.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2014, 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
@@ -31,6 +31,7 @@ Created 9/20/1997 Heikki Tuuri
#include "buf0types.h"
#include "hash0hash.h"
#include "log0log.h"
+#include <list>
/******************************************************//**
Checks the 4-byte checksum to the trailer checksum field of a log
@@ -404,6 +405,18 @@ struct recv_addr_t{
hash_node_t addr_hash;/*!< hash node in the hash bucket chain */
};
+struct recv_dblwr_t {
+ void add(byte* page);
+
+ byte* find_page(ulint space_id, ulint page_no);
+
+ std::list<byte *> pages; /* Pages from double write buffer */
+
+ void operator() () {
+ pages.clear();
+ }
+};
+
/** Recovery system data structure */
struct recv_sys_t{
#ifndef UNIV_HOTBACKUP
@@ -468,6 +481,8 @@ struct recv_sys_t{
hash_table_t* addr_hash;/*!< hash table of file addresses of pages */
ulint n_addrs;/*!< number of not processed hashed file
addresses in the hash table */
+
+ recv_dblwr_t dblwr;
};
/** The recovery system */
diff --git a/storage/xtradb/include/mem0mem.h b/storage/xtradb/include/mem0mem.h
index c36ef06b554..f30034f3074 100644
--- a/storage/xtradb/include/mem0mem.h
+++ b/storage/xtradb/include/mem0mem.h
@@ -92,18 +92,35 @@ void
mem_close(void);
/*===========*/
+#ifdef UNIV_DEBUG
/**************************************************************//**
Use this macro instead of the corresponding function! Macro for memory
heap creation. */
-#define mem_heap_create(N) mem_heap_create_func(\
- (N), MEM_HEAP_DYNAMIC, __FILE__, __LINE__)
+# define mem_heap_create(N) mem_heap_create_func( \
+ (N), __FILE__, __LINE__, MEM_HEAP_DYNAMIC)
/**************************************************************//**
Use this macro instead of the corresponding function! Macro for memory
heap creation. */
-#define mem_heap_create_typed(N, T) mem_heap_create_func(\
- (N), (T), __FILE__, __LINE__)
+# define mem_heap_create_typed(N, T) mem_heap_create_func( \
+ (N), __FILE__, __LINE__, (T))
+
+#else /* UNIV_DEBUG */
+/**************************************************************//**
+Use this macro instead of the corresponding function! Macro for memory
+heap creation. */
+
+# define mem_heap_create(N) mem_heap_create_func( \
+ (N), MEM_HEAP_DYNAMIC)
+/**************************************************************//**
+Use this macro instead of the corresponding function! Macro for memory
+heap creation. */
+
+# define mem_heap_create_typed(N, T) mem_heap_create_func( \
+ (N), (T))
+
+#endif /* UNIV_DEBUG */
/**************************************************************//**
Use this macro instead of the corresponding function! Macro for memory
heap freeing. */
@@ -124,9 +141,11 @@ mem_heap_create_func(
this means that a single user buffer
of size n will fit in the block,
0 creates a default size block */
- ulint type, /*!< in: heap type */
+#ifdef UNIV_DEBUG
const char* file_name, /*!< in: file name where created */
- ulint line); /*!< in: line where created */
+ ulint line, /*!< in: line where created */
+#endif /* UNIV_DEBUG */
+ ulint type); /*!< in: heap type */
/*****************************************************************//**
NOTE: Use the corresponding macro instead of this function. Frees the space
occupied by a memory heap. In the debug version erases the heap memory
@@ -218,8 +237,14 @@ Macro for memory buffer allocation */
#define mem_zalloc(N) memset(mem_alloc(N), 0, (N))
-#define mem_alloc(N) mem_alloc_func((N), NULL, __FILE__, __LINE__)
-#define mem_alloc2(N,S) mem_alloc_func((N), (S), __FILE__, __LINE__)
+#ifdef UNIV_DEBUG
+#define mem_alloc(N) mem_alloc_func((N), __FILE__, __LINE__, NULL)
+#define mem_alloc2(N,S) mem_alloc_func((N), __FILE__, __LINE__, (S))
+#else /* UNIV_DEBUG */
+#define mem_alloc(N) mem_alloc_func((N), NULL)
+#define mem_alloc2(N,S) mem_alloc_func((N), (S))
+#endif /* UNIV_DEBUG */
+
/***************************************************************//**
NOTE: Use the corresponding macro instead of this function.
Allocates a single buffer of memory from the dynamic memory of
@@ -231,10 +256,12 @@ void*
mem_alloc_func(
/*===========*/
ulint n, /*!< in: requested size in bytes */
- ulint* size, /*!< out: allocated size in bytes,
- or NULL */
+#ifdef UNIV_DEBUG
const char* file_name, /*!< in: file name where created */
- ulint line); /*!< in: line where created */
+ ulint line, /*!< in: line where created */
+#endif /* UNIV_DEBUG */
+ ulint* size); /*!< out: allocated size in bytes,
+ or NULL */
/**************************************************************//**
Use this macro instead of the corresponding function!
@@ -343,8 +370,10 @@ mem_validate_all_blocks(void);
/** The info structure stored at the beginning of a heap block */
struct mem_block_info_t {
ulint magic_n;/* magic number for debugging */
+#ifdef UNIV_DEBUG
char file_name[8];/* file name where the mem heap was created */
ulint line; /*!< line number where the mem heap was created */
+#endif /* UNIV_DEBUG */
UT_LIST_BASE_NODE_T(mem_block_t) base; /* In the first block in the
the list this is the base node of the list of blocks;
in subsequent blocks this is undefined */
diff --git a/storage/xtradb/include/mem0mem.ic b/storage/xtradb/include/mem0mem.ic
index 7f0e128cc40..0d983d69e1a 100644
--- a/storage/xtradb/include/mem0mem.ic
+++ b/storage/xtradb/include/mem0mem.ic
@@ -28,21 +28,34 @@ Created 6/8/1994 Heikki Tuuri
# include "mem0pool.h"
#endif /* !UNIV_HOTBACKUP */
+#ifdef UNIV_DEBUG
+# define mem_heap_create_block(heap, n, type, file_name, line) \
+ mem_heap_create_block_func(heap, n, file_name, line, type)
+# define mem_heap_create_at(N, file_name, line) \
+ mem_heap_create_func(N, file_name, line, MEM_HEAP_DYNAMIC)
+#else /* UNIV_DEBUG */
+# define mem_heap_create_block(heap, n, type, file_name, line) \
+ mem_heap_create_block_func(heap, n, type)
+# define mem_heap_create_at(N, file_name, line) \
+ mem_heap_create_func(N, MEM_HEAP_DYNAMIC)
+#endif /* UNIV_DEBUG */
/***************************************************************//**
Creates a memory heap block where data can be allocated.
@return own: memory heap block, NULL if did not succeed (only possible
for MEM_HEAP_BTR_SEARCH type heaps) */
UNIV_INTERN
mem_block_t*
-mem_heap_create_block(
-/*==================*/
+mem_heap_create_block_func(
+/*=======================*/
mem_heap_t* heap, /*!< in: memory heap or NULL if first block
should be created */
ulint n, /*!< in: number of bytes needed for user data */
- ulint type, /*!< in: type of heap: MEM_HEAP_DYNAMIC or
- MEM_HEAP_BUFFER */
+#ifdef UNIV_DEBUG
const char* file_name,/*!< in: file name where created */
- ulint line); /*!< in: line where created */
+ ulint line, /*!< in: line where created */
+#endif /* UNIV_DEBUG */
+ ulint type); /*!< in: type of heap: MEM_HEAP_DYNAMIC or
+ MEM_HEAP_BUFFER */
/******************************************************************//**
Frees a block from a memory heap. */
UNIV_INTERN
@@ -421,9 +434,11 @@ mem_heap_create_func(
this means that a single user buffer
of size n will fit in the block,
0 creates a default size block */
- ulint type, /*!< in: heap type */
+#ifdef UNIV_DEBUG
const char* file_name, /*!< in: file name where created */
- ulint line) /*!< in: line where created */
+ ulint line, /*!< in: line where created */
+#endif /* UNIV_DEBUG */
+ ulint type) /*!< in: heap type */
{
mem_block_t* block;
@@ -509,15 +524,17 @@ void*
mem_alloc_func(
/*===========*/
ulint n, /*!< in: desired number of bytes */
- ulint* size, /*!< out: allocated size in bytes,
- or NULL */
+#ifdef UNIV_DEBUG
const char* file_name, /*!< in: file name where created */
- ulint line) /*!< in: line where created */
+ ulint line, /*!< in: line where created */
+#endif /* UNIV_DEBUG */
+ ulint* size) /*!< out: allocated size in bytes,
+ or NULL */
{
mem_heap_t* heap;
void* buf;
- heap = mem_heap_create_func(n, MEM_HEAP_DYNAMIC, file_name, line);
+ heap = mem_heap_create_at(n, file_name, line);
/* Note that as we created the first block in the heap big enough
for the buffer requested by the caller, the buffer will be in the
diff --git a/storage/xtradb/include/os0file.h b/storage/xtradb/include/os0file.h
index 136c7b35a0a..1ab71d80829 100644
--- a/storage/xtradb/include/os0file.h
+++ b/storage/xtradb/include/os0file.h
@@ -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.
Copyright (c) 2009, Percona Inc.
Portions of this file contain modifications contributed and copyrighted
@@ -155,6 +155,10 @@ enum os_file_create_t {
#define OS_FILE_INSUFFICIENT_RESOURCE 78
#define OS_FILE_AIO_INTERRUPTED 79
#define OS_FILE_OPERATION_ABORTED 80
+
+#define OS_FILE_ACCESS_VIOLATION 81
+
+#define OS_FILE_ERROR_MAX 100
/* @} */
/** Types for aio operations @{ */
@@ -164,8 +168,8 @@ enum os_file_create_t {
#define OS_FILE_LOG 256 /* This can be ORed to type */
/* @} */
-#define OS_AIO_N_PENDING_IOS_PER_THREAD 256 /*!< Windows might be able to handle
-more */
+#define OS_AIO_N_PENDING_IOS_PER_THREAD 32 /*!< Win NT does not allow more
+ than 64 */
/** Modes for aio operations @{ */
#define OS_AIO_NORMAL 21 /*!< Normal asynchronous i/o not for ibuf
@@ -401,7 +405,8 @@ enum os_file_type_t {
OS_FILE_TYPE_UNKNOWN = 0,
OS_FILE_TYPE_FILE, /* regular file */
OS_FILE_TYPE_DIR, /* directory */
- OS_FILE_TYPE_LINK /* symbolic link */
+ OS_FILE_TYPE_LINK, /* symbolic link */
+ OS_FILE_TYPE_BLOCK /* block device */
};
/* Maximum path string length in bytes when referring to tables with in the
diff --git a/storage/xtradb/include/os0sync.h b/storage/xtradb/include/os0sync.h
index 51c4530bb5a..fa96eb7f28c 100644
--- a/storage/xtradb/include/os0sync.h
+++ b/storage/xtradb/include/os0sync.h
@@ -374,6 +374,9 @@ compare to, new_val is the value to swap in. */
# define os_compare_and_swap_lint(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
+# define os_compare_and_swap_uint32(ptr, old_val, new_val) \
+ os_compare_and_swap(ptr, old_val, new_val)
+
# ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC
# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
@@ -395,6 +398,9 @@ amount of increment. */
# define os_atomic_increment_lint(ptr, amount) \
os_atomic_increment(ptr, amount)
+# define os_atomic_increment_uint32(ptr, amount ) \
+ os_atomic_increment(ptr, amount)
+
# define os_atomic_increment_ulint(ptr, amount) \
os_atomic_increment(ptr, amount)
@@ -407,6 +413,9 @@ amount to decrement. */
# define os_atomic_decrement(ptr, amount) \
__sync_sub_and_fetch(ptr, amount)
+# define os_atomic_decrement_uint32(ptr, amount) \
+ os_atomic_decrement(ptr, amount)
+
# define os_atomic_decrement_lint(ptr, amount) \
os_atomic_decrement(ptr, amount)
@@ -425,6 +434,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
# define os_atomic_test_and_set_ulint(ptr, new_val) \
__sync_lock_test_and_set(ptr, new_val)
+# define os_atomic_lock_release_byte(ptr) \
+ __sync_lock_release(ptr)
+
#elif defined(HAVE_IB_SOLARIS_ATOMICS)
# define HAVE_ATOMIC_BUILTINS
@@ -439,6 +451,9 @@ intrinsics and running on Solaris >= 10 use Solaris atomics */
Returns true if swapped, ptr is pointer to target, old_val is value to
compare to, new_val is the value to swap in. */
+# define os_compare_and_swap_uint32(ptr, old_val, new_val) \
+ (atomic_cas_32(ptr, old_val, new_val) == old_val)
+
# define os_compare_and_swap_ulint(ptr, old_val, new_val) \
(atomic_cas_ulong(ptr, old_val, new_val) == old_val)
@@ -467,6 +482,9 @@ compare to, new_val is the value to swap in. */
Returns the resulting value, ptr is pointer to target, amount is the
amount of increment. */
+# define os_atomic_increment_uint32(ptr, amount) \
+ atomic_add_32_nv(ptr, amount)
+
# define os_atomic_increment_ulint(ptr, amount) \
atomic_add_long_nv(ptr, amount)
@@ -479,6 +497,9 @@ amount of increment. */
/* Returns the resulting value, ptr is pointer to target, amount is the
amount to decrement. */
+# define os_atomic_decrement_uint32(ptr, amount) \
+ os_atomic_increment_uint32(ptr, -(amount))
+
# define os_atomic_decrement_lint(ptr, amount) \
os_atomic_increment_ulint((ulong_t*) ptr, -(amount))
@@ -497,6 +518,9 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
# define os_atomic_test_and_set_ulint(ptr, new_val) \
atomic_swap_ulong(ptr, new_val)
+# define os_atomic_lock_release_byte(ptr) \
+ (void) atomic_swap_uchar(ptr, 0)
+
#elif defined(HAVE_WINDOWS_ATOMICS)
# define HAVE_ATOMIC_BUILTINS
@@ -555,6 +579,9 @@ win_cmp_and_xchg_dword(
Returns true if swapped, ptr is pointer to target, old_val is value to
compare to, new_val is the value to swap in. */
+# define os_compare_and_swap_uint32(ptr, old_val, new_val) \
+ (win_cmp_and_xchg_dword(ptr, new_val, old_val) == old_val)
+
# define os_compare_and_swap_ulint(ptr, old_val, new_val) \
(win_cmp_and_xchg_ulint(ptr, new_val, old_val) == old_val)
@@ -576,6 +603,9 @@ amount of increment. */
# define os_atomic_increment_lint(ptr, amount) \
(win_xchg_and_add(ptr, amount) + amount)
+# define os_atomic_increment_uint32(ptr, amount) \
+ ((ulint) InterlockedExchangeAdd((long*) ptr, amount))
+
# define os_atomic_increment_ulint(ptr, amount) \
((ulint) (win_xchg_and_add((lint*) ptr, (lint) amount) + amount))
@@ -588,6 +618,9 @@ amount of increment. */
Returns the resulting value, ptr is pointer to target, amount is the
amount to decrement. There is no atomic substract function on Windows */
+# define os_atomic_decrement_uint32(ptr, amount) \
+ ((ulint) InterlockedExchangeAdd((long*) ptr, (-amount)))
+
# define os_atomic_decrement_lint(ptr, amount) \
(win_xchg_and_add(ptr, -(lint) amount) - amount)
@@ -610,6 +643,9 @@ clobbered */
# define os_atomic_test_and_set_ulong(ptr, new_val) \
InterlockedExchange(ptr, new_val)
+# define os_atomic_lock_release_byte(ptr) \
+ (void) InterlockedExchange(ptr, 0)
+
#else
# define IB_ATOMICS_STARTUP_MSG \
"Mutexes and rw_locks use InnoDB's own implementation"
diff --git a/storage/xtradb/include/os0sync.ic b/storage/xtradb/include/os0sync.ic
index 33c238ceb47..9a7e520ece6 100644
--- a/storage/xtradb/include/os0sync.ic
+++ b/storage/xtradb/include/os0sync.ic
@@ -112,8 +112,10 @@ pfs_os_fast_mutex_lock(
PSI_mutex_locker* locker;
PSI_mutex_locker_state state;
- locker = PSI_MUTEX_CALL(start_mutex_wait)(&state, fast_mutex->pfs_psi,
- PSI_MUTEX_LOCK, file_name, line);
+ locker = PSI_MUTEX_CALL(start_mutex_wait)(
+ &state, fast_mutex->pfs_psi,
+ PSI_MUTEX_LOCK, file_name,
+ static_cast<uint>(line));
os_fast_mutex_lock_func(&fast_mutex->mutex);
diff --git a/storage/xtradb/include/page0page.h b/storage/xtradb/include/page0page.h
index 80181bb5c30..6940040a130 100644
--- a/storage/xtradb/include/page0page.h
+++ b/storage/xtradb/include/page0page.h
@@ -1102,6 +1102,14 @@ page_find_rec_with_heap_no(
/*=======================*/
const page_t* page, /*!< in: index page */
ulint heap_no);/*!< in: heap number */
+/** Get the last non-delete-marked record on a page.
+@param[in] page index tree leaf page
+@return the last record, not delete-marked
+@retval infimum record if all records are delete-marked */
+
+const rec_t*
+page_find_rec_max_not_deleted(
+ const page_t* page);
#ifdef UNIV_MATERIALIZE
#undef UNIV_INLINE
#define UNIV_INLINE UNIV_INLINE_ORIGINAL
diff --git a/storage/xtradb/include/page0page.ic b/storage/xtradb/include/page0page.ic
index 58add015d34..4a22a32112f 100644
--- a/storage/xtradb/include/page0page.ic
+++ b/storage/xtradb/include/page0page.ic
@@ -417,6 +417,8 @@ page_rec_is_user_rec(
/*=================*/
const rec_t* rec) /*!< in: record */
{
+ ut_ad(page_rec_check(rec));
+
return(page_rec_is_user_rec_low(page_offset(rec)));
}
@@ -429,6 +431,8 @@ page_rec_is_supremum(
/*=================*/
const rec_t* rec) /*!< in: record */
{
+ ut_ad(page_rec_check(rec));
+
return(page_rec_is_supremum_low(page_offset(rec)));
}
@@ -441,6 +445,8 @@ page_rec_is_infimum(
/*================*/
const rec_t* rec) /*!< in: record */
{
+ ut_ad(page_rec_check(rec));
+
return(page_rec_is_infimum_low(page_offset(rec)));
}
diff --git a/storage/xtradb/include/rem0rec.h b/storage/xtradb/include/rem0rec.h
index 2a84aee7a6f..8e7d5ff2d48 100644
--- a/storage/xtradb/include/rem0rec.h
+++ b/storage/xtradb/include/rem0rec.h
@@ -440,13 +440,24 @@ rec_get_offsets_func(
ulint n_fields,/*!< in: maximum number of
initialized fields
(ULINT_UNDEFINED if all fields) */
- mem_heap_t** heap, /*!< in/out: memory heap */
+#ifdef UNIV_DEBUG
const char* file, /*!< in: file name where called */
- ulint line) /*!< in: line number where called */
- __attribute__((nonnull(1,2,5,6),warn_unused_result));
+ ulint line, /*!< in: line number where called */
+#endif /* UNIV_DEBUG */
+ mem_heap_t** heap) /*!< in/out: memory heap */
+#ifdef UNIV_DEBUG
+ __attribute__((nonnull(1,2,5,7),warn_unused_result));
+#else /* UNIV_DEBUG */
+ __attribute__((nonnull(1,2,5),warn_unused_result));
+#endif /* UNIV_DEBUG */
-#define rec_get_offsets(rec,index,offsets,n,heap) \
- rec_get_offsets_func(rec,index,offsets,n,heap,__FILE__,__LINE__)
+#ifdef UNIV_DEBUG
+# define rec_get_offsets(rec,index,offsets,n,heap) \
+ rec_get_offsets_func(rec,index,offsets,n,__FILE__,__LINE__,heap)
+#else /* UNIV_DEBUG */
+# define rec_get_offsets(rec, index, offsets, n, heap) \
+ rec_get_offsets_func(rec, index, offsets, n, heap)
+#endif /* UNIV_DEBUG */
/******************************************************//**
The following function determines the offsets to each field
diff --git a/storage/xtradb/include/row0log.h b/storage/xtradb/include/row0log.h
index 41dac63963d..62715fe8808 100644
--- a/storage/xtradb/include/row0log.h
+++ b/storage/xtradb/include/row0log.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2011, 2014, 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
@@ -122,10 +122,9 @@ row_log_table_delete(
dict_index_t* index, /*!< in/out: clustered index, S-latched
or X-latched */
const ulint* offsets,/*!< in: rec_get_offsets(rec,index) */
- bool purge, /*!< in: true=purging BLOBs */
- trx_id_t trx_id) /*!< in: DB_TRX_ID of the record before
- it was deleted */
- UNIV_COLD __attribute__((nonnull));
+ const byte* sys) /*!< in: DB_TRX_ID,DB_ROLL_PTR that should
+ be logged, or NULL to use those in rec */
+ UNIV_COLD __attribute__((nonnull(1,2,3)));
/******************************************************//**
Logs an update operation to a table that is being rebuilt.
@@ -158,8 +157,10 @@ row_log_table_get_pk(
or X-latched */
const ulint* offsets,/*!< in: rec_get_offsets(rec,index),
or NULL */
+ byte* sys, /*!< out: DB_TRX_ID,DB_ROLL_PTR for
+ row_log_table_delete(), or NULL */
mem_heap_t** heap) /*!< in/out: memory heap where allocated */
- UNIV_COLD __attribute__((nonnull(1,2,4), warn_unused_result));
+ UNIV_COLD __attribute__((nonnull(1,2,5), warn_unused_result));
/******************************************************//**
Logs an insert to a table that is being rebuilt.
diff --git a/storage/xtradb/include/srv0srv.h b/storage/xtradb/include/srv0srv.h
index d278782daa8..d7e77842b75 100644
--- a/storage/xtradb/include/srv0srv.h
+++ b/storage/xtradb/include/srv0srv.h
@@ -1,8 +1,9 @@
/*****************************************************************************
-Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, 2009, Google Inc.
Copyright (c) 2009, Percona Inc.
+Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -452,8 +453,8 @@ expected. */
extern ulint srv_read_views_memory;
extern ulint srv_descriptors_memory;
-extern ibool srv_print_innodb_monitor;
-extern ibool srv_print_innodb_lock_monitor;
+extern my_bool srv_print_innodb_monitor;
+extern my_bool srv_print_innodb_lock_monitor;
extern ibool srv_print_innodb_tablespace_monitor;
extern ibool srv_print_verbose_log;
#define DEPRECATED_MSG_INNODB_TABLE_MONITOR \
@@ -527,6 +528,9 @@ extern const char* srv_io_thread_function[];
/* The tid of the cleaner thread */
extern os_tid_t srv_cleaner_tid;
+/* The tid of the LRU manager thread */
+extern os_tid_t srv_lru_manager_tid;
+
/* The tids of the purge threads */
extern os_tid_t srv_purge_tids[];
@@ -536,7 +540,7 @@ extern os_tid_t srv_io_tids[];
/* The tid of the master thread */
extern os_tid_t srv_master_tid;
-/* The relative scheduling priority of the cleaner thread */
+/* The relative scheduling priority of the cleaner and LRU manager threads */
extern ulint srv_sched_priority_cleaner;
/* The relative scheduling priority of the purge threads */
@@ -584,10 +588,13 @@ extern srv_stats_t srv_stats;
When FALSE, row locks are not taken at all. */
extern my_bool srv_fake_changes_locks;
+/** Simulate compression failures. */
+extern uint srv_simulate_comp_failures;
# ifdef UNIV_PFS_THREAD
/* Keys to register InnoDB threads with performance schema */
extern mysql_pfs_key_t buf_page_cleaner_thread_key;
+extern mysql_pfs_key_t buf_lru_manager_thread_key;
extern mysql_pfs_key_t trx_rollback_clean_thread_key;
extern mysql_pfs_key_t io_handler_thread_key;
extern mysql_pfs_key_t srv_lock_timeout_thread_key;
diff --git a/storage/xtradb/include/sync0rw.h b/storage/xtradb/include/sync0rw.h
index a215d4d3f60..cf239d78eb1 100644
--- a/storage/xtradb/include/sync0rw.h
+++ b/storage/xtradb/include/sync0rw.h
@@ -109,14 +109,8 @@ extern ib_mutex_t rw_lock_list_mutex;
#ifdef UNIV_SYNC_DEBUG
/* The global mutex which protects debug info lists of all rw-locks.
To modify the debug info list of an rw-lock, this mutex has to be
-
acquired in addition to the mutex protecting the lock. */
-extern ib_mutex_t rw_lock_debug_mutex;
-extern os_event_t rw_lock_debug_event; /*!< If deadlock detection does
- not get immediately the mutex it
- may wait for this event */
-extern ibool rw_lock_debug_waiters; /*!< This is set to TRUE, if
- there may be waiters for the event */
+extern os_fast_mutex_t rw_lock_debug_mutex;
#endif /* UNIV_SYNC_DEBUG */
/** Counters for RW locks. */
@@ -182,6 +176,9 @@ unlocking, not the corresponding function. */
# define rw_lock_s_lock_gen(M, P) \
rw_lock_s_lock_func((M), (P), __FILE__, __LINE__)
+# define rw_lock_s_lock_gen_nowait(M, P) \
+ rw_lock_s_lock_low((M), (P), __FILE__, __LINE__)
+
# define rw_lock_s_lock_nowait(M, F, L) \
rw_lock_s_lock_low((M), 0, (F), (L))
@@ -244,6 +241,9 @@ unlocking, not the corresponding function. */
# define rw_lock_s_lock_gen(M, P) \
pfs_rw_lock_s_lock_func((M), (P), __FILE__, __LINE__)
+# define rw_lock_s_lock_gen_nowait(M, P) \
+ pfs_rw_lock_s_lock_low((M), (P), __FILE__, __LINE__)
+
# define rw_lock_s_lock_nowait(M, F, L) \
pfs_rw_lock_s_lock_low((M), 0, (F), (L))
diff --git a/storage/xtradb/include/sync0rw.ic b/storage/xtradb/include/sync0rw.ic
index 097adfded37..3511987dbb0 100644
--- a/storage/xtradb/include/sync0rw.ic
+++ b/storage/xtradb/include/sync0rw.ic
@@ -874,12 +874,15 @@ pfs_rw_lock_x_lock_func(
/* Record the entry of rw x lock request in performance schema */
locker = PSI_RWLOCK_CALL(start_rwlock_wrwait)(
- &state, lock->pfs_psi, PSI_RWLOCK_WRITELOCK, file_name, line);
+ &state, lock->pfs_psi, PSI_RWLOCK_WRITELOCK,
+ file_name, static_cast<uint>(line));
- rw_lock_x_lock_func(lock, pass, file_name, line);
+ rw_lock_x_lock_func(
+ lock, pass, file_name, static_cast<uint>(line));
- if (locker != NULL)
+ if (locker != NULL) {
PSI_RWLOCK_CALL(end_rwlock_wrwait)(locker, 0);
+ }
}
else
{
@@ -946,12 +949,15 @@ pfs_rw_lock_x_lock_func_nowait(
/* Record the entry of rw x lock request in performance schema */
locker = PSI_RWLOCK_CALL(start_rwlock_wrwait)(
- &state, lock->pfs_psi, PSI_RWLOCK_WRITELOCK, file_name, line);
+ &state, lock->pfs_psi, PSI_RWLOCK_WRITELOCK,
+ file_name, static_cast<uint>(line));
ret = rw_lock_x_lock_func_nowait(lock, file_name, line);
- if (locker != NULL)
- PSI_RWLOCK_CALL(end_rwlock_wrwait)(locker, ret);
+ if (locker != NULL) {
+ PSI_RWLOCK_CALL(end_rwlock_wrwait)(
+ locker, static_cast<int>(ret));
+ }
}
else
{
@@ -1021,12 +1027,14 @@ pfs_rw_lock_s_lock_func(
/* Instrumented to inform we are aquiring a shared rwlock */
locker = PSI_RWLOCK_CALL(start_rwlock_rdwait)(
- &state, lock->pfs_psi, PSI_RWLOCK_READLOCK, file_name, line);
+ &state, lock->pfs_psi, PSI_RWLOCK_READLOCK,
+ file_name, static_cast<uint>(line));
rw_lock_s_lock_func(lock, pass, file_name, line);
- if (locker != NULL)
+ if (locker != NULL) {
PSI_RWLOCK_CALL(end_rwlock_rdwait)(locker, 0);
+ }
}
else
{
@@ -1100,12 +1108,15 @@ pfs_rw_lock_s_lock_low(
/* Instrumented to inform we are aquiring a shared rwlock */
locker = PSI_RWLOCK_CALL(start_rwlock_rdwait)(
- &state, lock->pfs_psi, PSI_RWLOCK_READLOCK, file_name, line);
+ &state, lock->pfs_psi, PSI_RWLOCK_READLOCK,
+ file_name, static_cast<uint>(line));
ret = rw_lock_s_lock_low(lock, pass, file_name, line);
- if (locker != NULL)
- PSI_RWLOCK_CALL(end_rwlock_rdwait)(locker, ret);
+ if (locker != NULL) {
+ PSI_RWLOCK_CALL(end_rwlock_rdwait)(
+ locker, static_cast<int>(ret));
+ }
}
else
{
diff --git a/storage/xtradb/include/sync0sync.h b/storage/xtradb/include/sync0sync.h
index 19cfcddd1f5..788f765f919 100644
--- a/storage/xtradb/include/sync0sync.h
+++ b/storage/xtradb/include/sync0sync.h
@@ -984,6 +984,7 @@ struct ib_prio_mutex_t {
priority in the global wait array
waiting for this mutex to be
released. */
+ UT_LIST_NODE_T(ib_prio_mutex_t) list;
};
/** 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 d6a95156ff4..d6922da7852 100644
--- a/storage/xtradb/include/sync0sync.ic
+++ b/storage/xtradb/include/sync0sync.ic
@@ -111,10 +111,7 @@ mutex_reset_lock_word(
ib_mutex_t* mutex) /*!< in: mutex */
{
#if defined(HAVE_ATOMIC_BUILTINS)
- /* In theory __sync_lock_release should be used to release the lock.
- Unfortunately, it does not work properly alone. The workaround is
- that more conservative __sync_lock_test_and_set is used instead. */
- os_atomic_test_and_set_byte(&mutex->lock_word, 0);
+ os_atomic_lock_release_byte(&mutex->lock_word);
#else
mutex->lock_word = 0;
@@ -354,7 +351,8 @@ pfs_mutex_enter_func(
locker = PSI_MUTEX_CALL(start_mutex_wait)(
&state, mutex->pfs_psi,
- PSI_MUTEX_LOCK, file_name, line);
+ PSI_MUTEX_LOCK, file_name,
+ static_cast<uint>(line));
mutex_enter_func(mutex, file_name, line);
@@ -423,7 +421,8 @@ pfs_mutex_enter_nowait_func(
locker = PSI_MUTEX_CALL(start_mutex_wait)(
&state, mutex->pfs_psi,
- PSI_MUTEX_TRYLOCK, file_name, line);
+ PSI_MUTEX_TRYLOCK, file_name,
+ static_cast<uint>(line));
ret = mutex_enter_nowait_func(mutex, file_name, line);
diff --git a/storage/xtradb/include/trx0trx.h b/storage/xtradb/include/trx0trx.h
index 259fcd0cf6e..7d1074ceaeb 100644
--- a/storage/xtradb/include/trx0trx.h
+++ b/storage/xtradb/include/trx0trx.h
@@ -857,8 +857,7 @@ struct trx_t{
when trx->in_rw_trx_list. Initially
set to TRX_ID_MAX. */
- time_t start_time; /*!< time the trx object was created
- or the state last time became
+ time_t start_time; /*!< time the trx state last time became
TRX_STATE_ACTIVE */
trx_id_t id; /*!< transaction id */
XID xid; /*!< X/Open XA transaction
@@ -1020,6 +1019,11 @@ struct trx_t{
count of tables being flushed. */
/*------------------------------*/
+ THD* current_lock_mutex_owner;
+ /*!< If this is equal to current_thd,
+ then in innobase_kill_query() we know we
+ already hold the lock_sys->mutex. */
+ /*------------------------------*/
#ifdef UNIV_DEBUG
ulint start_line; /*!< Track where it was started from */
const char* start_file; /*!< Filename where it was started */
diff --git a/storage/xtradb/include/univ.i b/storage/xtradb/include/univ.i
index eaf2262481c..572788f7242 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 15
+#define INNODB_VERSION_BUGFIX 17
#ifndef PERCONA_INNODB_VERSION
-#define PERCONA_INNODB_VERSION 63.0
+#define PERCONA_INNODB_VERSION 65.0
#endif
/* Enable UNIV_LOG_ARCHIVE in XtraDB */
@@ -447,7 +447,7 @@ macro ULINTPF. */
# define UINT32PF "%I32u"
# define INT64PF "%I64d"
# define UINT64PF "%I64u"
-# define UINT64PFx "%016I64u"
+# define UINT64PFx "%016I64x"
# define DBUG_LSN_PF "%llu"
typedef __int64 ib_int64_t;
typedef unsigned __int64 ib_uint64_t;
diff --git a/storage/xtradb/include/ut0ut.h b/storage/xtradb/include/ut0ut.h
index 163dc23b363..0caf379d8fa 100644
--- a/storage/xtradb/include/ut0ut.h
+++ b/storage/xtradb/include/ut0ut.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2014, 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
@@ -51,6 +51,19 @@ Created 1/20/1994 Heikki Tuuri
/** Time stamp */
typedef time_t ib_time_t;
+/* In order to call a piece of code, when a function returns or when the
+scope ends, use this utility class. It will invoke the given function
+object in its destructor. */
+template<typename F>
+struct ut_when_dtor {
+ ut_when_dtor(F& p) : f(p) {}
+ ~ut_when_dtor() {
+ f();
+ }
+private:
+ F& f;
+};
+
#ifndef UNIV_HOTBACKUP
# if defined(HAVE_PAUSE_INSTRUCTION)
/* According to the gcc info page, asm volatile means that the
diff --git a/storage/xtradb/lock/lock0lock.cc b/storage/xtradb/lock/lock0lock.cc
index 3e60680882a..c5938509c22 100644
--- a/storage/xtradb/lock/lock0lock.cc
+++ b/storage/xtradb/lock/lock0lock.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2014, 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
@@ -49,6 +49,7 @@ Created 5/7/1996 Heikki Tuuri
#include "btr0btr.h"
#include "dict0boot.h"
#include <set>
+#include "mysql/plugin.h"
/* Restricts the length of search we will do in the waits-for
graph of transactions */
@@ -373,6 +374,11 @@ struct lock_stack_t {
ulint heap_no; /*!< heap number if rec lock */
};
+extern "C" void thd_report_wait_for(const MYSQL_THD thd, MYSQL_THD other_thd);
+extern "C" int thd_need_wait_for(const MYSQL_THD thd);
+extern "C"
+int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd);
+
/** Stack to use during DFS search. Currently only a single stack is required
because there is no parallel deadlock check. This stack is protected by
the lock_sys_t::mutex. */
@@ -388,6 +394,14 @@ UNIV_INTERN mysql_pfs_key_t lock_sys_mutex_key;
UNIV_INTERN mysql_pfs_key_t lock_sys_wait_mutex_key;
#endif /* UNIV_PFS_MUTEX */
+/* Buffer to collect THDs to report waits for. */
+struct thd_wait_reports {
+ struct thd_wait_reports *next; /*!< List link */
+ ulint used; /*!< How many elements in waitees[] */
+ trx_t *waitees[64]; /*!< Trxs for thd_report_wait_for() */
+};
+
+
#ifdef UNIV_DEBUG
UNIV_INTERN ibool lock_print_waits = FALSE;
@@ -854,16 +868,11 @@ lock_reset_lock_and_trx_wait(
/*=========================*/
lock_t* lock) /*!< in/out: record lock */
{
+ ut_ad(lock->trx->lock.wait_lock == lock);
ut_ad(lock_get_wait(lock));
ut_ad(lock_mutex_own());
- /* Reset the back pointer in trx to this waiting lock request */
- if (!(lock->type_mode & LOCK_CONV_BY_OTHER)) {
- ut_ad(lock->trx->lock.wait_lock == lock);
- lock->trx->lock.wait_lock = NULL;
- } else {
- ut_ad(lock_get_type_low(lock) == LOCK_REC);
- }
+ lock->trx->lock.wait_lock = NULL;
lock->type_mode &= ~LOCK_WAIT;
}
@@ -1021,6 +1030,32 @@ lock_rec_has_to_wait(
return(FALSE);
}
+ if ((type_mode & LOCK_GAP || lock_rec_get_gap(lock2)) &&
+ !thd_need_ordering_with(trx->mysql_thd,
+ lock2->trx->mysql_thd)) {
+ /* If the upper server layer has already decided on the
+ commit order between the transaction requesting the
+ lock and the transaction owning the lock, we do not
+ need to wait for gap locks. Such ordeering by the upper
+ server layer happens in parallel replication, where the
+ commit order is fixed to match the original order on the
+ master.
+
+ Such gap locks are mainly needed to get serialisability
+ between transactions so that they will be binlogged in
+ the correct order so that statement-based replication
+ will give the correct results. Since the right order
+ was already determined on the master, we do not need
+ to enforce it again here.
+
+ Skipping the locks is not essential for correctness,
+ since in case of deadlock we will just kill the later
+ transaction and retry it. But it can save some
+ unnecessary rollbacks and retries. */
+
+ return (FALSE);
+ }
+
return(TRUE);
}
@@ -1486,7 +1521,7 @@ lock_rec_has_expl(
const buf_block_t* block, /*!< in: buffer block containing
the record */
ulint heap_no,/*!< in: heap number of the record */
- const trx_t* trx) /*!< in: transaction */
+ trx_id_t trx_id) /*!< in: transaction id */
{
lock_t* lock;
@@ -1499,13 +1534,13 @@ lock_rec_has_expl(
lock != NULL;
lock = lock_rec_get_next(heap_no, lock)) {
- if (lock->trx == trx
+ if (lock->trx->id == trx_id
&& !lock_rec_get_insert_intention(lock)
- && !lock_is_wait_not_by_other(lock->type_mode)
&& lock_mode_stronger_or_eq(
lock_get_mode(lock),
static_cast<enum lock_mode>(
precise_mode & LOCK_MODE_MASK))
+ && !lock_get_wait(lock)
&& (!lock_rec_get_rec_not_gap(lock)
|| (precise_mode & LOCK_REC_NOT_GAP)
|| heap_no == PAGE_HEAP_NO_SUPREMUM)
@@ -1524,7 +1559,7 @@ lock_rec_has_expl(
/*********************************************************************//**
Checks if some other transaction has a lock request in the queue.
@return lock or NULL */
-static
+static __attribute__((nonnull, warn_unused_result))
const lock_t*
lock_rec_other_has_expl_req(
/*========================*/
@@ -1538,9 +1573,7 @@ lock_rec_other_has_expl_req(
const buf_block_t* block, /*!< in: buffer block containing
the record */
ulint heap_no,/*!< in: heap number of the record */
- const trx_t* trx) /*!< in: transaction, or NULL if
- requests by all transactions
- are taken into account */
+ trx_id_t trx_id) /*!< in: transaction */
{
const lock_t* lock;
@@ -1553,7 +1586,7 @@ lock_rec_other_has_expl_req(
lock != NULL;
lock = lock_rec_get_next_const(heap_no, lock)) {
- if (lock->trx != trx
+ if (lock->trx->id != trx_id
&& (gap
|| !(lock_rec_get_gap(lock)
|| heap_no == PAGE_HEAP_NO_SUPREMUM))
@@ -1689,6 +1722,69 @@ lock_sec_rec_some_has_impl(
return(trx_id);
}
+#ifdef UNIV_DEBUG
+/*********************************************************************//**
+Checks if some transaction, other than given trx_id, has an explicit
+lock on the given rec, in the given precise_mode.
+@return the transaction, whose id is not equal to trx_id, that has an
+explicit lock on the given rec, in the given precise_mode or NULL.*/
+static
+trx_t*
+lock_rec_other_trx_holds_expl(
+/*==========================*/
+ ulint precise_mode, /*!< in: LOCK_S or LOCK_X
+ possibly ORed to LOCK_GAP or
+ LOCK_REC_NOT_GAP. */
+ trx_id_t trx_id, /*!< in: trx holding implicit
+ lock on rec */
+ const rec_t* rec, /*!< in: user record */
+ const buf_block_t* block) /*!< in: buffer block
+ containing the record */
+{
+ trx_t* holds = NULL;
+
+ lock_mutex_enter();
+ mutex_enter(&trx_sys->mutex);
+
+ trx_id_t* impl_trx_desc = trx_find_descriptor(trx_sys->descriptors,
+ trx_sys->descr_n_used,
+ trx_id);
+ if (impl_trx_desc) {
+ ut_ad(trx_id == *impl_trx_desc);
+ ulint heap_no = page_rec_get_heap_no(rec);
+ ulint rw_trx_count = trx_sys->descr_n_used;
+ trx_id_t* rw_trx_snapshot = static_cast<trx_id_t *>
+ (ut_malloc(sizeof(trx_id_t) * rw_trx_count));
+ memcpy(rw_trx_snapshot, trx_sys->descriptors,
+ sizeof(trx_id_t) * rw_trx_count);
+
+ mutex_exit(&trx_sys->mutex);
+
+ for (ulint i = 0; i < rw_trx_count; i++) {
+
+ lock_t* expl_lock = lock_rec_has_expl(precise_mode,
+ block, heap_no,
+ rw_trx_snapshot[i]);
+ if (expl_lock && expl_lock->trx->id != trx_id) {
+ /* An explicit lock is held by trx other than
+ the trx holding the implicit lock. */
+ holds = expl_lock->trx;
+ break;
+ }
+ }
+
+ ut_free(rw_trx_snapshot);
+
+ } else {
+ mutex_exit(&trx_sys->mutex);
+ }
+
+ lock_mutex_exit();
+
+ return(holds);
+}
+#endif /* UNIV_DEBUG */
+
/*********************************************************************//**
Return approximate number or record locks (bits set in the bitmap) for
this transaction. Since delete-marked records may be removed, the
@@ -1815,7 +1911,7 @@ lock_rec_create(
}
ut_ad(trx_mutex_own(trx));
- if (lock_is_wait_not_by_other(type_mode)) {
+ if (type_mode & LOCK_WAIT) {
lock_set_lock_and_trx_wait(lock, trx);
}
@@ -1855,12 +1951,11 @@ lock_rec_enqueue_waiting(
const buf_block_t* block, /*!< in: buffer block containing
the record */
ulint heap_no,/*!< in: heap number of the record */
- lock_t* lock, /*!< in: lock object; NULL if a new
- one should be created. */
dict_index_t* index, /*!< in: index of record */
que_thr_t* thr) /*!< in: query thread */
{
trx_t* trx;
+ lock_t* lock;
trx_id_t victim_trx_id;
ulint sec;
ulint ms;
@@ -1901,20 +1996,10 @@ lock_rec_enqueue_waiting(
ut_ad(0);
}
- if (lock == NULL) {
- /* Enqueue the lock request that will wait
- to be granted, note that we already own
- the trx mutex. */
- lock = lock_rec_create(
- type_mode | LOCK_WAIT, block, heap_no,
- index, trx, TRUE);
- } else {
- ut_ad(lock->type_mode & LOCK_WAIT);
- ut_ad(lock->type_mode & LOCK_CONV_BY_OTHER);
-
- lock->type_mode &= ~LOCK_CONV_BY_OTHER;
- lock_set_lock_and_trx_wait(lock, trx);
- }
+ /* Enqueue the lock request that will wait to be granted, note that
+ we already own the trx mutex. */
+ lock = lock_rec_create(
+ type_mode | LOCK_WAIT, block, heap_no, index, trx, TRUE);
/* Release the mutex to obey the latching order.
This is safe, because lock_deadlock_check_and_resolve()
@@ -2018,7 +2103,7 @@ lock_rec_add_to_queue(
: LOCK_S;
const lock_t* other_lock
= lock_rec_other_has_expl_req(mode, 0, LOCK_WAIT,
- block, heap_no, trx);
+ block, heap_no, trx->id);
ut_a(!other_lock);
}
#endif /* UNIV_DEBUG */
@@ -2190,7 +2275,6 @@ lock_rec_lock_slow(
que_thr_t* thr) /*!< in: query thread */
{
trx_t* trx;
- lock_t* lock;
dberr_t err = DB_SUCCESS;
ut_ad(lock_mutex_own());
@@ -2210,26 +2294,7 @@ lock_rec_lock_slow(
trx = thr_get_trx(thr);
trx_mutex_enter(trx);
- lock = lock_rec_has_expl(mode, block, heap_no, trx);
- if (lock) {
- if (lock->type_mode & LOCK_CONV_BY_OTHER) {
- /* This lock or lock waiting was created by the other
- transaction, not by the transaction (trx) itself.
- So, the transaction (trx) should treat it collectly
- according as whether granted or not. */
-
- if (lock->type_mode & LOCK_WAIT) {
- /* This lock request was not granted yet.
- Should wait for granted. */
-
- goto enqueue_waiting;
- } else {
- /* This lock request was already granted.
- Just clearing the flag. */
-
- lock->type_mode &= ~LOCK_CONV_BY_OTHER;
- }
- }
+ if (lock_rec_has_expl(mode, block, heap_no, trx->id)) {
/* The trx already has a strong enough lock on rec: do
nothing */
@@ -2243,10 +2308,8 @@ lock_rec_lock_slow(
have a lock strong enough already granted on the
record, we have to wait. */
- ut_ad(lock == NULL);
-enqueue_waiting:
err = lock_rec_enqueue_waiting(
- mode, block, heap_no, lock, index, thr);
+ mode, block, heap_no, index, thr);
} else if (!impl) {
/* Set the requested lock on the record, note that
@@ -2341,7 +2404,7 @@ lock_rec_has_to_wait_in_queue(
heap_no = lock_rec_find_set_bit(wait_lock);
bit_offset = heap_no / 8;
- bit_mask = 1 << (heap_no % 8);
+ bit_mask = static_cast<ulint>(1 << (heap_no % 8));
for (lock = lock_rec_get_first_on_page_addr(space, page_no);
lock != wait_lock;
@@ -2401,8 +2464,7 @@ lock_grant(
TRX_QUE_LOCK_WAIT state, and there is no need to end the lock wait
for it */
- if (!(lock->type_mode & LOCK_CONV_BY_OTHER)
- && lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
+ if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
que_thr_t* thr;
thr = que_thr_end_lock_wait(lock->trx);
@@ -2429,7 +2491,6 @@ lock_rec_cancel(
ut_ad(lock_mutex_own());
ut_ad(lock_get_type_low(lock) == LOCK_REC);
- ut_ad(!(lock->type_mode & LOCK_CONV_BY_OTHER));
/* Reset the bit (there can be only one set bit) in the lock bitmap */
lock_rec_reset_nth_bit(lock, lock_rec_find_set_bit(lock));
@@ -2598,12 +2659,8 @@ lock_rec_reset_and_release_wait(
lock != NULL;
lock = lock_rec_get_next(heap_no, lock)) {
- if (lock_is_wait_not_by_other(lock->type_mode)) {
+ if (lock_get_wait(lock)) {
lock_rec_cancel(lock);
- } else if (lock_get_wait(lock)) {
- /* just reset LOCK_WAIT */
- lock_rec_reset_nth_bit(lock, heap_no);
- lock_reset_lock_and_trx_wait(lock);
} else {
lock_rec_reset_nth_bit(lock, heap_no);
}
@@ -3804,7 +3861,8 @@ static
trx_id_t
lock_deadlock_search(
/*=================*/
- lock_deadlock_ctx_t* ctx) /*!< in/out: deadlock context */
+ lock_deadlock_ctx_t* ctx, /*!< in/out: deadlock context */
+ struct thd_wait_reports*waitee_ptr) /*!< in/out: list of waitees */
{
const lock_t* lock;
ulint heap_no;
@@ -3879,38 +3937,64 @@ lock_deadlock_search(
/* Select the joining transaction as the victim. */
return(ctx->start->id);
- } else if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
+ } else {
+ /* We do not need to report autoinc locks to the upper
+ layer. These locks are released before commit, so they
+ can not cause deadlocks with binlog-fixed commit
+ order. */
+ if (waitee_ptr &&
+ (lock_get_type_low(lock) != LOCK_TABLE ||
+ lock_get_mode(lock) != LOCK_AUTO_INC)) {
+ if (waitee_ptr->used ==
+ sizeof(waitee_ptr->waitees) /
+ sizeof(waitee_ptr->waitees[0])) {
+ waitee_ptr->next =
+ (struct thd_wait_reports *)
+ mem_alloc(sizeof(*waitee_ptr));
+ waitee_ptr = waitee_ptr->next;
+ if (!waitee_ptr) {
+ ctx->too_deep = TRUE;
+ return(ctx->start->id);
+ }
+ waitee_ptr->next = NULL;
+ waitee_ptr->used = 0;
+ }
+ waitee_ptr->waitees[waitee_ptr->used++] = lock->trx;
+ }
- /* Another trx ahead has requested a lock in an
- incompatible mode, and is itself waiting for a lock. */
+ if (lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
- ++ctx->cost;
+ /* Another trx ahead has requested a lock in an
+ incompatible mode, and is itself waiting for a lock. */
- /* Save current search state. */
- if (!lock_deadlock_push(ctx, lock, heap_no)) {
+ ++ctx->cost;
- /* Unable to save current search state, stack
- size not big enough. */
+ /* Save current search state. */
+ if (!lock_deadlock_push(ctx, lock, heap_no)) {
- ctx->too_deep = TRUE;
+ /* Unable to save current search state, stack
+ size not big enough. */
- return(ctx->start->id);
- }
+ ctx->too_deep = TRUE;
+
+ return(ctx->start->id);
+ }
- ctx->wait_lock = lock->trx->lock.wait_lock;
- lock = lock_get_first_lock(ctx, &heap_no);
+ ctx->wait_lock = lock->trx->lock.wait_lock;
+ lock = lock_get_first_lock(ctx, &heap_no);
- if (lock->trx->lock.deadlock_mark > ctx->mark_start) {
+ if (lock->trx->lock.deadlock_mark > ctx->mark_start) {
+ lock = lock_get_next_lock(ctx, lock, heap_no);
+ }
+
+ } else {
lock = lock_get_next_lock(ctx, lock, heap_no);
}
-
- } else {
- lock = lock_get_next_lock(ctx, lock, heap_no);
}
}
ut_a(lock == NULL && ctx->depth == 0);
-
+
/* No deadlock found. */
return(0);
}
@@ -3970,6 +4054,48 @@ lock_deadlock_trx_rollback(
trx_mutex_exit(trx);
}
+static
+void
+lock_report_waiters_to_mysql(
+/*=======================*/
+ struct thd_wait_reports* waitee_buf_ptr, /*!< in: set of trxs */
+ THD* mysql_thd, /*!< in: THD */
+ trx_id_t victim_trx_id) /*!< in: Trx selected
+ as deadlock victim, if
+ any */
+{
+ struct thd_wait_reports* p;
+ struct thd_wait_reports* q;
+ ulint i;
+
+ p = waitee_buf_ptr;
+ while (p) {
+ i = 0;
+ while (i < p->used) {
+ trx_t *w_trx = p->waitees[i];
+ /* There is no need to report waits to a trx already
+ selected as a victim. */
+ if (w_trx->id != victim_trx_id) {
+ /* If thd_report_wait_for() decides to kill the
+ transaction, then we will get a call back into
+ innobase_kill_query. We mark this by setting
+ current_lock_mutex_owner, so we can avoid trying
+ to recursively take lock_sys->mutex. */
+ w_trx->current_lock_mutex_owner = mysql_thd;
+ thd_report_wait_for(mysql_thd, w_trx->mysql_thd);
+ w_trx->current_lock_mutex_owner = NULL;
+ }
+ ++i;
+ }
+ q = p->next;
+ if (p != waitee_buf_ptr) {
+ mem_free(p);
+ }
+ p = q;
+ }
+}
+
+
/********************************************************************//**
Checks if a joining lock request results in a deadlock. If a deadlock is
found this function will resolve the dadlock by choosing a victim transaction
@@ -3985,13 +4111,23 @@ lock_deadlock_check_and_resolve(
const lock_t* lock, /*!< in: lock the transaction is requesting */
const trx_t* trx) /*!< in: transaction */
{
- trx_id_t victim_trx_id;
+ trx_id_t victim_trx_id;
+ struct thd_wait_reports waitee_buf;
+ struct thd_wait_reports*waitee_buf_ptr;
+ THD* start_mysql_thd;
ut_ad(trx != NULL);
ut_ad(lock != NULL);
ut_ad(lock_mutex_own());
assert_trx_in_list(trx);
+ start_mysql_thd = trx->mysql_thd;
+ if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) {
+ waitee_buf_ptr = &waitee_buf;
+ } else {
+ waitee_buf_ptr = NULL;
+ }
+
/* Try and resolve as many deadlocks as possible. */
do {
lock_deadlock_ctx_t ctx;
@@ -4004,7 +4140,19 @@ lock_deadlock_check_and_resolve(
ctx.wait_lock = lock;
ctx.mark_start = lock_mark_counter;
- victim_trx_id = lock_deadlock_search(&ctx);
+ if (waitee_buf_ptr) {
+ waitee_buf_ptr->next = NULL;
+ waitee_buf_ptr->used = 0;
+ }
+
+ victim_trx_id = lock_deadlock_search(&ctx, waitee_buf_ptr);
+
+ /* Report waits to upper layer, as needed. */
+ if (waitee_buf_ptr) {
+ lock_report_waiters_to_mysql(waitee_buf_ptr,
+ start_mysql_thd,
+ victim_trx_id);
+ }
/* Search too deep, we rollback the joining transaction. */
if (ctx.too_deep) {
@@ -4065,7 +4213,6 @@ lock_table_create(
ut_ad(table && trx);
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(trx));
- ut_ad(!(type_mode & LOCK_CONV_BY_OTHER));
/* Non-locking autocommit read-only transactions should not set
any locks. */
@@ -5206,11 +5353,14 @@ lock_print_info_summary(
the state of the variable for display. */
switch (purge_sys->state){
- case PURGE_STATE_EXIT:
case PURGE_STATE_INIT:
/* Should never be in this state while the system is running. */
ut_error;
+ case PURGE_STATE_EXIT:
+ fprintf(file, "exited");
+ break;
+
case PURGE_STATE_DISABLED:
fprintf(file, "disabled");
break;
@@ -5544,7 +5694,6 @@ lock_rec_queue_validate(
const dict_index_t* index, /*!< in: index, or NULL if not known */
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
{
- const trx_t* impl_trx;
const lock_t* lock;
ulint heap_no;
@@ -5586,23 +5735,27 @@ lock_rec_queue_validate(
if (!index);
else if (dict_index_is_clust(index)) {
trx_id_t trx_id;
+ trx_id_t* trx_desc;
/* Unlike the non-debug code, this invariant can only succeed
if the check and assertion are covered by the lock mutex. */
trx_id = lock_clust_rec_some_has_impl(rec, index, offsets);
- impl_trx = trx_rw_get_active_trx_by_id(trx_id, NULL);
+ trx_desc = trx_find_descriptor(trx_sys->descriptors,
+ trx_sys->descr_n_used,
+ trx_id);
ut_ad(lock_mutex_own());
- /* impl_trx cannot be committed until lock_mutex_exit()
+ /* trx_id cannot be committed until lock_mutex_exit()
because lock_trx_release_locks() acquires lock_sys->mutex */
- if (impl_trx != NULL
+ if (trx_desc != NULL
&& lock_rec_other_has_expl_req(LOCK_S, 0, LOCK_WAIT,
- block, heap_no, impl_trx)) {
+ block, heap_no, trx_id)) {
+ ut_ad(trx_id == *trx_desc);
ut_a(lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP,
- block, heap_no, impl_trx));
+ block, heap_no, trx_id));
}
}
@@ -5626,7 +5779,8 @@ lock_rec_queue_validate(
mode = LOCK_S;
}
ut_a(!lock_rec_other_has_expl_req(
- mode, 0, 0, block, heap_no, lock->trx));
+ mode, 0, 0, block, heap_no,
+ lock->trx->id));
} else if (lock_get_wait(lock) && !lock_rec_get_gap(lock)) {
@@ -6001,7 +6155,7 @@ lock_rec_insert_check_and_lock(
err = lock_rec_enqueue_waiting(
LOCK_X | LOCK_GAP | LOCK_INSERT_INTENTION,
- block, next_rec_heap_no, NULL, index, thr);
+ block, next_rec_heap_no, index, thr);
trx_mutex_exit(trx);
} else {
@@ -6079,11 +6233,14 @@ lock_rec_convert_impl_to_expl(
/* The transaction can be committed before the
trx_is_active(trx_id, NULL) check below, because we are not
holding lock_mutex. */
+
+ ut_ad(!lock_rec_other_trx_holds_expl(LOCK_S | LOCK_REC_NOT_GAP,
+ trx_id, rec, block));
}
if (trx_id != 0) {
- trx_t* impl_trx;
- ulint heap_no = page_rec_get_heap_no(rec);
+ trx_id_t* impl_trx_desc;
+ ulint heap_no = page_rec_get_heap_no(rec);
lock_mutex_enter();
@@ -6091,31 +6248,25 @@ lock_rec_convert_impl_to_expl(
explicit x-lock set on the record, set one for it */
mutex_enter(&trx_sys->mutex);
- impl_trx = trx_rw_get_active_trx_by_id(trx_id, NULL);
+ impl_trx_desc = trx_find_descriptor(trx_sys->descriptors,
+ trx_sys->descr_n_used,
+ trx_id);
mutex_exit(&trx_sys->mutex);
- /* impl_trx cannot be committed until lock_mutex_exit()
+ /* trx_id cannot be committed until lock_mutex_exit()
because lock_trx_release_locks() acquires lock_sys->mutex */
- if (impl_trx != NULL
+ if (impl_trx_desc != NULL
&& !lock_rec_has_expl(LOCK_X | LOCK_REC_NOT_GAP, block,
- heap_no, impl_trx)) {
+ heap_no, trx_id)) {
ulint type_mode = (LOCK_REC | LOCK_X
| LOCK_REC_NOT_GAP);
- /* If the delete-marked record was locked already,
- we should reserve lock waiting for impl_trx as
- implicit lock. Because cannot lock at this moment.*/
-
- if (rec_get_deleted_flag(rec, rec_offs_comp(offsets))
- && lock_rec_other_has_conflicting(
- static_cast<enum lock_mode>
- (LOCK_X | LOCK_REC_NOT_GAP), block,
- heap_no, impl_trx)) {
-
- type_mode |= (LOCK_WAIT
- | LOCK_CONV_BY_OTHER);
- }
+ mutex_enter(&trx_sys->mutex);
+ trx_t* impl_trx = trx_rw_get_active_trx_by_id(trx_id,
+ NULL);
+ mutex_exit(&trx_sys->mutex);
+ ut_ad(impl_trx != NULL);
lock_rec_add_to_queue(
type_mode, block, heap_no, index,
@@ -6790,7 +6941,6 @@ lock_cancel_waiting_and_release(
ut_ad(lock_mutex_own());
ut_ad(trx_mutex_own(lock->trx));
- ut_ad(!(lock->type_mode & LOCK_CONV_BY_OTHER));
lock->trx->lock.cancel = TRUE;
@@ -7168,7 +7318,7 @@ lock_trx_has_rec_x_lock(
if (UNIV_LIKELY(srv_fake_changes_locks)) {
ut_a(lock_rec_has_expl(rec_lock | LOCK_REC_NOT_GAP,
- block, heap_no, trx));
+ block, heap_no, trx->id));
}
lock_mutex_exit();
return(true);
diff --git a/storage/xtradb/log/log0recv.cc b/storage/xtradb/log/log0recv.cc
index cb4b988e46c..0db2b6ef5ed 100644
--- a/storage/xtradb/log/log0recv.cc
+++ b/storage/xtradb/log/log0recv.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2014, 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
@@ -24,6 +24,11 @@ Recovery
Created 9/20/1997 Heikki Tuuri
*******************************************************/
+// First include (the generated) my_config.h, to get correct platform defines.
+#include "my_config.h"
+#include <stdio.h> // Solaris/x86 header file bug
+
+#include <vector>
#include "log0recv.h"
#ifdef UNIV_NONINL
@@ -59,6 +64,7 @@ Created 9/20/1997 Heikki Tuuri
# include "sync0sync.h"
#else /* !UNIV_HOTBACKUP */
+
/** This is set to FALSE if the backup was originally taken with the
ibbackup --include regexp option: then we do not want to create tables in
directories which were not included */
@@ -429,6 +435,9 @@ recv_sys_init(
recv_max_page_lsn = 0;
+ /* Call the constructor for recv_sys_t::dblwr member */
+ new (&recv_sys->dblwr) recv_dblwr_t();
+
mutex_exit(&(recv_sys->mutex));
}
@@ -1379,14 +1388,23 @@ recv_parse_or_apply_log_rec_body(
ptr = mlog_parse_string(ptr, end_ptr, page, page_zip);
break;
case MLOG_FILE_RENAME:
- ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type,
- (recv_recovery_is_on()
- ? space_id : 0), 0);
+ /* Do not rerun file-based log entries if this is
+ IO completion from a page read. */
+ if (page == NULL) {
+ ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type,
+ (recv_recovery_is_on()
+ ? space_id : 0), 0);
+ }
break;
case MLOG_FILE_CREATE:
case MLOG_FILE_DELETE:
case MLOG_FILE_CREATE2:
- ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, 0, 0);
+ /* Do not rerun file-based log entries if this is
+ IO completion from a page read. */
+ if (page == NULL) {
+ ptr = fil_op_log_parse_or_replay(ptr, end_ptr,
+ type, 0, 0);
+ }
break;
case MLOG_ZIP_WRITE_NODE_PTR:
ut_ad(!page || page_type == FIL_PAGE_INDEX);
@@ -3039,7 +3057,7 @@ recv_init_crash_recovery(void)
ib_logf(IB_LOG_LEVEL_INFO,
"from the doublewrite buffer...");
- buf_dblwr_init_or_restore_pages(TRUE);
+ buf_dblwr_process();
/* Spawn the background thread to flush dirty pages
from the buffer pools. */
@@ -3081,6 +3099,7 @@ recv_recovery_from_checkpoint_start_func(
byte* log_hdr_buf;
byte* log_hdr_buf_base = (byte*)alloca(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
dberr_t err;
+ ut_when_dtor<recv_dblwr_t> tmp(recv_sys->dblwr);
log_hdr_buf = static_cast<byte *>
(ut_align(log_hdr_buf_base, OS_FILE_LOG_BLOCK_SIZE));
@@ -3098,11 +3117,6 @@ recv_recovery_from_checkpoint_start_func(
# define LIMIT_LSN LSN_MAX
#endif /* UNIV_LOG_ARCHIVE */
- if (TYPE_CHECKPOINT) {
- recv_sys_create();
- recv_sys_init(buf_pool_get_curr_size());
- }
-
if (srv_force_recovery >= SRV_FORCE_NO_LOG_REDO) {
ib_logf(IB_LOG_LEVEL_INFO,
@@ -3352,11 +3366,6 @@ recv_recovery_from_checkpoint_start_func(
}
}
}
-
- if (!recv_needed_recovery && !srv_read_only_mode) {
- /* Init the doublewrite buffer memory structure */
- buf_dblwr_init_or_restore_pages(FALSE);
- }
}
/* We currently have only one log group */
@@ -4059,3 +4068,46 @@ recv_recovery_from_archive_finish(void)
recv_recovery_from_backup_on = FALSE;
}
#endif /* UNIV_LOG_ARCHIVE */
+
+
+void recv_dblwr_t::add(byte* page)
+{
+ pages.push_back(page);
+}
+
+byte* recv_dblwr_t::find_page(ulint space_id, ulint page_no)
+{
+ std::vector<byte*> matches;
+ byte* result = 0;
+
+ for (std::list<byte*>::iterator i = pages.begin();
+ i != pages.end(); ++i) {
+
+ if ((page_get_space_id(*i) == space_id)
+ && (page_get_page_no(*i) == page_no)) {
+ matches.push_back(*i);
+ }
+ }
+
+ if (matches.size() == 1) {
+ result = matches[0];
+ } else if (matches.size() > 1) {
+
+ lsn_t max_lsn = 0;
+ lsn_t page_lsn = 0;
+
+ for (std::vector<byte*>::iterator i = matches.begin();
+ i != matches.end(); ++i) {
+
+ page_lsn = mach_read_from_8(*i + FIL_PAGE_LSN);
+
+ if (page_lsn > max_lsn) {
+ max_lsn = page_lsn;
+ result = *i;
+ }
+ }
+ }
+
+ return(result);
+}
+
diff --git a/storage/xtradb/mem/mem0mem.cc b/storage/xtradb/mem/mem0mem.cc
index e0e6220f4d8..e066aff5b30 100644
--- a/storage/xtradb/mem/mem0mem.cc
+++ b/storage/xtradb/mem/mem0mem.cc
@@ -299,15 +299,17 @@ Creates a memory heap block where data can be allocated.
for MEM_HEAP_BTR_SEARCH type heaps) */
UNIV_INTERN
mem_block_t*
-mem_heap_create_block(
-/*==================*/
+mem_heap_create_block_func(
+/*=======================*/
mem_heap_t* heap, /*!< in: memory heap or NULL if first block
should be created */
ulint n, /*!< in: number of bytes needed for user data */
- ulint type, /*!< in: type of heap: MEM_HEAP_DYNAMIC or
- MEM_HEAP_BUFFER */
+#ifdef UNIV_DEBUG
const char* file_name,/*!< in: file name where created */
- ulint line) /*!< in: line where created */
+ ulint line, /*!< in: line where created */
+#endif /* UNIV_DEBUG */
+ ulint type) /*!< in: type of heap: MEM_HEAP_DYNAMIC or
+ MEM_HEAP_BUFFER */
{
#ifndef UNIV_HOTBACKUP
buf_block_t* buf_block = NULL;
@@ -368,8 +370,9 @@ mem_heap_create_block(
#endif /* !UNIV_HOTBACKUP */
block->magic_n = MEM_BLOCK_MAGIC_N;
- ut_strlcpy_rev(block->file_name, file_name, sizeof(block->file_name));
- block->line = line;
+ ut_d(ut_strlcpy_rev(block->file_name, file_name,
+ sizeof(block->file_name)));
+ ut_d(block->line = line);
#ifdef MEM_PERIODIC_CHECK
mutex_enter(&(mem_comm_pool->mutex));
diff --git a/storage/xtradb/mtr/mtr0log.cc b/storage/xtradb/mtr/mtr0log.cc
index 5335cb4c9ef..0660c819240 100644
--- a/storage/xtradb/mtr/mtr0log.cc
+++ b/storage/xtradb/mtr/mtr0log.cc
@@ -560,7 +560,7 @@ mlog_parse_index(
n = n_uniq = 1;
}
table = dict_mem_table_create("LOG_DUMMY", DICT_HDR_SPACE, n,
- comp ? DICT_TF_COMPACT : 0, 0);
+ comp ? DICT_TF_COMPACT : 0, 0, true);
ind = dict_mem_index_create("LOG_DUMMY", "LOG_DUMMY",
DICT_HDR_SPACE, 0, n);
ind->table = table;
diff --git a/storage/xtradb/os/os0file.cc b/storage/xtradb/os/os0file.cc
index 8c09beb3e9c..e81116874ec 100644
--- a/storage/xtradb/os/os0file.cc
+++ b/storage/xtradb/os/os0file.cc
@@ -563,8 +563,10 @@ os_file_get_last_error_low(
return(OS_FILE_INSUFFICIENT_RESOURCE);
} else if (err == ERROR_OPERATION_ABORTED) {
return(OS_FILE_OPERATION_ABORTED);
+ } else if (err == ERROR_ACCESS_DENIED) {
+ return(OS_FILE_ACCESS_VIOLATION);
} else {
- return(100 + err);
+ return(OS_FILE_ERROR_MAX + err);
}
#else
int err = errno;
@@ -638,8 +640,10 @@ os_file_get_last_error_low(
return(OS_FILE_AIO_INTERRUPTED);
}
break;
+ case EACCES:
+ return(OS_FILE_ACCESS_VIOLATION);
}
- return(100 + err);
+ return(OS_FILE_ERROR_MAX + err);
#endif
}
@@ -717,6 +721,7 @@ os_file_handle_error_cond_exit(
case OS_FILE_PATH_ERROR:
case OS_FILE_ALREADY_EXISTS:
+ case OS_FILE_ACCESS_VIOLATION:
return(FALSE);
@@ -2587,12 +2592,13 @@ os_file_pread(
os_mutex_exit(os_file_count_mutex);
#endif /* HAVE_ATOMIC_BUILTINS && UNIV_WORD == 8 */
- /* Handle signal interruptions correctly */
+ /* Handle partial reads and signal interruptions correctly */
for (n_bytes = 0; n_bytes < (ssize_t) n; ) {
- n_read = pread(file, buf, (ssize_t)n, offs);
+ n_read = pread(file, buf, (ssize_t)n - n_bytes, offs);
if (n_read > 0) {
n_bytes += n_read;
offs += n_read;
+ buf = (char *)buf + n_read;
} else if (n_read == -1 && errno == EINTR) {
continue;
} else {
@@ -2734,12 +2740,13 @@ os_file_pwrite(
MONITOR_ATOMIC_INC(MONITOR_OS_PENDING_WRITES);
#endif /* !HAVE_ATOMIC_BUILTINS || UNIV_WORD < 8 */
- /* Handle signal interruptions correctly */
+ /* Handle partial writes and signal interruptions correctly */
for (ret = 0; ret < (ssize_t) n; ) {
- n_written = pwrite(file, buf, (ssize_t)n, offs);
- if (n_written > 0) {
+ n_written = pwrite(file, buf, (ssize_t)n - ret, offs);
+ if (n_written >= 0) {
ret += n_written;
offs += n_written;
+ buf = (char *)buf + n_written;
} else if (n_written == -1 && errno == EINTR) {
continue;
} else {
@@ -3042,7 +3049,8 @@ os_file_write_func(
DWORD len;
ulint n_retries = 0;
ulint err;
- OVERLAPPED overlapped;
+ OVERLAPPED overlapped;
+ DWORD saved_error = 0;
/* On 64-bit Windows, ulint is 64 bits. But offset and n should be
no more than 32 bits. */
@@ -3069,7 +3077,7 @@ retry:
if (ret) {
ret = GetOverlappedResult(file, &overlapped, (DWORD *)&len, FALSE);
}
- else if(GetLastError() == ERROR_IO_PENDING) {
+ else if ( GetLastError() == ERROR_IO_PENDING) {
ret = GetOverlappedResult(file, &overlapped, (DWORD *)&len, TRUE);
}
@@ -3097,8 +3105,10 @@ retry:
}
if (!os_has_said_disk_full) {
+ char *winmsg = NULL;
- err = (ulint) GetLastError();
+ saved_error = GetLastError();
+ err = (ulint) saved_error;
ut_print_timestamp(stderr);
@@ -3115,6 +3125,23 @@ retry:
name, offset,
(ulong) n, (ulong) len, (ulong) err);
+ /* Ask Windows to prepare a standard message for a
+ GetLastError() */
+
+ FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, saved_error,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPSTR)&winmsg, 0, NULL);
+
+ if (winmsg) {
+ fprintf(stderr,
+ "InnoDB: FormatMessage: Error number %lu means '%s'.\n",
+ (ulong) saved_error, winmsg);
+ LocalFree(winmsg);
+ }
+
if (strerror((int) err) != NULL) {
fprintf(stderr,
"InnoDB: Error number %lu means '%s'.\n",
@@ -3333,30 +3360,41 @@ os_file_get_status(
return(DB_FAIL);
- } else if (S_ISDIR(statinfo.st_mode)) {
+ }
+
+ switch (statinfo.st_mode & S_IFMT) {
+ case S_IFDIR:
stat_info->type = OS_FILE_TYPE_DIR;
- } else if (S_ISLNK(statinfo.st_mode)) {
+ break;
+ case S_IFLNK:
stat_info->type = OS_FILE_TYPE_LINK;
- } else if (S_ISREG(statinfo.st_mode)) {
+ break;
+ case S_IFBLK:
+ stat_info->type = OS_FILE_TYPE_BLOCK;
+ break;
+ case S_IFREG:
stat_info->type = OS_FILE_TYPE_FILE;
+ break;
+ default:
+ stat_info->type = OS_FILE_TYPE_UNKNOWN;
+ }
- if (check_rw_perm) {
- int fh;
- int access;
- access = !srv_read_only_mode ? O_RDWR : O_RDONLY;
+ if (check_rw_perm && (stat_info->type == OS_FILE_TYPE_FILE
+ || stat_info->type == OS_FILE_TYPE_BLOCK)) {
+ int fh;
+ int access;
- fh = ::open(path, access, os_innodb_umask);
+ access = !srv_read_only_mode ? O_RDWR : O_RDONLY;
- if (fh == -1) {
- stat_info->rw_perm = false;
- } else {
- stat_info->rw_perm = true;
- close(fh);
- }
+ fh = ::open(path, access, os_innodb_umask);
+
+ if (fh == -1) {
+ stat_info->rw_perm = false;
+ } else {
+ stat_info->rw_perm = true;
+ close(fh);
}
- } else {
- stat_info->type = OS_FILE_TYPE_UNKNOWN;
}
#endif /* _WIN_ */
@@ -4702,8 +4740,10 @@ os_aio_func(
wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
mode = mode & (~OS_AIO_SIMULATED_WAKE_LATER);
- if (mode == OS_AIO_SYNC)
- {
+ DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
+ mode = OS_AIO_SYNC;);
+
+ if (mode == OS_AIO_SYNC) {
ibool ret;
/* This is actually an ordinary synchronous read or write:
no need to use an i/o-handler thread */
@@ -4717,7 +4757,18 @@ os_aio_func(
ret = os_file_write(name, file, buf, offset, n);
}
- ut_a(ret);
+
+ DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
+ os_has_said_disk_full = FALSE;);
+ DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
+ ret = 0;);
+ DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28",
+ errno = 28;);
+
+ if (!ret) {
+ fprintf(stderr, "FAIL");
+ }
+
return ret;
}
@@ -5154,6 +5205,7 @@ os_aio_linux_handle(
segment = os_aio_get_array_and_local_segment(&array, global_seg);
n = array->n_slots / array->n_segments;
+ wait_for_event:
/* Loop until we have found a completed request. */
for (;;) {
ibool any_reserved = FALSE;
@@ -5216,6 +5268,41 @@ found:
if (slot->ret == 0 && slot->n_bytes == (long) slot->len) {
ret = TRUE;
+ } else if ((slot->ret == 0) && (slot->n_bytes > 0)
+ && (slot->n_bytes < (long) slot->len)) {
+ /* Partial read or write scenario */
+ int submit_ret;
+ struct iocb* iocb;
+ slot->buf = (byte*)slot->buf + slot->n_bytes;
+ slot->offset = slot->offset + slot->n_bytes;
+ slot->len = slot->len - slot->n_bytes;
+ /* Resetting the bytes read/written */
+ slot->n_bytes = 0;
+ slot->io_already_done = FALSE;
+ iocb = &(slot->control);
+
+ if (slot->type == OS_FILE_READ) {
+ io_prep_pread(&slot->control, slot->file, slot->buf,
+ slot->len, (off_t) slot->offset);
+ } else {
+ ut_a(slot->type == OS_FILE_WRITE);
+ io_prep_pwrite(&slot->control, slot->file, slot->buf,
+ slot->len, (off_t) slot->offset);
+ }
+ /* Resubmit an I/O request */
+ submit_ret = io_submit(array->aio_ctx[segment], 1, &iocb);
+ if (submit_ret < 0 ) {
+ /* Aborting in case of submit failure */
+ ib_logf(IB_LOG_LEVEL_FATAL,
+ "Native Linux AIO interface. io_submit()"
+ " call failed when resubmitting a partial"
+ " I/O request on the file %s.",
+ slot->name);
+ } else {
+ ret = FALSE;
+ os_mutex_exit(array->mutex);
+ goto wait_for_event;
+ }
} else {
errno = -slot->ret;
@@ -5510,7 +5597,13 @@ consecutive_loop:
aio_slot->offset, total_len);
}
- ut_a(ret);
+ DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28_2",
+ os_has_said_disk_full = FALSE;);
+ DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28_2",
+ ret = 0;);
+ DBUG_EXECUTE_IF("ib_os_aio_func_io_failure_28_2",
+ errno = 28;);
+
srv_set_io_thread_op_info(global_segment, "file i/o done");
if (aio_slot->type == OS_FILE_READ && n_consecutive > 1) {
diff --git a/storage/xtradb/os/os0stacktrace.cc b/storage/xtradb/os/os0stacktrace.cc
index 4d52e625057..6d5b6781cc1 100644
--- a/storage/xtradb/os/os0stacktrace.cc
+++ b/storage/xtradb/os/os0stacktrace.cc
@@ -92,9 +92,9 @@ os_stacktrace_print(
#elif defined(__sparc__)
struct sigcontext* sc = (struct sigcontext*) ucontext;
#if __WORDSIZE == 64
- caller_address = (void*) scp->sigc_regs.tpc ;
+ caller_address = (void*) sc->sigc_regs.tpc ;
#else
- pnt = (void*) scp->si_regs.pc ;
+ caller_address = (void*) sc->si_regs.pc ;
#endif
#elif defined(__i386__)
ucontext_t* uc = (ucontext_t*) ucontext;
diff --git a/storage/xtradb/os/os0sync.cc b/storage/xtradb/os/os0sync.cc
index 392dbe0d7a7..e42c5900c0c 100644
--- a/storage/xtradb/os/os0sync.cc
+++ b/storage/xtradb/os/os0sync.cc
@@ -644,7 +644,7 @@ os_event_wait_time_low(
ut_a(event);
if (time_in_usec != OS_SYNC_INFINITE_TIME) {
- time_in_ms = time_in_usec / 1000;
+ time_in_ms = static_cast<DWORD>(time_in_usec / 1000);
err = WaitForSingleObject(event->handle, time_in_ms);
} else {
err = WaitForSingleObject(event->handle, INFINITE);
@@ -663,7 +663,7 @@ os_event_wait_time_low(
ut_a(sleep_condition_variable != NULL);
if (time_in_usec != OS_SYNC_INFINITE_TIME) {
- time_in_ms = time_in_usec / 1000;
+ time_in_ms = static_cast<DWORD>(time_in_usec / 1000);
} else {
time_in_ms = INFINITE;
}
diff --git a/storage/xtradb/page/page0cur.cc b/storage/xtradb/page/page0cur.cc
index efce1f10cae..f5f7e1299ce 100644
--- a/storage/xtradb/page/page0cur.cc
+++ b/storage/xtradb/page/page0cur.cc
@@ -977,7 +977,8 @@ page_cur_insert_rec_low(
== (ibool) !!page_is_comp(page));
ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX);
ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID)
- == index->id || recv_recovery_is_on() || mtr->inside_ibuf);
+ == index->id || recv_recovery_is_on()
+ || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index)));
ut_ad(!page_rec_is_supremum(current_rec));
@@ -1204,7 +1205,8 @@ page_cur_insert_rec_zip(
ut_ad(page_is_comp(page));
ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX);
ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID)
- == index->id || mtr->inside_ibuf || recv_recovery_is_on());
+ == index->id || recv_recovery_is_on()
+ || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index)));
ut_ad(!page_cur_is_after_last(cursor));
#ifdef UNIV_ZIP_DEBUG
@@ -1977,7 +1979,8 @@ page_cur_delete_rec(
const dict_index_t* index, /*!< in: record descriptor */
const ulint* offsets,/*!< in: rec_get_offsets(
cursor->rec, index) */
- mtr_t* mtr) /*!< in: mini-transaction handle */
+ mtr_t* mtr) /*!< in: mini-transaction handle
+ or NULL */
{
page_dir_slot_t* cur_dir_slot;
page_dir_slot_t* prev_slot;
@@ -2006,7 +2009,8 @@ page_cur_delete_rec(
ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
ut_ad(fil_page_get_type(page) == FIL_PAGE_INDEX);
ut_ad(mach_read_from_8(page + PAGE_HEADER + PAGE_INDEX_ID)
- == index->id || mtr->inside_ibuf || recv_recovery_is_on());
+ == index->id || recv_recovery_is_on()
+ || (mtr ? mtr->inside_ibuf : dict_index_is_ibuf(index)));
/* The record must not be the supremum or infimum record. */
ut_ad(page_rec_is_user_rec(current_rec));
diff --git a/storage/xtradb/page/page0page.cc b/storage/xtradb/page/page0page.cc
index 2faf804279c..bd5fb36af8f 100644
--- a/storage/xtradb/page/page0page.cc
+++ b/storage/xtradb/page/page0page.cc
@@ -2779,3 +2779,35 @@ page_delete_rec(
return(no_compress_needed);
}
+/** Get the last non-delete-marked record on a page.
+@param[in] page index tree leaf page
+@return the last record, not delete-marked
+@retval infimum record if all records are delete-marked */
+
+const rec_t*
+page_find_rec_max_not_deleted(
+ const page_t* page)
+{
+ const rec_t* rec = page_get_infimum_rec(page);
+ const rec_t* prev_rec = NULL; // remove warning
+
+ /* Because the page infimum is never delete-marked,
+ prev_rec will always be assigned to it first. */
+ ut_ad(!rec_get_deleted_flag(rec, page_rec_is_comp(rec)));
+ if (page_is_comp(page)) {
+ do {
+ if (!rec_get_deleted_flag(rec, true)) {
+ prev_rec = rec;
+ }
+ rec = page_rec_get_next_low(rec, true);
+ } while (rec != page + PAGE_NEW_SUPREMUM);
+ } else {
+ do {
+ if (!rec_get_deleted_flag(rec, false)) {
+ prev_rec = rec;
+ }
+ rec = page_rec_get_next_low(rec, false);
+ } while (rec != page + PAGE_OLD_SUPREMUM);
+ }
+ return(prev_rec);
+}
diff --git a/storage/xtradb/page/page0zip.cc b/storage/xtradb/page/page0zip.cc
index 81c9e0ab45a..c4c8354aa1e 100644
--- a/storage/xtradb/page/page0zip.cc
+++ b/storage/xtradb/page/page0zip.cc
@@ -1,7 +1,8 @@
/*****************************************************************************
-Copyright (c) 2005, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
+Copyright (c) 2014, SkySQL Ab. 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,6 +25,9 @@ Compressed page interface
Created June 2005 by Marko Makela
*******************************************************/
+// First include (the generated) my_config.h, to get correct platform defines.
+#include "my_config.h"
+
#include <map>
using namespace std;
@@ -168,7 +172,7 @@ page_zip_empty_size(
+ 1/* end of modification log */
- REC_N_NEW_EXTRA_BYTES/* omitted bytes */)
/* subtract the space for page_zip_fields_encode() */
- - compressBound(2 * (n_fields + 1));
+ - compressBound(static_cast<uLong>(2 * (n_fields + 1)));
return(size > 0 ? (ulint) size : 0);
}
#endif /* !UNIV_HOTBACKUP */
@@ -849,8 +853,8 @@ page_zip_compress_node_ptrs(
rec_offs_extra_size(offsets));
/* Compress the extra bytes. */
- c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
- - c_stream->next_in;
+ c_stream->avail_in = static_cast<uInt>(
+ rec - REC_N_NEW_EXTRA_BYTES - c_stream->next_in);
if (c_stream->avail_in) {
err = deflate(c_stream, Z_NO_FLUSH);
@@ -862,8 +866,8 @@ page_zip_compress_node_ptrs(
/* Compress the data bytes, except node_ptr. */
c_stream->next_in = (byte*) rec;
- c_stream->avail_in = rec_offs_data_size(offsets)
- - REC_NODE_PTR_SIZE;
+ c_stream->avail_in = static_cast<uInt>(
+ rec_offs_data_size(offsets) - REC_NODE_PTR_SIZE);
if (c_stream->avail_in) {
err = deflate(c_stream, Z_NO_FLUSH);
@@ -904,8 +908,9 @@ page_zip_compress_sec(
const rec_t* rec = *recs++;
/* Compress everything up to this record. */
- c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
- - c_stream->next_in;
+ c_stream->avail_in = static_cast<uInt>(
+ rec - REC_N_NEW_EXTRA_BYTES
+ - c_stream->next_in);
if (UNIV_LIKELY(c_stream->avail_in)) {
UNIV_MEM_ASSERT_RW(c_stream->next_in,
@@ -970,8 +975,8 @@ page_zip_compress_clust_ext(
ut_ad(len == DATA_ROLL_PTR_LEN);
/* Compress any preceding bytes. */
- c_stream->avail_in
- = src - c_stream->next_in;
+ c_stream->avail_in = static_cast<uInt>(
+ src - c_stream->next_in);
if (c_stream->avail_in) {
err = deflate(c_stream, Z_NO_FLUSH);
@@ -1000,8 +1005,8 @@ page_zip_compress_clust_ext(
ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
src += len - BTR_EXTERN_FIELD_REF_SIZE;
- c_stream->avail_in = src
- - c_stream->next_in;
+ c_stream->avail_in = static_cast<uInt>(
+ src - c_stream->next_in);
if (UNIV_LIKELY(c_stream->avail_in)) {
err = deflate(c_stream, Z_NO_FLUSH);
if (UNIV_UNLIKELY(err != Z_OK)) {
@@ -1096,8 +1101,9 @@ page_zip_compress_clust(
rec_offs_extra_size(offsets));
/* Compress the extra bytes. */
- c_stream->avail_in = rec - REC_N_NEW_EXTRA_BYTES
- - c_stream->next_in;
+ c_stream->avail_in = static_cast<uInt>(
+ rec - REC_N_NEW_EXTRA_BYTES
+ - c_stream->next_in);
if (c_stream->avail_in) {
err = deflate(c_stream, Z_NO_FLUSH);
@@ -1144,7 +1150,8 @@ page_zip_compress_clust(
rec_offs_extra_size(offsets));
/* Compress any preceding bytes. */
- c_stream->avail_in = src - c_stream->next_in;
+ c_stream->avail_in = static_cast<uInt>(
+ src - c_stream->next_in);
if (c_stream->avail_in) {
err = deflate(c_stream, Z_NO_FLUSH);
@@ -1171,8 +1178,8 @@ page_zip_compress_clust(
}
/* Compress the last bytes of the record. */
- c_stream->avail_in = rec + rec_offs_data_size(offsets)
- - c_stream->next_in;
+ c_stream->avail_in = static_cast<uInt>(
+ rec + rec_offs_data_size(offsets) - c_stream->next_in);
if (c_stream->avail_in) {
err = deflate(c_stream, Z_NO_FLUSH);
@@ -1307,6 +1314,30 @@ page_zip_compress(
MONITOR_INC(MONITOR_PAGE_COMPRESS);
+ /* Simulate a compression failure with a probability determined by
+ innodb_simulate_comp_failures, only if the page has 2 or more
+ records. */
+
+ if (srv_simulate_comp_failures
+ && !dict_index_is_ibuf(index)
+ && page_get_n_recs(page) >= 2
+ && ((ulint)(rand() % 100) < srv_simulate_comp_failures)
+ && strcasecmp(index->table_name, "IBUF_DUMMY") != 0) {
+
+#ifdef UNIV_DEBUG
+ fprintf(stderr,
+ "InnoDB: Simulating a compression failure"
+ " for table %s, index %s, page %lu (%s)\n",
+ index->table_name,
+ index->name,
+ page_get_page_no(page),
+ page_is_leaf(page) ? "leaf" : "non-leaf");
+
+#endif
+
+ goto err_exit;
+ }
+
heap = mem_heap_create(page_zip_get_size(page_zip)
+ n_fields * (2 + sizeof(ulint))
+ REC_OFFS_HEADER_SIZE
@@ -1328,7 +1359,7 @@ page_zip_compress(
/* Compress the data payload. */
page_zip_set_alloc(&c_stream, heap);
- err = deflateInit2(&c_stream, level,
+ err = deflateInit2(&c_stream, static_cast<int>(level),
Z_DEFLATED, UNIV_PAGE_SIZE_SHIFT,
MAX_MEM_LEVEL, Z_DEFAULT_STRATEGY);
ut_a(err == Z_OK);
@@ -1336,7 +1367,8 @@ page_zip_compress(
c_stream.next_out = buf;
/* Subtract the space reserved for uncompressed data. */
/* Page header and the end marker of the modification log */
- c_stream.avail_out = buf_end - buf - 1;
+ c_stream.avail_out = static_cast<uInt>(buf_end - buf - 1);
+
/* Dense page directory and uncompressed columns, if any */
if (page_is_leaf(page)) {
if (dict_index_is_clust(index)) {
@@ -1365,9 +1397,9 @@ page_zip_compress(
goto zlib_error;
}
- c_stream.avail_out -= n_dense * slot_size;
- c_stream.avail_in = page_zip_fields_encode(n_fields, index,
- trx_id_col, fields);
+ c_stream.avail_out -= static_cast<uInt>(n_dense * slot_size);
+ c_stream.avail_in = static_cast<uInt>(
+ page_zip_fields_encode(n_fields, index, trx_id_col, fields));
c_stream.next_in = fields;
if (UNIV_LIKELY(!trx_id_col)) {
trx_id_col = ULINT_UNDEFINED;
@@ -1422,9 +1454,9 @@ page_zip_compress(
/* Compress any trailing garbage, in case the last record was
allocated from an originally longer space on the free list,
or the data of the last record from page_zip_compress_sec(). */
- c_stream.avail_in
- = page_header_get_field(page, PAGE_HEAP_TOP)
- - (c_stream.next_in - page);
+ c_stream.avail_in = static_cast<uInt>(
+ page_header_get_field(page, PAGE_HEAP_TOP)
+ - (c_stream.next_in - page));
ut_a(c_stream.avail_in <= UNIV_PAGE_SIZE - PAGE_ZIP_START - PAGE_DIR);
UNIV_MEM_ASSERT_RW(c_stream.next_in, c_stream.avail_in);
@@ -1571,9 +1603,8 @@ page_zip_fields_free(
dict_table_t* table = index->table;
os_fast_mutex_free(&index->zip_pad.mutex);
mem_heap_free(index->heap);
- mutex_free(&(table->autoinc_mutex));
- ut_free(table->name);
- mem_heap_free(table->heap);
+
+ dict_mem_table_free(table);
}
}
@@ -1621,7 +1652,7 @@ page_zip_fields_decode(
}
table = dict_mem_table_create("ZIP_DUMMY", DICT_HDR_SPACE, n,
- DICT_TF_COMPACT, 0);
+ DICT_TF_COMPACT, 0, true);
index = dict_mem_index_create("ZIP_DUMMY", "ZIP_DUMMY",
DICT_HDR_SPACE, 0, n);
index->table = table;
@@ -2225,15 +2256,15 @@ page_zip_decompress_node_ptrs(
const byte* storage;
/* Subtract the space reserved for uncompressed data. */
- d_stream->avail_in -= n_dense
- * (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE);
+ d_stream->avail_in -= static_cast<uInt>(
+ n_dense * (PAGE_ZIP_DIR_SLOT_SIZE + REC_NODE_PTR_SIZE));
/* Decompress the records in heap_no order. */
for (slot = 0; slot < n_dense; slot++) {
rec_t* rec = recs[slot];
- d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
- - d_stream->next_out;
+ d_stream->avail_out = static_cast<uInt>(
+ rec - REC_N_NEW_EXTRA_BYTES - d_stream->next_out);
ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR);
@@ -2269,8 +2300,8 @@ page_zip_decompress_node_ptrs(
ut_ad(!rec_offs_any_extern(offsets));
/* Decompress the data bytes, except node_ptr. */
- d_stream->avail_out = rec_offs_data_size(offsets)
- - REC_NODE_PTR_SIZE;
+ d_stream->avail_out =static_cast<uInt>(
+ rec_offs_data_size(offsets) - REC_NODE_PTR_SIZE);
switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
@@ -2299,9 +2330,9 @@ page_zip_decompress_node_ptrs(
/* Decompress any trailing garbage, in case the last record was
allocated from an originally longer space on the free list. */
- d_stream->avail_out = page_header_get_field(page_zip->data,
- PAGE_HEAP_TOP)
- - page_offset(d_stream->next_out);
+ d_stream->avail_out = static_cast<uInt>(
+ page_header_get_field(page_zip->data, PAGE_HEAP_TOP)
+ - page_offset(d_stream->next_out));
if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR)) {
@@ -2414,14 +2445,15 @@ page_zip_decompress_sec(
ut_a(!dict_index_is_clust(index));
/* Subtract the space reserved for uncompressed data. */
- d_stream->avail_in -= n_dense * PAGE_ZIP_DIR_SLOT_SIZE;
+ d_stream->avail_in -= static_cast<uint>(
+ n_dense * PAGE_ZIP_DIR_SLOT_SIZE);
for (slot = 0; slot < n_dense; slot++) {
rec_t* rec = recs[slot];
/* Decompress everything up to this record. */
- d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
- - d_stream->next_out;
+ d_stream->avail_out = static_cast<uint>(
+ rec - REC_N_NEW_EXTRA_BYTES - d_stream->next_out);
if (UNIV_LIKELY(d_stream->avail_out)) {
switch (inflate(d_stream, Z_SYNC_FLUSH)) {
@@ -2452,9 +2484,9 @@ page_zip_decompress_sec(
/* Decompress the data of the last record and any trailing garbage,
in case the last record was allocated from an originally longer space
on the free list. */
- d_stream->avail_out = page_header_get_field(page_zip->data,
- PAGE_HEAP_TOP)
- - page_offset(d_stream->next_out);
+ d_stream->avail_out = static_cast<uInt>(
+ page_header_get_field(page_zip->data, PAGE_HEAP_TOP)
+ - page_offset(d_stream->next_out));
if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR)) {
@@ -2567,7 +2599,8 @@ page_zip_decompress_clust_ext(
return(FALSE);
}
- d_stream->avail_out = dst - d_stream->next_out;
+ d_stream->avail_out = static_cast<uInt>(
+ dst - d_stream->next_out);
switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
@@ -2598,7 +2631,8 @@ page_zip_decompress_clust_ext(
ut_ad(len >= BTR_EXTERN_FIELD_REF_SIZE);
dst += len - BTR_EXTERN_FIELD_REF_SIZE;
- d_stream->avail_out = dst - d_stream->next_out;
+ d_stream->avail_out = static_cast<uInt>(
+ dst - d_stream->next_out);
switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
case Z_OK:
@@ -2664,16 +2698,17 @@ page_zip_decompress_clust(
ut_a(dict_index_is_clust(index));
/* Subtract the space reserved for uncompressed data. */
- d_stream->avail_in -= n_dense * (PAGE_ZIP_DIR_SLOT_SIZE
- + DATA_TRX_ID_LEN
- + DATA_ROLL_PTR_LEN);
+ d_stream->avail_in -= static_cast<uInt>(n_dense)
+ * (PAGE_ZIP_DIR_SLOT_SIZE
+ + DATA_TRX_ID_LEN
+ + DATA_ROLL_PTR_LEN);
/* Decompress the records in heap_no order. */
for (slot = 0; slot < n_dense; slot++) {
rec_t* rec = recs[slot];
- d_stream->avail_out = rec - REC_N_NEW_EXTRA_BYTES
- - d_stream->next_out;
+ d_stream->avail_out =static_cast<uInt>(
+ rec - REC_N_NEW_EXTRA_BYTES - d_stream->next_out);
ut_ad(d_stream->avail_out < UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR);
@@ -2731,7 +2766,8 @@ page_zip_decompress_clust(
goto zlib_error;
}
- d_stream->avail_out = dst - d_stream->next_out;
+ d_stream->avail_out = static_cast<uInt>(
+ dst - d_stream->next_out);
switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
@@ -2760,8 +2796,8 @@ page_zip_decompress_clust(
}
/* Decompress the last bytes of the record. */
- d_stream->avail_out = rec_get_end(rec, offsets)
- - d_stream->next_out;
+ d_stream->avail_out = static_cast<uInt>(
+ rec_get_end(rec, offsets) - d_stream->next_out);
switch (inflate(d_stream, Z_SYNC_FLUSH)) {
case Z_STREAM_END:
@@ -2781,9 +2817,9 @@ page_zip_decompress_clust(
/* Decompress any trailing garbage, in case the last record was
allocated from an originally longer space on the free list. */
- d_stream->avail_out = page_header_get_field(page_zip->data,
- PAGE_HEAP_TOP)
- - page_offset(d_stream->next_out);
+ d_stream->avail_out = static_cast<uInt>(
+ page_header_get_field(page_zip->data, PAGE_HEAP_TOP)
+ - page_offset(d_stream->next_out));
if (UNIV_UNLIKELY(d_stream->avail_out > UNIV_PAGE_SIZE
- PAGE_ZIP_START - PAGE_DIR)) {
@@ -3039,7 +3075,8 @@ zlib_error:
d_stream.next_in = page_zip->data + PAGE_DATA;
/* Subtract the space reserved for
the page header and the end marker of the modification log. */
- d_stream.avail_in = page_zip_get_size(page_zip) - (PAGE_DATA + 1);
+ d_stream.avail_in = static_cast<uInt>(
+ page_zip_get_size(page_zip) - (PAGE_DATA + 1));
d_stream.next_out = page + PAGE_ZIP_START;
d_stream.avail_out = UNIV_PAGE_SIZE - PAGE_ZIP_START;
@@ -3498,7 +3535,7 @@ page_zip_write_rec_ext(
externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
if (create) {
- page_zip->n_blobs += n_ext;
+ page_zip->n_blobs += static_cast<unsigned>(n_ext);
ASSERT_ZERO_BLOB(ext_end - n_ext
* BTR_EXTERN_FIELD_REF_SIZE);
memmove(ext_end - n_ext
@@ -4406,7 +4443,7 @@ page_zip_dir_delete(
* BTR_EXTERN_FIELD_REF_SIZE;
externs -= blob_no * BTR_EXTERN_FIELD_REF_SIZE;
- page_zip->n_blobs -= n_ext;
+ page_zip->n_blobs -= static_cast<unsigned>(n_ext);
/* Shift and zero fill the array. */
memmove(ext_end + n_ext * BTR_EXTERN_FIELD_REF_SIZE, ext_end,
(page_zip->n_blobs - blob_no)
@@ -4861,8 +4898,10 @@ page_zip_calc_checksum(
adler = adler32(0L, s + FIL_PAGE_OFFSET,
FIL_PAGE_LSN - FIL_PAGE_OFFSET);
adler = adler32(adler, s + FIL_PAGE_TYPE, 2);
- adler = adler32(adler, s + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
- size - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ adler = adler32(
+ adler, s + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID,
+ static_cast<uInt>(size)
+ - FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
return((ulint) adler);
case SRV_CHECKSUM_ALGORITHM_NONE:
@@ -4892,21 +4931,25 @@ page_zip_verify_checksum(
ib_uint32_t crc32 = 0 /* silence bogus warning */;
ib_uint32_t innodb = 0 /* silence bogus warning */;
- stored = mach_read_from_4(
- (const unsigned char*) data + FIL_PAGE_SPACE_OR_CHKSUM);
+ stored = static_cast<ib_uint32_t>(mach_read_from_4(
+ static_cast<const unsigned char*>(data) + FIL_PAGE_SPACE_OR_CHKSUM));
/* declare empty pages non-corrupted */
if (stored == 0) {
/* make sure that the page is really empty */
- ut_d(ulint i; for (i = 0; i < size; i++) {
- ut_a(*((const char*) data + i) == 0); });
+ ulint i;
+ for (i = 0; i < size; i++) {
+ if (*((const char*) data + i) != 0) {
+ return(FALSE);
+ }
+ }
return(TRUE);
}
- calc = page_zip_calc_checksum(
+ calc = static_cast<ib_uint32_t>(page_zip_calc_checksum(
data, size, static_cast<srv_checksum_algorithm_t>(
- srv_checksum_algorithm));
+ srv_checksum_algorithm)));
if (stored == calc) {
return(TRUE);
@@ -4922,15 +4965,15 @@ page_zip_verify_checksum(
return(TRUE);
}
crc32 = calc;
- innodb = page_zip_calc_checksum(
- data, size, SRV_CHECKSUM_ALGORITHM_INNODB);
+ innodb = static_cast<ib_uint32_t>(page_zip_calc_checksum(
+ data, size, SRV_CHECKSUM_ALGORITHM_INNODB));
break;
case SRV_CHECKSUM_ALGORITHM_INNODB:
if (stored == BUF_NO_CHECKSUM_MAGIC) {
return(TRUE);
}
- crc32 = page_zip_calc_checksum(
- data, size, SRV_CHECKSUM_ALGORITHM_CRC32);
+ crc32 = static_cast<ib_uint32_t>(page_zip_calc_checksum(
+ data, size, SRV_CHECKSUM_ALGORITHM_CRC32));
innodb = calc;
break;
case SRV_CHECKSUM_ALGORITHM_NONE:
diff --git a/storage/xtradb/pars/lexyy.cc b/storage/xtradb/pars/lexyy.cc
index 16458dda637..07476320e03 100644
--- a/storage/xtradb/pars/lexyy.cc
+++ b/storage/xtradb/pars/lexyy.cc
@@ -35,7 +35,7 @@
#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types.
+ * if you want the limit (max/min) macros for int types.
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS 1
@@ -2424,8 +2424,8 @@ static int yy_get_next_buffer (void)
else
{
- int num_to_read =
- YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+ int num_to_read = static_cast<int>(
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1);
while ( num_to_read <= 0 )
{ /* Not enough room in the buffer - grow it. */
@@ -2438,7 +2438,7 @@ static int yy_get_next_buffer (void)
if ( b->yy_is_our_buffer )
{
- int new_size = b->yy_buf_size * 2;
+ int new_size = static_cast<int>(b->yy_buf_size * 2);
if ( new_size <= 0 )
b->yy_buf_size += b->yy_buf_size / 8;
@@ -2459,8 +2459,9 @@ static int yy_get_next_buffer (void)
(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
- num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
- number_to_move - 1;
+ num_to_read = static_cast<int>(
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size
+ - number_to_move - 1);
}
@@ -2643,7 +2644,7 @@ static int yy_get_next_buffer (void)
/** Immediately switch to a different input stream.
* @param input_file A readable stream.
- *
+ *
* @note This function does not reset the start condition to @c INITIAL .
*/
void yyrestart (FILE * input_file )
@@ -2661,7 +2662,7 @@ static int yy_get_next_buffer (void)
/** Switch to a different input buffer.
* @param new_buffer The new input buffer.
- *
+ *
*/
__attribute__((unused)) static void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
{
@@ -2705,7 +2706,7 @@ static void yy_load_buffer_state (void)
/** Allocate and initialize an input buffer state.
* @param file A readable stream.
* @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- *
+ *
* @return the allocated buffer state.
*/
static YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
@@ -2734,7 +2735,7 @@ static void yy_load_buffer_state (void)
/** Destroy the buffer.
* @param b a buffer created with yy_create_buffer()
- *
+ *
*/
void yy_delete_buffer (YY_BUFFER_STATE b )
{
@@ -2759,7 +2760,7 @@ static void yy_load_buffer_state (void)
{
int oerrno = errno;
-
+
yy_flush_buffer(b );
b->yy_input_file = file;
@@ -2775,13 +2776,13 @@ static void yy_load_buffer_state (void)
}
b->yy_is_interactive = 0;
-
+
errno = oerrno;
}
/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
* @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- *
+ *
*/
void yy_flush_buffer (YY_BUFFER_STATE b )
{
@@ -2810,7 +2811,7 @@ static void yy_load_buffer_state (void)
* the current state. This function will allocate the stack
* if necessary.
* @param new_buffer The new state.
- *
+ *
*/
void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
{
@@ -2840,7 +2841,7 @@ void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
/** Removes and deletes the top of the stack, if present.
* The next element becomes the new top.
- *
+ *
*/
void yypop_buffer_state (void)
{
@@ -2864,7 +2865,7 @@ void yypop_buffer_state (void)
static void yyensure_buffer_stack (void)
{
int num_to_alloc;
-
+
if (!(yy_buffer_stack)) {
/* First allocation is just for 2 elements, since we don't know if this
@@ -2890,7 +2891,8 @@ static void yyensure_buffer_stack (void)
/* Increase the buffer to prepare for a possible push. */
int grow_size = 8 /* arbitrary grow size */;
- num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ num_to_alloc = static_cast<int>(
+ (yy_buffer_stack_max) + grow_size);
(yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
((yy_buffer_stack),
num_to_alloc * sizeof(struct yy_buffer_state*)
@@ -2934,7 +2936,7 @@ static void yy_fatal_error (yyconst char* msg )
/* Accessor methods (get/set functions) to struct members. */
/** Get the current line number.
- *
+ *
*/
int yyget_lineno (void)
{
@@ -2943,7 +2945,7 @@ int yyget_lineno (void)
}
/** Get the input stream.
- *
+ *
*/
FILE *yyget_in (void)
{
@@ -2951,7 +2953,7 @@ FILE *yyget_in (void)
}
/** Get the output stream.
- *
+ *
*/
FILE *yyget_out (void)
{
@@ -2959,7 +2961,7 @@ FILE *yyget_out (void)
}
/** Get the length of the current token.
- *
+ *
*/
yy_size_t yyget_leng (void)
{
@@ -2967,7 +2969,7 @@ yy_size_t yyget_leng (void)
}
/** Get the current token.
- *
+ *
*/
char *yyget_text (void)
@@ -2977,18 +2979,18 @@ char *yyget_text (void)
/** Set the current line number.
* @param line_number
- *
+ *
*/
void yyset_lineno (int line_number )
{
-
+
yylineno = line_number;
}
/** Set the input stream. This does not discard the current
* input buffer.
* @param in_str A readable stream.
- *
+ *
* @see yy_switch_to_buffer
*/
void yyset_in (FILE * in_str )
@@ -3042,7 +3044,7 @@ static int yy_init_globals (void)
/* yylex_destroy is for both reentrant and non-reentrant scanners. */
__attribute__((unused)) static int yylex_destroy (void)
{
-
+
/* Pop the buffer stack, destroying each element. */
while(YY_CURRENT_BUFFER){
yy_delete_buffer(YY_CURRENT_BUFFER );
diff --git a/storage/xtradb/pars/pars0pars.cc b/storage/xtradb/pars/pars0pars.cc
index e0bc00fad0d..f051481184b 100644
--- a/storage/xtradb/pars/pars0pars.cc
+++ b/storage/xtradb/pars/pars0pars.cc
@@ -1988,10 +1988,16 @@ pars_create_table(
}
}
+ /* Set the flags2 when create table or alter tables */
+ flags2 |= DICT_TF2_FTS_AUX_HEX_NAME;
+ DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
+ flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;);
+
+
n_cols = que_node_list_get_len(column_defs);
table = dict_mem_table_create(
- table_sym->name, 0, n_cols, flags, flags2);
+ table_sym->name, 0, n_cols, flags, flags2, false);
#ifdef UNIV_DEBUG
if (not_fit_in_memory != NULL) {
@@ -2154,8 +2160,9 @@ pars_get_lex_chars(
{
int len;
- len = pars_sym_tab_global->string_len
- - pars_sym_tab_global->next_char_pos;
+ len = static_cast<int>(
+ pars_sym_tab_global->string_len
+ - pars_sym_tab_global->next_char_pos);
if (len == 0) {
#ifdef YYDEBUG
/* fputs("SQL string ends\n", stderr); */
diff --git a/storage/xtradb/plugin_exports b/storage/xtradb/plugin_exports
deleted file mode 100644
index 235ae3d5e72..00000000000
--- a/storage/xtradb/plugin_exports
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- global:
- _maria_plugin_interface_version_;
- _maria_sizeof_struct_st_plugin_;
- _maria_plugin_declarations_;
- my_snprintf_service;
- thd_alloc_service;
- thd_autoinc_service;
- thd_error_context_service;
- thd_kill_statement_service;
- thd_wait_service;
- local:
- *;
-};
diff --git a/storage/xtradb/rem/rem0cmp.cc b/storage/xtradb/rem/rem0cmp.cc
index db0fdf3ee21..426cf9e3ac5 100644
--- a/storage/xtradb/rem/rem0cmp.cc
+++ b/storage/xtradb/rem/rem0cmp.cc
@@ -316,8 +316,8 @@ cmp_dfield_dfield_like_prefix(
dfield_t* dfield1,/* in: data field; must have type field set */
dfield_t* dfield2)/* in: data field */
{
- const dtype_t* type;
- ulint ret;
+ const dtype_t* type;
+ int ret;
ut_ad(dfield_check_typed(dfield1));
@@ -325,21 +325,21 @@ cmp_dfield_dfield_like_prefix(
if (type->mtype >= DATA_FLOAT) {
ret = innobase_mysql_cmp_prefix(
- (int)(type->prtype & DATA_MYSQL_TYPE_MASK),
- (uint) dtype_get_charset_coll(type->prtype),
+ static_cast<int>(type->prtype & DATA_MYSQL_TYPE_MASK),
+ static_cast<uint>(dtype_get_charset_coll(type->prtype)),
+ static_cast<byte*>(dfield_get_data(dfield1)),
+ static_cast<uint>(dfield_get_len(dfield1)),
+ static_cast<byte*>(dfield_get_data(dfield2)),
+ static_cast<uint>(dfield_get_len(dfield2)));
+ } else {
+ ret = (cmp_data_data_like_prefix(
static_cast<byte*>(dfield_get_data(dfield1)),
dfield_get_len(dfield1),
- static_cast<byte*>(dfield_get_data(dfield2)),
- dfield_get_len(dfield2));
- } else {
- ret = (cmp_data_data_like_prefix(
- static_cast<byte*>(dfield_get_data(dfield1)),
- dfield_get_len(dfield1),
- static_cast<byte*>(dfield_get_data(dfield2)),
- dfield_get_len(dfield2)));
- }
-
- return(ret);
+ static_cast<byte*>(dfield_get_data(dfield2)),
+ dfield_get_len(dfield2)));
+ }
+
+ return(ret);
}
/*************************************************************//**
@@ -506,7 +506,8 @@ cmp_data_data_slow_varchar(
}
}
- return(i == lhs_len && i == rhs_len) ? 0 : rhs_len - lhs_len;
+ return((i == lhs_len && i == rhs_len) ? 0 :
+ static_cast<int>(rhs_len - lhs_len));
}
/*****************************************************************
diff --git a/storage/xtradb/rem/rem0rec.cc b/storage/xtradb/rem/rem0rec.cc
index 43072159b9e..0d7b7c16785 100644
--- a/storage/xtradb/rem/rem0rec.cc
+++ b/storage/xtradb/rem/rem0rec.cc
@@ -543,9 +543,11 @@ rec_get_offsets_func(
ulint n_fields,/*!< in: maximum number of
initialized fields
(ULINT_UNDEFINED if all fields) */
- mem_heap_t** heap, /*!< in/out: memory heap */
+#ifdef UNIV_DEBUG
const char* file, /*!< in: file name where called */
- ulint line) /*!< in: line number where called */
+ ulint line, /*!< in: line number where called */
+#endif /* UNIV_DEBUG */
+ mem_heap_t** heap) /*!< in/out: memory heap */
{
ulint n;
ulint size;
@@ -590,9 +592,8 @@ rec_get_offsets_func(
if (UNIV_UNLIKELY(!offsets)
|| UNIV_UNLIKELY(rec_offs_get_n_alloc(offsets) < size)) {
if (UNIV_UNLIKELY(!*heap)) {
- *heap = mem_heap_create_func(size * sizeof(ulint),
- MEM_HEAP_DYNAMIC,
- file, line);
+ *heap = mem_heap_create_at(size * sizeof(ulint),
+ file, line);
}
offsets = static_cast<ulint*>(
mem_heap_alloc(*heap, size * sizeof(ulint)));
diff --git a/storage/xtradb/row/row0ftsort.cc b/storage/xtradb/row/row0ftsort.cc
index 7a673feae9b..54f6f7bcc0f 100644
--- a/storage/xtradb/row/row0ftsort.cc
+++ b/storage/xtradb/row/row0ftsort.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.
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
@@ -872,7 +872,9 @@ func_exit:
mutex_exit(&psort_info->mutex);
if (UT_LIST_GET_LEN(psort_info->fts_doc_list) > 0) {
- ut_ad(error != DB_SUCCESS);
+ /* child can exit either with error or told by parent. */
+ ut_ad(error != DB_SUCCESS
+ || psort_info->state == FTS_PARENT_EXITING);
}
/* Free fts doc list in case of error. */
@@ -1194,7 +1196,7 @@ row_fts_sel_tree_propagate(
sel_tree[parent] = selected;
- return(parent);
+ return(static_cast<int>(parent));
}
/*********************************************************************//**
@@ -1214,8 +1216,8 @@ row_fts_sel_tree_update(
ulint i;
for (i = 1; i <= height; i++) {
- propagated = row_fts_sel_tree_propagate(
- propagated, sel_tree, mrec, offsets, index);
+ propagated = static_cast<ulint>(row_fts_sel_tree_propagate(
+ static_cast<int>(propagated), sel_tree, mrec, offsets, index));
}
return(sel_tree[0]);
@@ -1239,8 +1241,8 @@ row_fts_build_sel_tree_level(
ulint i;
ulint num_item;
- start = (1 << level) - 1;
- num_item = (1 << level);
+ start = static_cast<ulint>((1 << level) - 1);
+ num_item = static_cast<ulint>(1 << level);
for (i = 0; i < num_item; i++) {
child_left = sel_tree[(start + i) * 2 + 1];
@@ -1315,8 +1317,9 @@ row_fts_build_sel_tree(
sel_tree[i + start] = i;
}
- for (i = treelevel - 1; i >=0; i--) {
- row_fts_build_sel_tree_level(sel_tree, i, mrec, offsets, index);
+ for (i = static_cast<int>(treelevel) - 1; i >= 0; i--) {
+ row_fts_build_sel_tree_level(
+ sel_tree, static_cast<ulint>(i), mrec, offsets, index);
}
return(treelevel);
@@ -1434,11 +1437,17 @@ row_fts_merge_insert(
ins_ctx.ins_graph = static_cast<que_t**>(mem_heap_alloc(heap, n_bytes));
memset(ins_ctx.ins_graph, 0x0, n_bytes);
+ /* We should set the flags2 with aux_table_name here,
+ in order to get the correct aux table names. */
+ index->table->flags2 |= DICT_TF2_FTS_AUX_HEX_NAME;
+ DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
+ index->table->flags2 &= ~DICT_TF2_FTS_AUX_HEX_NAME;);
+
ins_ctx.fts_table.type = FTS_INDEX_TABLE;
ins_ctx.fts_table.index_id = index->id;
ins_ctx.fts_table.table_id = table->id;
ins_ctx.fts_table.parent = index->table->name;
- ins_ctx.fts_table.table = NULL;
+ ins_ctx.fts_table.table = index->table;
for (i = 0; i < fts_sort_pll_degree; i++) {
if (psort_info[i].merge_file[id]->n_rec == 0) {
@@ -1495,7 +1504,7 @@ row_fts_merge_insert(
mrec[i], mrec[min_rec],
offsets[i], offsets[min_rec],
index, NULL) < 0) {
- min_rec = i;
+ min_rec = static_cast<int>(i);
}
}
} else {
diff --git a/storage/xtradb/row/row0ins.cc b/storage/xtradb/row/row0ins.cc
index 34e34925b9a..f8ca40fac12 100644
--- a/storage/xtradb/row/row0ins.cc
+++ b/storage/xtradb/row/row0ins.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2014, 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
@@ -2995,6 +2995,10 @@ row_ins_index_entry(
dtuple_t* entry, /*!< in/out: index entry to insert */
que_thr_t* thr) /*!< in: query thread */
{
+ DBUG_EXECUTE_IF("row_ins_index_entry_timeout", {
+ DBUG_SET("-d,row_ins_index_entry_timeout");
+ return(DB_LOCK_WAIT);});
+
if (dict_index_is_clust(index)) {
return(row_ins_clust_index_entry(index, entry, thr, 0));
} else {
diff --git a/storage/xtradb/row/row0log.cc b/storage/xtradb/row/row0log.cc
index 0c5ae2d3125..1240cf7fcc5 100644
--- a/storage/xtradb/row/row0log.cc
+++ b/storage/xtradb/row/row0log.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2011, 2014, 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
@@ -78,11 +78,12 @@ struct row_log_buf_t {
mrec_buf_t buf; /*!< buffer for accessing a record
that spans two blocks */
ulint blocks; /*!< current position in blocks */
- ulint bytes; /*!< current position within buf */
+ ulint bytes; /*!< current position within block */
ulonglong total; /*!< logical position, in bytes from
the start of the row_log_table log;
0 for row_log_online_op() and
row_log_apply(). */
+ ulint size; /*!< allocated size of block */
};
/** Tracks BLOB allocation during online ALTER TABLE */
@@ -193,9 +194,48 @@ struct row_log_t {
or by index->lock X-latch only */
row_log_buf_t head; /*!< reader context; protected by MDL only;
modifiable by row_log_apply_ops() */
- ulint size; /*!< allocated size */
};
+
+/** Allocate the memory for the log buffer.
+@param[in,out] log_buf Buffer used for log operation
+@return TRUE if success, false if not */
+static __attribute__((warn_unused_result))
+bool
+row_log_block_allocate(
+ row_log_buf_t& log_buf)
+{
+ DBUG_ENTER("row_log_block_allocate");
+ if (log_buf.block == NULL) {
+ log_buf.size = srv_sort_buf_size;
+ log_buf.block = (byte*) os_mem_alloc_large(&log_buf.size,
+ FALSE);
+ DBUG_EXECUTE_IF("simulate_row_log_allocation_failure",
+ if (log_buf.block)
+ os_mem_free_large(log_buf.block, log_buf.size);
+ log_buf.block = NULL;);
+ if (!log_buf.block) {
+ DBUG_RETURN(false);
+ }
+ }
+ DBUG_RETURN(true);
+}
+
+/** Free the log buffer.
+@param[in,out] log_buf Buffer used for log operation */
+static
+void
+row_log_block_free(
+ row_log_buf_t& log_buf)
+{
+ DBUG_ENTER("row_log_block_free");
+ if (log_buf.block != NULL) {
+ os_mem_free_large(log_buf.block, log_buf.size);
+ log_buf.block = NULL;
+ }
+ DBUG_VOID_RETURN;
+}
+
/******************************************************//**
Logs an operation to a secondary index that is (or was) being created. */
UNIV_INTERN
@@ -247,6 +287,11 @@ row_log_online_op(
log->max_trx = trx_id;
}
+ if (!row_log_block_allocate(log->tail)) {
+ log->error = DB_OUT_OF_MEMORY;
+ goto err_exit;
+ }
+
UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf);
ut_ad(log->tail.bytes < srv_sort_buf_size);
@@ -318,6 +363,7 @@ write_failed:
}
UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf);
+err_exit:
mutex_exit(&log->mutex);
}
@@ -352,10 +398,16 @@ row_log_table_open(
UNIV_MEM_INVALID(log->tail.buf, sizeof log->tail.buf);
if (log->error != DB_SUCCESS) {
+err_exit:
mutex_exit(&log->mutex);
return(NULL);
}
+ if (!row_log_block_allocate(log->tail)) {
+ log->error = DB_OUT_OF_MEMORY;
+ goto err_exit;
+ }
+
ut_ad(log->tail.bytes < srv_sort_buf_size);
*avail = srv_sort_buf_size - log->tail.bytes;
@@ -441,9 +493,8 @@ row_log_table_delete(
dict_index_t* index, /*!< in/out: clustered index, S-latched
or X-latched */
const ulint* offsets,/*!< in: rec_get_offsets(rec,index) */
- bool purge, /*!< in: true=purging BLOBs */
- trx_id_t trx_id) /*!< in: DB_TRX_ID of the record before
- it was deleted */
+ const byte* sys) /*!< in: DB_TRX_ID,DB_ROLL_PTR that should
+ be logged, or NULL to use those in rec */
{
ulint old_pk_extra_size;
ulint old_pk_size;
@@ -475,22 +526,21 @@ row_log_table_delete(
ut_ad(dict_index_is_clust(new_index));
ut_ad(!dict_index_is_online_ddl(new_index));
- /* Create the tuple PRIMARY KEY, DB_TRX_ID in the new_table. */
+ /* Create the tuple PRIMARY KEY,DB_TRX_ID,DB_ROLL_PTR in new_table. */
if (index->online_log->same_pk) {
- byte* db_trx_id;
dtuple_t* tuple;
ut_ad(new_index->n_uniq == index->n_uniq);
- /* The PRIMARY KEY and DB_TRX_ID are in the first
+ /* The PRIMARY KEY and DB_TRX_ID,DB_ROLL_PTR are in the first
fields of the record. */
heap = mem_heap_create(
DATA_TRX_ID_LEN
- + DTUPLE_EST_ALLOC(new_index->n_uniq + 1));
- old_pk = tuple = dtuple_create(heap, new_index->n_uniq + 1);
+ + DTUPLE_EST_ALLOC(new_index->n_uniq + 2));
+ old_pk = tuple = dtuple_create(heap, new_index->n_uniq + 2);
dict_index_copy_types(tuple, new_index, tuple->n_fields);
dtuple_set_n_fields_cmp(tuple, new_index->n_uniq);
- for (ulint i = 0; i < new_index->n_uniq; i++) {
+ for (ulint i = 0; i < dtuple_get_n_fields(tuple); i++) {
ulint len;
const void* field = rec_get_nth_field(
rec, offsets, i, &len);
@@ -501,42 +551,33 @@ row_log_table_delete(
dfield_set_data(dfield, field, len);
}
- db_trx_id = static_cast<byte*>(
- mem_heap_alloc(heap, DATA_TRX_ID_LEN));
- trx_write_trx_id(db_trx_id, trx_id);
-
- dfield_set_data(dtuple_get_nth_field(tuple, new_index->n_uniq),
- db_trx_id, DATA_TRX_ID_LEN);
+ if (sys) {
+ dfield_set_data(
+ dtuple_get_nth_field(tuple,
+ new_index->n_uniq),
+ sys, DATA_TRX_ID_LEN);
+ dfield_set_data(
+ dtuple_get_nth_field(tuple,
+ new_index->n_uniq + 1),
+ sys + DATA_TRX_ID_LEN, DATA_ROLL_PTR_LEN);
+ }
} else {
/* The PRIMARY KEY has changed. Translate the tuple. */
- dfield_t* dfield;
-
- old_pk = row_log_table_get_pk(rec, index, offsets, &heap);
+ old_pk = row_log_table_get_pk(
+ rec, index, offsets, NULL, &heap);
if (!old_pk) {
ut_ad(index->online_log->error != DB_SUCCESS);
+ if (heap) {
+ goto func_exit;
+ }
return;
}
-
- /* Remove DB_ROLL_PTR. */
- ut_ad(dtuple_get_n_fields_cmp(old_pk)
- == dict_index_get_n_unique(new_index));
- ut_ad(dtuple_get_n_fields(old_pk)
- == dict_index_get_n_unique(new_index) + 2);
- const_cast<ulint&>(old_pk->n_fields)--;
-
- /* Overwrite DB_TRX_ID with the old trx_id. */
- dfield = dtuple_get_nth_field(old_pk, new_index->n_uniq);
- ut_ad(dfield_get_type(dfield)->mtype == DATA_SYS);
- ut_ad(dfield_get_type(dfield)->prtype
- == (DATA_NOT_NULL | DATA_TRX_ID));
- ut_ad(dfield_get_len(dfield) == DATA_TRX_ID_LEN);
- dfield_dup(dfield, heap);
- trx_write_trx_id(static_cast<byte*>(dfield->data), trx_id);
}
- ut_ad(dtuple_get_n_fields(old_pk) > 1);
ut_ad(DATA_TRX_ID_LEN == dtuple_get_nth_field(
+ old_pk, old_pk->n_fields - 2)->len);
+ ut_ad(DATA_ROLL_PTR_LEN == dtuple_get_nth_field(
old_pk, old_pk->n_fields - 1)->len);
old_pk_size = rec_get_converted_size_temp(
new_index, old_pk->fields, old_pk->n_fields,
@@ -548,7 +589,7 @@ row_log_table_delete(
/* Log enough prefix of the BLOB unless both the
old and new table are in COMPACT or REDUNDANT format,
which store the prefix in the clustered index record. */
- if (purge && rec_offs_any_extern(offsets)
+ if (rec_offs_any_extern(offsets)
&& (dict_table_get_format(index->table) >= UNIV_FORMAT_B
|| dict_table_get_format(new_table) >= UNIV_FORMAT_B)) {
@@ -613,6 +654,7 @@ row_log_table_delete(
index->online_log, b, mrec_size, avail_size);
}
+func_exit:
mem_heap_free(heap);
}
@@ -966,6 +1008,8 @@ row_log_table_get_pk(
dict_index_t* index, /*!< in/out: clustered index, S-latched
or X-latched */
const ulint* offsets,/*!< in: rec_get_offsets(rec,index) */
+ byte* sys, /*!< out: DB_TRX_ID,DB_ROLL_PTR for
+ row_log_table_delete(), or NULL */
mem_heap_t** heap) /*!< in/out: memory heap where allocated */
{
dtuple_t* tuple = NULL;
@@ -984,6 +1028,31 @@ row_log_table_get_pk(
if (log->same_pk) {
/* The PRIMARY KEY columns are unchanged. */
+ if (sys) {
+ /* Store the DB_TRX_ID,DB_ROLL_PTR. */
+ ulint trx_id_offs = index->trx_id_offset;
+
+ if (!trx_id_offs) {
+ ulint pos = dict_index_get_sys_col_pos(
+ index, DATA_TRX_ID);
+ ulint len;
+ ut_ad(pos > 0);
+
+ if (!offsets) {
+ offsets = rec_get_offsets(
+ rec, index, NULL, pos + 1,
+ heap);
+ }
+
+ trx_id_offs = rec_get_nth_field_offs(
+ offsets, pos, &len);
+ ut_ad(len == DATA_TRX_ID_LEN);
+ }
+
+ memcpy(sys, rec + trx_id_offs,
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
+ }
+
return(NULL);
}
@@ -1093,6 +1162,20 @@ err_exit:
const byte* trx_roll = rec
+ row_get_trx_id_offset(index, offsets);
+ /* Copy the fields, because the fields will be updated
+ or the record may be moved somewhere else in the B-tree
+ as part of the upcoming operation. */
+ if (sys) {
+ memcpy(sys, trx_roll,
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN);
+ trx_roll = sys;
+ } else {
+ trx_roll = static_cast<const byte*>(
+ mem_heap_dup(
+ *heap, trx_roll,
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN));
+ }
+
dfield_set_data(dtuple_get_nth_field(tuple, new_n_uniq),
trx_roll, DATA_TRX_ID_LEN);
dfield_set_data(dtuple_get_nth_field(tuple, new_n_uniq + 1),
@@ -1211,10 +1294,13 @@ row_log_table_apply_convert_mrec(
mem_heap_t* heap, /*!< in/out: memory heap */
trx_id_t trx_id, /*!< in: DB_TRX_ID of mrec */
dberr_t* error) /*!< out: DB_SUCCESS or
+ DB_MISSING_HISTORY or
reason of failure */
{
dtuple_t* row;
+ *error = DB_SUCCESS;
+
/* This is based on row_build(). */
if (log->add_cols) {
row = dtuple_copy(log->add_cols, heap);
@@ -1256,7 +1342,7 @@ row_log_table_apply_convert_mrec(
dfield_t* dfield
= dtuple_get_nth_field(row, col_no);
ulint len;
- const byte* data= NULL;
+ const byte* data;
if (rec_offs_nth_extern(offsets, i)) {
ut_ad(rec_offs_any_extern(offsets));
@@ -1276,29 +1362,26 @@ row_log_table_apply_convert_mrec(
&& p->second.is_freed(log->head.total)) {
/* This BLOB has been freed.
We must not access the row. */
- row = NULL;
+ *error = DB_MISSING_HISTORY;
+ dfield_set_data(dfield, data, len);
+ dfield_set_ext(dfield);
+ goto blob_done;
}
}
- if (row) {
- data = btr_rec_copy_externally_stored_field(
- mrec, offsets,
- dict_table_zip_size(index->table),
- i, &len, heap);
- ut_a(data);
- }
-
+ data = btr_rec_copy_externally_stored_field(
+ mrec, offsets,
+ dict_table_zip_size(index->table),
+ i, &len, heap);
+ ut_a(data);
+ dfield_set_data(dfield, data, len);
+blob_done:
rw_lock_x_unlock(dict_index_get_lock(index));
-
- if (!row) {
- goto func_exit;
- }
} else {
data = rec_get_nth_field(mrec, offsets, i, &len);
+ dfield_set_data(dfield, data, len);
}
- dfield_set_data(dfield, data, len);
-
/* See if any columns were changed to NULL or NOT NULL. */
const dict_col_t* new_col
= dict_table_get_nth_col(log->table, col_no);
@@ -1327,8 +1410,6 @@ row_log_table_apply_convert_mrec(
dfield_get_type(dfield)));
}
-func_exit:
- *error = DB_SUCCESS;
return(row);
}
@@ -1427,22 +1508,32 @@ row_log_table_apply_insert(
const dtuple_t* row = row_log_table_apply_convert_mrec(
mrec, dup->index, offsets, log, heap, trx_id, &error);
- ut_ad(error == DB_SUCCESS || !row);
- /* Handling of duplicate key error requires storing
- of offending key in a record buffer. */
- ut_ad(error != DB_DUPLICATE_KEY);
-
- if (error != DB_SUCCESS)
+ switch (error) {
+ case DB_MISSING_HISTORY:
+ ut_ad(log->blobs);
+ /* Because some BLOBs are missing, we know that the
+ transaction was rolled back later (a rollback of
+ an insert can free BLOBs).
+ We can simply skip the insert: the subsequent
+ ROW_T_DELETE will be ignored, or a ROW_T_UPDATE will
+ be interpreted as ROW_T_INSERT. */
+ return(DB_SUCCESS);
+ case DB_SUCCESS:
+ ut_ad(row != NULL);
+ break;
+ default:
+ ut_ad(0);
+ case DB_INVALID_NULL:
+ ut_ad(row == NULL);
return(error);
+ }
- if (row) {
- error = row_log_table_apply_insert_low(
- thr, row, trx_id, offsets_heap, heap, dup);
- if (error != DB_SUCCESS) {
- /* Report the erroneous row using the new
- version of the table. */
- innobase_row_to_mysql(dup->table, log->table, row);
- }
+ error = row_log_table_apply_insert_low(
+ thr, row, trx_id, offsets_heap, heap, dup);
+ if (error != DB_SUCCESS) {
+ /* Report the erroneous row using the new
+ version of the table. */
+ innobase_row_to_mysql(dup->table, log->table, row);
}
return(error);
}
@@ -1561,10 +1652,11 @@ row_log_table_apply_delete(
mem_heap_t* offsets_heap, /*!< in/out: memory heap
that can be emptied */
mem_heap_t* heap, /*!< in/out: memory heap */
- dict_table_t* new_table, /*!< in: rebuilt table */
+ const row_log_t* log, /*!< in: online log */
const row_ext_t* save_ext) /*!< in: saved external field
info, or NULL */
{
+ dict_table_t* new_table = log->table;
dict_index_t* index = dict_table_get_first_index(new_table);
dtuple_t* old_pk;
mtr_t mtr;
@@ -1572,15 +1664,14 @@ row_log_table_apply_delete(
ulint* offsets;
ut_ad(rec_offs_n_fields(moffsets)
- == dict_index_get_n_unique(index) + 1);
+ == dict_index_get_n_unique(index) + 2);
ut_ad(!rec_offs_any_extern(moffsets));
/* Convert the row to a search tuple. */
- old_pk = dtuple_create(heap, index->n_uniq + 1);
- dict_index_copy_types(old_pk, index, old_pk->n_fields);
- dtuple_set_n_fields_cmp(old_pk, index->n_uniq);
+ old_pk = dtuple_create(heap, index->n_uniq);
+ dict_index_copy_types(old_pk, index, index->n_uniq);
- for (ulint i = 0; i <= index->n_uniq; i++) {
+ for (ulint i = 0; i < index->n_uniq; i++) {
ulint len;
const void* field;
field = rec_get_nth_field(mrec, moffsets, i, &len);
@@ -1614,6 +1705,10 @@ flag_ok:
all_done:
mtr_commit(&mtr);
/* The record was not found. All done. */
+ /* This should only happen when an earlier
+ ROW_T_INSERT was skipped or
+ ROW_T_UPDATE was interpreted as ROW_T_DELETE
+ due to BLOBs having been freed by rollback. */
return(DB_SUCCESS);
}
@@ -1623,19 +1718,38 @@ all_done:
ut_a(!rec_offs_any_null_extern(btr_pcur_get_rec(&pcur), offsets));
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
- /* Only remove the record if DB_TRX_ID matches what was
- buffered. */
+ /* Only remove the record if DB_TRX_ID,DB_ROLL_PTR match. */
{
ulint len;
- const void* mrec_trx_id
+ const byte* mrec_trx_id
= rec_get_nth_field(mrec, moffsets, trx_id_col, &len);
ut_ad(len == DATA_TRX_ID_LEN);
- const void* rec_trx_id
+ const byte* rec_trx_id
= rec_get_nth_field(btr_pcur_get_rec(&pcur), offsets,
trx_id_col, &len);
ut_ad(len == DATA_TRX_ID_LEN);
- if (memcmp(mrec_trx_id, rec_trx_id, DATA_TRX_ID_LEN)) {
+
+ ut_ad(rec_get_nth_field(mrec, moffsets, trx_id_col + 1, &len)
+ == mrec_trx_id + DATA_TRX_ID_LEN);
+ ut_ad(len == DATA_ROLL_PTR_LEN);
+ ut_ad(rec_get_nth_field(btr_pcur_get_rec(&pcur), offsets,
+ trx_id_col + 1, &len)
+ == rec_trx_id + DATA_TRX_ID_LEN);
+ ut_ad(len == DATA_ROLL_PTR_LEN);
+
+ if (memcmp(mrec_trx_id, rec_trx_id,
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)) {
+ /* The ROW_T_DELETE was logged for a different
+ PRIMARY KEY,DB_TRX_ID,DB_ROLL_PTR.
+ This is possible if a ROW_T_INSERT was skipped
+ or a ROW_T_UPDATE was interpreted as ROW_T_DELETE
+ because some BLOBs were missing due to
+ (1) rolling back the initial insert, or
+ (2) purging the BLOB for a later ROW_T_DELETE
+ (3) purging 'old values' for a later ROW_T_UPDATE
+ or ROW_T_DELETE. */
+ ut_ad(!log->same_pk);
goto all_done;
}
}
@@ -1679,17 +1793,32 @@ row_log_table_apply_update(
== dict_index_get_n_unique(index));
ut_ad(dtuple_get_n_fields(old_pk)
== dict_index_get_n_unique(index)
- + (dup->index->online_log->same_pk ? 0 : 2));
+ + (log->same_pk ? 0 : 2));
row = row_log_table_apply_convert_mrec(
mrec, dup->index, offsets, log, heap, trx_id, &error);
- ut_ad(error == DB_SUCCESS || !row);
- /* Handling of duplicate key error requires storing
- of offending key in a record buffer. */
- ut_ad(error != DB_DUPLICATE_KEY);
-
- if (!row) {
+ switch (error) {
+ case DB_MISSING_HISTORY:
+ /* The record contained BLOBs that are now missing. */
+ ut_ad(log->blobs);
+ /* Whether or not we are updating the PRIMARY KEY, we
+ know that there should be a subsequent
+ ROW_T_DELETE for rolling back a preceding ROW_T_INSERT,
+ overriding this ROW_T_UPDATE record. (*1)
+
+ This allows us to interpret this ROW_T_UPDATE
+ as ROW_T_DELETE.
+
+ When applying the subsequent ROW_T_DELETE, no matching
+ record will be found. */
+ case DB_SUCCESS:
+ ut_ad(row != NULL);
+ break;
+ default:
+ ut_ad(0);
+ case DB_INVALID_NULL:
+ ut_ad(row == NULL);
return(error);
}
@@ -1712,10 +1841,57 @@ 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;
+ /* The record was not found. This should only happen
+ when an earlier ROW_T_INSERT or ROW_T_UPDATE was
+ diverted because BLOBs were freed when the insert was
+ later rolled back. */
+
+ ut_ad(log->blobs);
+
+ if (error == DB_SUCCESS) {
+ /* An earlier ROW_T_INSERT could have been
+ skipped because of a missing BLOB, like this:
+
+ BEGIN;
+ INSERT INTO t SET blob_col='blob value';
+ UPDATE t SET blob_col='';
+ ROLLBACK;
+
+ This would generate the following records:
+ ROW_T_INSERT (referring to 'blob value')
+ ROW_T_UPDATE
+ ROW_T_UPDATE (referring to 'blob value')
+ ROW_T_DELETE
+ [ROLLBACK removes the 'blob value']
+
+ The ROW_T_INSERT would have been skipped
+ because of a missing BLOB. Now we are
+ executing the first ROW_T_UPDATE.
+ The second ROW_T_UPDATE (for the ROLLBACK)
+ would be interpreted as ROW_T_DELETE, because
+ the BLOB would be missing.
+
+ We could probably assume that the transaction
+ has been rolled back and simply skip the
+ 'insert' part of this ROW_T_UPDATE record.
+ However, there might be some complex scenario
+ that could interfere with such a shortcut.
+ So, we will insert the row (and risk
+ introducing a bogus duplicate key error
+ for the ALTER TABLE), and a subsequent
+ ROW_T_UPDATE or ROW_T_DELETE will delete it. */
+ mtr_commit(&mtr);
+ error = row_log_table_apply_insert_low(
+ thr, row, trx_id, offsets_heap, heap, dup);
+ } else {
+ /* Some BLOBs are missing, so we are interpreting
+ this ROW_T_UPDATE as ROW_T_DELETE (see *1).
+ Because the record was not found, we do nothing. */
+ ut_ad(error == DB_MISSING_HISTORY);
+ error = DB_SUCCESS;
func_exit:
- mtr_commit(&mtr);
+ mtr_commit(&mtr);
+ }
func_exit_committed:
ut_ad(mtr.state == MTR_COMMITTED);
@@ -1728,19 +1904,76 @@ func_exit_committed:
return(error);
}
- /* Update the record. */
+ /* Prepare to update (or delete) the record. */
ulint* cur_offsets = rec_get_offsets(
btr_pcur_get_rec(&pcur),
index, NULL, ULINT_UNDEFINED, &offsets_heap);
+ if (!log->same_pk) {
+ /* Only update the record if DB_TRX_ID,DB_ROLL_PTR match what
+ was buffered. */
+ ulint len;
+ const void* rec_trx_id
+ = rec_get_nth_field(btr_pcur_get_rec(&pcur),
+ cur_offsets, index->n_uniq, &len);
+ ut_ad(len == DATA_TRX_ID_LEN);
+ ut_ad(dtuple_get_nth_field(old_pk, index->n_uniq)->len
+ == DATA_TRX_ID_LEN);
+ ut_ad(dtuple_get_nth_field(old_pk, index->n_uniq + 1)->len
+ == DATA_ROLL_PTR_LEN);
+ ut_ad(DATA_TRX_ID_LEN + static_cast<const char*>(
+ dtuple_get_nth_field(old_pk,
+ index->n_uniq)->data)
+ == dtuple_get_nth_field(old_pk,
+ index->n_uniq + 1)->data);
+ if (memcmp(rec_trx_id,
+ dtuple_get_nth_field(old_pk, index->n_uniq)->data,
+ DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN)) {
+ /* The ROW_T_UPDATE was logged for a different
+ DB_TRX_ID,DB_ROLL_PTR. This is possible if an
+ earlier ROW_T_INSERT or ROW_T_UPDATE was diverted
+ because some BLOBs were missing due to rolling
+ back the initial insert or due to purging
+ the old BLOB values of an update. */
+ ut_ad(log->blobs);
+ if (error != DB_SUCCESS) {
+ ut_ad(error == DB_MISSING_HISTORY);
+ /* Some BLOBs are missing, so we are
+ interpreting this ROW_T_UPDATE as
+ ROW_T_DELETE (see *1).
+ Because this is a different row,
+ we will do nothing. */
+ error = DB_SUCCESS;
+ } else {
+ /* Because the user record is missing due to
+ BLOBs that were missing when processing
+ an earlier log record, we should
+ interpret the ROW_T_UPDATE as ROW_T_INSERT.
+ However, there is a different user record
+ with the same PRIMARY KEY value already. */
+ error = DB_DUPLICATE_KEY;
+ }
+
+ goto func_exit;
+ }
+ }
+
+ if (error != DB_SUCCESS) {
+ ut_ad(error == DB_MISSING_HISTORY);
+ ut_ad(log->blobs);
+ /* Some BLOBs are missing, so we are interpreting
+ this ROW_T_UPDATE as ROW_T_DELETE (see *1). */
+ error = row_log_table_apply_delete_low(
+ &pcur, cur_offsets, NULL, heap, &mtr);
+ goto func_exit_committed;
+ }
+
dtuple_t* entry = row_build_index_entry(
row, NULL, index, heap);
const upd_t* update = row_upd_build_difference_binary(
index, entry, btr_pcur_get_rec(&pcur), cur_offsets,
false, NULL, heap);
- error = DB_SUCCESS;
-
if (!update->n_fields) {
/* Nothing to do. */
goto func_exit;
@@ -1756,7 +1989,7 @@ func_exit_committed:
allow purge to free any orphaned externally stored
columns. */
- if (pk_updated && dup->index->online_log->same_pk) {
+ if (pk_updated && 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
@@ -1982,7 +2215,7 @@ row_log_table_apply_op(
For fixed-length PRIMARY key columns, it is 0. */
mrec += extra_size;
- rec_offs_set_n_fields(offsets, new_index->n_uniq + 1);
+ rec_offs_set_n_fields(offsets, new_index->n_uniq + 2);
rec_init_offsets_temp(mrec, new_index, offsets);
next_mrec = mrec + rec_offs_data_size(offsets) + ext_size;
if (next_mrec > mrec_end) {
@@ -2017,7 +2250,7 @@ row_log_table_apply_op(
*error = row_log_table_apply_delete(
thr, new_trx_id_col,
mrec, offsets, offsets_heap, heap,
- log->table, ext);
+ log, ext);
break;
case ROW_T_UPDATE:
@@ -2266,7 +2499,9 @@ corruption:
if (index->online_log->head.blocks) {
#ifdef HAVE_FTRUNCATE
/* Truncate the file in order to save space. */
- ftruncate(index->online_log->fd, 0);
+ if (ftruncate(index->online_log->fd, 0) == -1) {
+ perror("ftruncate");
+ }
#endif /* HAVE_FTRUNCATE */
index->online_log->head.blocks
= index->online_log->tail.blocks = 0;
@@ -2301,6 +2536,11 @@ all_done:
ut_ad(dict_index_is_online_ddl(index));
+ if (!row_log_block_allocate(index->online_log->head)) {
+ error = DB_OUT_OF_MEMORY;
+ goto func_exit;
+ }
+
success = os_file_read_no_error_handling(
OS_FILE_FROM_FD(index->online_log->fd),
index->online_log->head.block, ofs,
@@ -2504,6 +2744,7 @@ func_exit:
mem_heap_free(offsets_heap);
mem_heap_free(heap);
+ row_log_block_free(index->online_log->head);
ut_free(offsets);
return(error);
}
@@ -2577,9 +2818,7 @@ row_log_allocate(
const ulint* col_map)/*!< in: mapping of old column
numbers to new ones, or NULL if !table */
{
- byte* buf;
row_log_t* log;
- ulint size;
DBUG_ENTER("row_log_allocate");
ut_ad(!dict_index_is_online_ddl(index));
@@ -2591,17 +2830,14 @@ row_log_allocate(
#ifdef UNIV_SYNC_DEBUG
ut_ad(rw_lock_own(dict_index_get_lock(index), RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
- size = 2 * srv_sort_buf_size + sizeof *log;
- buf = (byte*) os_mem_alloc_large(&size, FALSE);
- if (!buf) {
+ log = (row_log_t*) ut_malloc(sizeof *log);
+ if (!log) {
DBUG_RETURN(false);
}
- log = (row_log_t*) &buf[2 * srv_sort_buf_size];
- log->size = size;
log->fd = row_merge_file_create_low();
if (log->fd < 0) {
- os_mem_free_large(buf, size);
+ ut_free(log);
DBUG_RETURN(false);
}
mutex_create(index_online_log_key, &log->mutex,
@@ -2613,10 +2849,9 @@ row_log_allocate(
log->col_map = col_map;
log->error = DB_SUCCESS;
log->max_trx = 0;
- log->head.block = buf;
- log->tail.block = buf + srv_sort_buf_size;
log->tail.blocks = log->tail.bytes = 0;
log->tail.total = 0;
+ log->tail.block = log->head.block = NULL;
log->head.blocks = log->head.bytes = 0;
log->head.total = 0;
dict_index_set_online_status(index, ONLINE_INDEX_CREATION);
@@ -2641,9 +2876,11 @@ row_log_free(
MONITOR_ATOMIC_DEC(MONITOR_ONLINE_CREATE_INDEX);
delete log->blobs;
+ row_log_block_free(log->tail);
+ row_log_block_free(log->head);
row_merge_file_destroy_low(log->fd);
mutex_free(&log->mutex);
- os_mem_free_large(log->head.block, log->size);
+ ut_free(log);
log = 0;
}
@@ -3069,6 +3306,11 @@ next_block:
goto interrupted;
}
+ error = index->online_log->error;
+ if (error != DB_SUCCESS) {
+ goto func_exit;
+ }
+
if (dict_index_is_corrupted(index)) {
error = DB_INDEX_CORRUPT;
goto func_exit;
@@ -3089,7 +3331,9 @@ corruption:
if (index->online_log->head.blocks) {
#ifdef HAVE_FTRUNCATE
/* Truncate the file in order to save space. */
- ftruncate(index->online_log->fd, 0);
+ if (ftruncate(index->online_log->fd, 0) == -1) {
+ perror("ftruncate");
+ }
#endif /* HAVE_FTRUNCATE */
index->online_log->head.blocks
= index->online_log->tail.blocks = 0;
@@ -3120,6 +3364,11 @@ all_done:
log_free_check();
+ if (!row_log_block_allocate(index->online_log->head)) {
+ error = DB_OUT_OF_MEMORY;
+ goto func_exit;
+ }
+
success = os_file_read_no_error_handling(
OS_FILE_FROM_FD(index->online_log->fd),
index->online_log->head.block, ofs,
@@ -3320,6 +3569,7 @@ func_exit:
mem_heap_free(heap);
mem_heap_free(offsets_heap);
+ row_log_block_free(index->online_log->head);
ut_free(offsets);
return(error);
}
diff --git a/storage/xtradb/row/row0mysql.cc b/storage/xtradb/row/row0mysql.cc
index b590a04b3e8..c65c39b7971 100644
--- a/storage/xtradb/row/row0mysql.cc
+++ b/storage/xtradb/row/row0mysql.cc
@@ -1276,7 +1276,9 @@ row_insert_for_mysql(
" newraw is replaced\n"
"InnoDB: with raw, and innodb_force_... is removed.\n",
stderr);
-
+ if(srv_force_recovery) {
+ return(DB_READ_ONLY);
+ }
return(DB_ERROR);
}
@@ -1665,7 +1667,9 @@ row_update_for_mysql(
" is replaced\n"
"InnoDB: with raw, and innodb_force_... is removed.\n",
stderr);
-
+ if(srv_force_recovery) {
+ return(DB_READ_ONLY);
+ }
return(DB_ERROR);
}
@@ -3254,7 +3258,6 @@ row_truncate_table_for_mysql(
ut_a(trx->dict_operation_lock_mode == 0);
/* Prevent foreign key checks etc. while we are truncating the
table */
-
row_mysql_lock_data_dictionary(trx);
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -3318,6 +3321,25 @@ row_truncate_table_for_mysql(
goto funct_exit;
}
+ /* Check if memcached plugin is running on this table. if is, we don't
+ allow truncate this table. */
+ if (table->memcached_sync_count != 0) {
+ ut_print_timestamp(stderr);
+ fputs(" InnoDB: Cannot truncate table ", stderr);
+ ut_print_name(stderr, trx, TRUE, table->name);
+ fputs(" by DROP+CREATE\n"
+ "InnoDB: because there are memcached operations"
+ " running on it.\n",
+ stderr);
+ err = DB_ERROR;
+
+ goto funct_exit;
+ } else {
+ /* We need to set this counter to -1 for blocking
+ memcached operations. */
+ table->memcached_sync_count = DICT_TABLE_IN_DDL;
+ }
+
/* Remove all locks except the table-level X lock. */
lock_remove_all_on_table(table, FALSE);
@@ -3501,6 +3523,7 @@ next_rec:
fts_table.name = table->name;
fts_table.id = new_id;
+ fts_table.flags2 = table->flags2;
err = fts_create_common_tables(
trx, &fts_table, table->name, TRUE);
@@ -3645,6 +3668,12 @@ next_rec:
funct_exit:
+ if (table->memcached_sync_count == DICT_TABLE_IN_DDL) {
+ /* We need to set the memcached sync back to 0, unblock
+ memcached operationse. */
+ table->memcached_sync_count = 0;
+ }
+
row_mysql_unlock_data_dictionary(trx);
dict_stats_update(table, DICT_STATS_EMPTY_TABLE);
@@ -4716,6 +4745,9 @@ row_rename_table_for_mysql(
" is replaced\n"
"InnoDB: with raw, and innodb_force_... is removed.\n",
stderr);
+ if(srv_force_recovery) {
+ err = DB_READ_ONLY;
+ }
goto funct_exit;
} else if (row_mysql_is_system_table(new_name)) {
@@ -4989,15 +5021,31 @@ row_rename_table_for_mysql(
if (err != DB_SUCCESS && (table->space != 0)) {
char* orig_name = table->name;
+ trx_t* trx_bg = trx_allocate_for_background();
+
+ /* If the first fts_rename fails, the trx would
+ be rolled back and committed, we can't use it any more,
+ so we have to start a new background trx here. */
+ ut_a(trx_state_eq(trx, TRX_STATE_NOT_STARTED));
+ trx_bg->op_info = "Revert the failing rename "
+ "for fts aux tables";
+ trx_bg->dict_operation_lock_mode = RW_X_LATCH;
+ trx_start_for_ddl(trx_bg, TRX_DICT_OP_TABLE);
/* If rename fails and table has its own tablespace,
we need to call fts_rename_aux_tables again to
revert the ibd file rename, which is not under the
control of trx. Also notice the parent table name
- in cache is not changed yet. */
+ in cache is not changed yet. If the reverting fails,
+ the ibd data may be left in the new database, which
+ can be fixed only manually. */
table->name = const_cast<char*>(new_name);
- fts_rename_aux_tables(table, old_name, trx);
+ fts_rename_aux_tables(table, old_name, trx_bg);
table->name = orig_name;
+
+ trx_bg->dict_operation_lock_mode = 0;
+ trx_commit_for_mysql(trx_bg);
+ trx_free_for_background(trx_bg);
}
}
diff --git a/storage/xtradb/row/row0quiesce.cc b/storage/xtradb/row/row0quiesce.cc
index a59a6088ad6..1d67d5a9717 100644
--- a/storage/xtradb/row/row0quiesce.cc
+++ b/storage/xtradb/row/row0quiesce.cc
@@ -71,7 +71,7 @@ row_quiesce_write_index_fields(
}
/* Include the NUL byte in the length. */
- ib_uint32_t len = strlen(field->name) + 1;
+ ib_uint32_t len = static_cast<ib_uint32_t>(strlen(field->name) + 1);
ut_a(len > 1);
mach_write_to_4(row, len);
@@ -180,7 +180,7 @@ row_quiesce_write_indexes(
/* Write the length of the index name.
NUL byte is included in the length. */
- ib_uint32_t len = strlen(index->name) + 1;
+ ib_uint32_t len = static_cast<ib_uint32_t>(strlen(index->name) + 1);
ut_a(len > 1);
mach_write_to_4(row, len);
@@ -267,7 +267,7 @@ row_quiesce_write_table(
col_name = dict_table_get_col_name(table, dict_col_get_no(col));
/* Include the NUL byte in the length. */
- len = strlen(col_name) + 1;
+ len = static_cast<ib_uint32_t>(strlen(col_name) + 1);
ut_a(len > 1);
mach_write_to_4(row, len);
@@ -333,7 +333,7 @@ row_quiesce_write_header(
}
/* The server hostname includes the NUL byte. */
- len = strlen(hostname) + 1;
+ len = static_cast<ib_uint32_t>(strlen(hostname) + 1);
mach_write_to_4(value, len);
DBUG_EXECUTE_IF("ib_export_io_write_failure_5", close(fileno(file)););
@@ -351,7 +351,7 @@ row_quiesce_write_header(
/* The table name includes the NUL byte. */
ut_a(table->name != 0);
- len = strlen(table->name) + 1;
+ len = static_cast<ib_uint32_t>(strlen(table->name) + 1);
/* Write the table name. */
mach_write_to_4(value, len);
diff --git a/storage/xtradb/row/row0sel.cc b/storage/xtradb/row/row0sel.cc
index c68b4de1125..67107c34204 100644
--- a/storage/xtradb/row/row0sel.cc
+++ b/storage/xtradb/row/row0sel.cc
@@ -5340,25 +5340,40 @@ func_exit:
return(value);
}
-/*******************************************************************//**
-Get the last row.
-@return current rec or NULL */
+/** Get the maximum and non-delete-marked record in an index.
+@param[in] index index tree
+@param[in,out] mtr mini-transaction (may be committed and restarted)
+@return maximum record, page s-latched in mtr
+@retval NULL if there are no records, or if all of them are delete-marked */
static
const rec_t*
-row_search_autoinc_get_rec(
-/*=======================*/
- btr_pcur_t* pcur, /*!< in: the current cursor */
- mtr_t* mtr) /*!< in: mini transaction */
+row_search_get_max_rec(
+ dict_index_t* index,
+ mtr_t* mtr)
{
+ btr_pcur_t pcur;
+ const rec_t* rec;
+ /* Open at the high/right end (false), and init cursor */
+ btr_pcur_open_at_index_side(
+ false, index, BTR_SEARCH_LEAF, &pcur, true, 0, mtr);
+
do {
- const rec_t* rec = btr_pcur_get_rec(pcur);
+ const page_t* page;
+
+ page = btr_pcur_get_page(&pcur);
+ rec = page_find_rec_max_not_deleted(page);
if (page_rec_is_user_rec(rec)) {
- return(rec);
+ break;
+ } else {
+ rec = NULL;
}
- } while (btr_pcur_move_to_prev(pcur, mtr));
+ btr_pcur_move_before_first_on_page(&pcur);
+ } while (btr_pcur_move_to_prev(&pcur, mtr));
- return(NULL);
+ btr_pcur_close(&pcur);
+
+ return(rec);
}
/*******************************************************************//**
@@ -5373,55 +5388,30 @@ row_search_max_autoinc(
const char* col_name, /*!< in: name of autoinc column */
ib_uint64_t* value) /*!< out: AUTOINC value read */
{
- ulint i;
- ulint n_cols;
- dict_field_t* dfield = NULL;
+ dict_field_t* dfield = dict_index_get_nth_field(index, 0);
dberr_t error = DB_SUCCESS;
-
- n_cols = dict_index_get_n_ordering_defined_by_user(index);
-
- /* Search the index for the AUTOINC column name */
- for (i = 0; i < n_cols; ++i) {
- dfield = dict_index_get_nth_field(index, i);
-
- if (strcmp(col_name, dfield->name) == 0) {
- break;
- }
- }
-
*value = 0;
- /* Must find the AUTOINC column name */
- if (i < n_cols && dfield) {
+ if (strcmp(col_name, dfield->name) != 0) {
+ error = DB_RECORD_NOT_FOUND;
+ } else {
mtr_t mtr;
- btr_pcur_t pcur;
+ const rec_t* rec;
mtr_start(&mtr);
- /* Open at the high/right end (false), and init cursor */
- btr_pcur_open_at_index_side(
- false, index, BTR_SEARCH_LEAF, &pcur, true, 0, &mtr);
-
- if (!page_is_empty(btr_pcur_get_page(&pcur))) {
- const rec_t* rec;
-
- rec = row_search_autoinc_get_rec(&pcur, &mtr);
+ rec = row_search_get_max_rec(index, &mtr);
- if (rec != NULL) {
- ibool unsigned_type = (
- dfield->col->prtype & DATA_UNSIGNED);
+ if (rec != NULL) {
+ ibool unsigned_type = (
+ dfield->col->prtype & DATA_UNSIGNED);
- *value = row_search_autoinc_read_column(
- index, rec, i,
- dfield->col->mtype, unsigned_type);
- }
+ *value = row_search_autoinc_read_column(
+ index, rec, 0,
+ dfield->col->mtype, unsigned_type);
}
- btr_pcur_close(&pcur);
-
mtr_commit(&mtr);
- } else {
- error = DB_RECORD_NOT_FOUND;
}
return(error);
diff --git a/storage/xtradb/row/row0uins.cc b/storage/xtradb/row/row0uins.cc
index 7b50d8b62ae..849bf096492 100644
--- a/storage/xtradb/row/row0uins.cc
+++ b/storage/xtradb/row/row0uins.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2014, 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
@@ -109,8 +109,7 @@ row_undo_ins_remove_clust_rec(
mem_heap_t* heap = NULL;
const ulint* offsets = rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED, &heap);
- row_log_table_delete(
- rec, index, offsets, true, node->trx->id);
+ row_log_table_delete(rec, index, offsets, NULL);
mem_heap_free(heap);
}
diff --git a/storage/xtradb/row/row0umod.cc b/storage/xtradb/row/row0umod.cc
index 3c70c3e662b..29252c7834a 100644
--- a/storage/xtradb/row/row0umod.cc
+++ b/storage/xtradb/row/row0umod.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2014, 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
@@ -86,6 +86,8 @@ row_undo_mod_clust_low(
before the update, or NULL if
the table is not being rebuilt online or
the PRIMARY KEY definition does not change */
+ byte* sys, /*!< out: DB_TRX_ID, DB_ROLL_PTR
+ for row_log_table_delete() */
que_thr_t* thr, /*!< in: query thread */
mtr_t* mtr, /*!< in: mtr; must be committed before
latching any further pages */
@@ -115,7 +117,7 @@ row_undo_mod_clust_low(
&& dict_index_is_online_ddl(btr_cur_get_index(btr_cur))) {
*rebuilt_old_pk = row_log_table_get_pk(
btr_cur_get_rec(btr_cur),
- btr_cur_get_index(btr_cur), NULL, &heap);
+ btr_cur_get_index(btr_cur), NULL, sys, &heap);
} else {
*rebuilt_old_pk = NULL;
}
@@ -277,12 +279,13 @@ row_undo_mod_clust(
mem_heap_t* offsets_heap = NULL;
ulint* offsets = NULL;
const dtuple_t* rebuilt_old_pk;
+ byte sys[DATA_TRX_ID_LEN + DATA_ROLL_PTR_LEN];
/* Try optimistic processing of the record, keeping changes within
the index page */
err = row_undo_mod_clust_low(node, &offsets, &offsets_heap,
- heap, &rebuilt_old_pk,
+ heap, &rebuilt_old_pk, sys,
thr, &mtr, online
? BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED
: BTR_MODIFY_LEAF);
@@ -296,7 +299,8 @@ row_undo_mod_clust(
mtr_start(&mtr);
err = row_undo_mod_clust_low(
- node, &offsets, &offsets_heap, heap, &rebuilt_old_pk,
+ node, &offsets, &offsets_heap,
+ heap, &rebuilt_old_pk, sys,
thr, &mtr, BTR_MODIFY_TREE);
ut_ad(err == DB_SUCCESS || err == DB_OUT_OF_FILE_SPACE);
}
@@ -322,8 +326,7 @@ row_undo_mod_clust(
break;
case TRX_UNDO_UPD_DEL_REC:
row_log_table_delete(
- btr_pcur_get_rec(pcur), index, offsets,
- true, node->trx->id);
+ btr_pcur_get_rec(pcur), index, offsets, sys);
break;
default:
ut_ad(0);
diff --git a/storage/xtradb/row/row0upd.cc b/storage/xtradb/row/row0upd.cc
index 4cf1c604c47..3ead385c2cd 100644
--- a/storage/xtradb/row/row0upd.cc
+++ b/storage/xtradb/row/row0upd.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2014, 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
@@ -1948,9 +1948,7 @@ row_upd_clust_rec_by_insert_inherit_func(
data += len - BTR_EXTERN_FIELD_REF_SIZE;
/* The pointer must not be zero. */
ut_a(memcmp(data, field_ref_zero, BTR_EXTERN_FIELD_REF_SIZE));
- /* The BLOB must be owned. */
- ut_a(!(data[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
-
+ data[BTR_EXTERN_LEN] &= ~BTR_EXTERN_OWNER_FLAG;
data[BTR_EXTERN_LEN] |= BTR_EXTERN_INHERITED_FLAG;
/* The BTR_EXTERN_INHERITED_FLAG only matters in
rollback. Purge will always free the extern fields of
@@ -2055,7 +2053,13 @@ err_exit:
rec, offsets, entry, node->update);
if (change_ownership) {
- btr_pcur_store_position(pcur, mtr);
+ /* The blobs are disowned here, expecting the
+ insert down below to inherit them. But if the
+ insert fails, then this disown will be undone
+ when the operation is rolled back. */
+ btr_cur_disown_inherited_fields(
+ btr_cur_get_page_zip(btr_cur),
+ rec, index, offsets, node->update, mtr);
}
}
@@ -2081,41 +2085,6 @@ err_exit:
? UPD_NODE_INSERT_BLOB
: UPD_NODE_INSERT_CLUSTERED;
- if (err == DB_SUCCESS && change_ownership) {
- /* Mark the non-updated fields disowned by the old record. */
-
- /* NOTE: this transaction has an x-lock on the record
- and therefore other transactions cannot modify the
- record when we have no latch on the page. In addition,
- we assume that other query threads of the same
- transaction do not modify the record in the meantime.
- Therefore we can assert that the restoration of the
- cursor succeeds. */
-
- mtr_start(mtr);
-
- if (!btr_pcur_restore_position(BTR_MODIFY_LEAF, pcur, mtr)) {
- ut_error;
- }
-
- rec = btr_cur_get_rec(btr_cur);
- offsets = rec_get_offsets(rec, index, offsets,
- ULINT_UNDEFINED, &heap);
- ut_ad(page_rec_is_user_rec(rec));
- ut_ad(rec_get_deleted_flag(rec, rec_offs_comp(offsets)));
-
- btr_cur_disown_inherited_fields(
- btr_cur_get_page_zip(btr_cur),
- rec, index, offsets, node->update, mtr);
-
- /* It is not necessary to call row_log_table for
- this, because during online table rebuild, purge will
- not free any BLOBs in the table, whether or not they
- are owned by the clustered index record. */
-
- mtr_commit(mtr);
- }
-
mem_heap_free(heap);
return(err);
@@ -2158,7 +2127,7 @@ row_upd_clust_rec(
if (dict_index_is_online_ddl(index)) {
rebuilt_old_pk = row_log_table_get_pk(
- btr_cur_get_rec(btr_cur), index, offsets, &heap);
+ btr_cur_get_rec(btr_cur), index, offsets, NULL, &heap);
}
/* Try optimistic updating of the record, keeping changes within
diff --git a/storage/xtradb/row/row0vers.cc b/storage/xtradb/row/row0vers.cc
index bde796831c6..9f1fc13ee09 100644
--- a/storage/xtradb/row/row0vers.cc
+++ b/storage/xtradb/row/row0vers.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2014, 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
@@ -73,6 +73,8 @@ row_vers_impl_x_locked_low(
ulint* clust_offsets;
mem_heap_t* heap;
+ DBUG_ENTER("row_vers_impl_x_locked_low");
+
ut_ad(rec_offs_validate(rec, index, offsets));
heap = mem_heap_create(1024);
@@ -92,7 +94,7 @@ row_vers_impl_x_locked_low(
trx_sys_get_max_trx_id());
}
mem_heap_free(heap);
- return(0);
+ DBUG_RETURN(0);
}
comp = page_rec_is_comp(rec);
@@ -131,17 +133,37 @@ row_vers_impl_x_locked_low(
clust_rec, mtr, version, clust_index, clust_offsets,
heap, &prev_version);
- /* Free version and clust_offsets. */
+ /* The oldest visible clustered index version must not be
+ delete-marked, because we never start a transaction by
+ inserting a delete-marked record. */
+ ut_ad(prev_version
+ || !rec_get_deleted_flag(version, comp)
+ || !trx_rw_is_active(trx_id, NULL));
+ /* Free version and clust_offsets. */
mem_heap_free(old_heap);
if (prev_version == NULL) {
- /* clust_rec should be a fresh insert, because
- no previous version was found or the transaction
- has committed. The caller has to recheck as the
- synopsis of this function states, whether trx_id
- is active or not. */
+ /* We reached the oldest visible version without
+ finding an older version of clust_rec that would
+ match the secondary index record. If the secondary
+ index record is not delete marked, then clust_rec
+ is considered the correct match of the secondary
+ index record and hence holds the implicit lock. */
+
+ if (rec_del) {
+ /* The secondary index record is del marked.
+ So, the implicit lock holder of clust_rec
+ did not modify the secondary index record yet,
+ and is not holding an implicit lock on it.
+
+ This assumes that whenever a row is inserted
+ or updated, the leaf page record always is
+ created with a clear delete-mark flag.
+ (We never insert a delete-marked record.) */
+ trx_id = 0;
+ }
break;
}
@@ -237,8 +259,11 @@ row_vers_impl_x_locked_low(
}
}
+ DBUG_PRINT("info", ("Implicit lock is held by trx:%lu",
+ static_cast<unsigned long>(trx_id)));
+
mem_heap_free(heap);
- return(trx_id);
+ DBUG_RETURN(trx_id);
}
/*****************************************************************//**
diff --git a/storage/xtradb/srv/srv0conc.cc b/storage/xtradb/srv/srv0conc.cc
index 413d5c4eab2..6c15753246a 100644
--- a/storage/xtradb/srv/srv0conc.cc
+++ b/storage/xtradb/srv/srv0conc.cc
@@ -271,7 +271,7 @@ srv_conc_enter_innodb_with_atomics(
&& sleep_in_us > srv_adaptive_max_sleep_delay) {
sleep_in_us = srv_adaptive_max_sleep_delay;
- srv_thread_sleep_delay = sleep_in_us;
+ srv_thread_sleep_delay = static_cast<ulong>(sleep_in_us);
}
os_thread_sleep(sleep_in_us);
diff --git a/storage/xtradb/srv/srv0srv.cc b/storage/xtradb/srv/srv0srv.cc
index 953bbba11f7..001a9257c92 100644
--- a/storage/xtradb/srv/srv0srv.cc
+++ b/storage/xtradb/srv/srv0srv.cc
@@ -3,6 +3,7 @@
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
+Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -359,6 +360,9 @@ UNIV_INTERN ulong srv_flushing_avg_loops = 30;
/* The tid of the cleaner thread */
UNIV_INTERN os_tid_t srv_cleaner_tid;
+/* The tid of the LRU manager thread */
+UNIV_INTERN os_tid_t srv_lru_manager_tid;
+
/* The tids of the purge threads */
UNIV_INTERN os_tid_t srv_purge_tids[SRV_MAX_N_PURGE_THREADS];
@@ -368,7 +372,7 @@ UNIV_INTERN os_tid_t srv_io_tids[SRV_MAX_N_IO_THREADS];
/* The tid of the master thread */
UNIV_INTERN os_tid_t srv_master_tid;
-/* The relative scheduling priority of the cleaner thread */
+/* The relative scheduling priority of the cleaner and LRU manager threads */
UNIV_INTERN ulint srv_sched_priority_cleaner = 19;
/* The relative scheduling priority of the purge threads */
@@ -510,8 +514,8 @@ counters_pad_end[CACHE_LINE_SIZE] __attribute__((unused)) = {0};
/* Set the following to 0 if you want InnoDB to write messages on
stderr on startup/shutdown. */
UNIV_INTERN ibool srv_print_verbose_log = TRUE;
-UNIV_INTERN ibool srv_print_innodb_monitor = FALSE;
-UNIV_INTERN ibool srv_print_innodb_lock_monitor = FALSE;
+UNIV_INTERN my_bool srv_print_innodb_monitor = FALSE;
+UNIV_INTERN my_bool srv_print_innodb_lock_monitor = FALSE;
UNIV_INTERN ibool srv_print_innodb_tablespace_monitor = FALSE;
UNIV_INTERN ibool srv_print_innodb_table_monitor = FALSE;
@@ -616,6 +620,9 @@ current_time % 5 != 0. */
? thd_lock_wait_timeout((trx)->mysql_thd) \
: 0)
+/** Simulate compression failures. */
+UNIV_INTERN uint srv_simulate_comp_failures = 0;
+
/*
IMPLEMENTATION OF THE SERVER MAIN PROGRAM
=========================================
@@ -3284,7 +3291,8 @@ srv_purge_coordinator_suspend(
rw_lock_x_lock(&purge_sys->latch);
- stop = (purge_sys->state == PURGE_STATE_STOP);
+ stop = (srv_shutdown_state == SRV_SHUTDOWN_NONE
+ && purge_sys->state == PURGE_STATE_STOP);
if (!stop) {
ut_a(purge_sys->n_stop == 0);
@@ -3372,8 +3380,9 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
/* If there are no records to purge or the last
purge didn't purge any records then wait for activity. */
- if (purge_sys->state == PURGE_STATE_STOP
- || n_total_purged == 0) {
+ if (srv_shutdown_state == SRV_SHUTDOWN_NONE
+ && (purge_sys->state == PURGE_STATE_STOP
+ || n_total_purged == 0)) {
srv_purge_coordinator_suspend(slot, rseg_history_len);
}
diff --git a/storage/xtradb/srv/srv0start.cc b/storage/xtradb/srv/srv0start.cc
index 64d2d4cc896..c8fbbd74344 100644
--- a/storage/xtradb/srv/srv0start.cc
+++ b/storage/xtradb/srv/srv0start.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 1996, 2014, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2009, Percona Inc.
@@ -162,7 +162,7 @@ UNIV_INTERN mysql_pfs_key_t srv_log_tracking_thread_key;
#endif /* UNIV_PFS_THREAD */
/*********************************************************************//**
-Convert a numeric string that optionally ends in G or M, to a number
+Convert a numeric string that optionally ends in G or M or K, to a number
containing megabytes.
@return next character in string */
static
@@ -186,6 +186,10 @@ srv_parse_megabytes(
case 'M': case 'm':
str++;
break;
+ case 'K': case 'k':
+ size /= 1024;
+ str++;
+ break;
default:
size /= 1024 * 1024;
break;
@@ -222,7 +226,8 @@ srv_file_check_mode(
/* Note: stat.rw_perm is only valid of files */
- if (stat.type == OS_FILE_TYPE_FILE) {
+ if (stat.type == OS_FILE_TYPE_FILE
+ || stat.type == OS_FILE_TYPE_BLOCK) {
if (!stat.rw_perm) {
ib_logf(IB_LOG_LEVEL_ERROR,
@@ -1004,14 +1009,40 @@ size_check:
return(DB_ERROR);
}
skip_size_check:
+
+ /* This is the earliest location where we can load
+ the double write buffer. */
+ if (i == 0) {
+ buf_dblwr_init_or_load_pages(
+ files[i], srv_data_file_names[i], true);
+ }
+
+ bool retry = true;
+check_first_page:
check_msg = fil_read_first_page(
files[i], one_opened, &flags, &space,
min_flushed_lsn, max_flushed_lsn);
if (check_msg) {
+
+ if (retry) {
+ fsp_open_info fsp;
+ const ulint page_no = 0;
+
+ retry = false;
+ fsp.id = 0;
+ fsp.filepath = srv_data_file_names[i];
+ fsp.file = files[i];
+
+ if (fil_user_tablespace_restore_page(
+ &fsp, page_no)) {
+ goto check_first_page;
+ }
+ }
+
ib_logf(IB_LOG_LEVEL_ERROR,
- "%s in data file %s",
- check_msg, name);
+ "%s in data file %s",
+ check_msg, name);
return(DB_ERROR);
}
@@ -1570,6 +1601,16 @@ innobase_start_or_create_for_mysql(void)
# endif /* F_FULLFSYNC */
#endif /* HAVE_DARWIN_THREADS */
+ ib_logf(IB_LOG_LEVEL_INFO,
+ "Using %s to ref count buffer pool pages",
+#ifdef PAGE_ATOMIC_REF_COUNT
+ "atomics"
+#else
+ "mutexes"
+#endif /* PAGE_ATOMIC_REF_COUNT */
+ );
+
+
if (sizeof(ulint) != sizeof(void*)) {
ut_print_timestamp(stderr);
fprintf(stderr,
@@ -2064,6 +2105,9 @@ innobase_start_or_create_for_mysql(void)
return(DB_ERROR);
}
+ recv_sys_create();
+ recv_sys_init(buf_pool_get_curr_size());
+
err = open_or_create_data_files(&create_new_db,
#ifdef UNIV_LOG_ARCHIVE
&min_arch_log_no, &max_arch_log_no,
@@ -2729,6 +2773,7 @@ files_checked:
if (!srv_read_only_mode) {
os_thread_create(buf_flush_page_cleaner_thread, NULL, NULL);
}
+ os_thread_create(buf_flush_lru_manager_thread, NULL, NULL);
#ifdef UNIV_DEBUG
/* buf_debug_prints = TRUE; */
diff --git a/storage/xtradb/sync/sync0arr.cc b/storage/xtradb/sync/sync0arr.cc
index 9dd0259b3f9..95ecf496e82 100644
--- a/storage/xtradb/sync/sync0arr.cc
+++ b/storage/xtradb/sync/sync0arr.cc
@@ -2,6 +2,7 @@
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
+Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -183,6 +184,33 @@ sync_array_get_nth_cell(
}
/******************************************************************//**
+Looks for a cell with the given thread id.
+@return pointer to cell or NULL if not found */
+static
+sync_cell_t*
+sync_array_find_thread(
+/*===================*/
+ sync_array_t* arr, /*!< in: wait array */
+ os_thread_id_t thread) /*!< in: thread id */
+{
+ ulint i;
+ sync_cell_t* cell;
+
+ for (i = 0; i < arr->n_cells; i++) {
+
+ cell = sync_array_get_nth_cell(arr, i);
+
+ if (cell->wait_object != NULL
+ && os_thread_eq(cell->thread, thread)) {
+
+ return(cell); /* Found */
+ }
+ }
+
+ return(NULL); /* Not found */
+}
+
+/******************************************************************//**
Reserves the mutex semaphore protecting a sync array. */
static
void
@@ -441,8 +469,10 @@ static
void
sync_array_cell_print(
/*==================*/
- FILE* file, /*!< in: file where to print */
- sync_cell_t* cell) /*!< in: sync cell */
+ FILE* file, /*!< in: file where to print */
+ sync_cell_t* cell, /*!< in: sync cell */
+ os_thread_id_t* reserver) /*!< out: write reserver or
+ 0 */
{
ib_mutex_t* mutex;
ib_prio_mutex_t* prio_mutex;
@@ -460,16 +490,9 @@ sync_array_cell_print(
innobase_basename(cell->file), (ulong) cell->line,
difftime(time(NULL), cell->reservation_time));
- /* If stacktrace feature is enabled we will send a SIGUSR2
- signal to thread waiting for the semaphore. Signal handler
- will then dump the current stack to error log. */
- if (srv_use_stacktrace) {
-#ifdef __linux__
- pthread_kill(cell->thread, SIGUSR2);
-#endif
- }
if (type == SYNC_MUTEX || type == SYNC_PRIO_MUTEX) {
+
/* We use old_wait_mutex in case the cell has already
been freed meanwhile */
if (type == SYNC_MUTEX) {
@@ -483,18 +506,29 @@ sync_array_cell_print(
}
- fprintf(file,
- "Mutex at %p '%s', lock var %lu\n"
+ if (mutex) {
+ fprintf(file,
+ "Mutex at %p '%s', lock var %lu\n"
#ifdef UNIV_SYNC_DEBUG
- "Last time reserved in file %s line %lu, "
+ "Last time reserved in file %s line %lu, "
#endif /* UNIV_SYNC_DEBUG */
- "waiters flag %lu\n",
- (void*) mutex, mutex->cmutex_name,
- (ulong) mutex->lock_word,
+ "waiters flag %lu\n",
+ (void*) mutex, mutex->cmutex_name,
+ (ulong) mutex->lock_word,
#ifdef UNIV_SYNC_DEBUG
- mutex->file_name, (ulong) mutex->line,
+ mutex->file_name, (ulong) mutex->line,
#endif /* UNIV_SYNC_DEBUG */
- (ulong) mutex->waiters);
+ (ulong) mutex->waiters);
+ }
+
+ /* If stacktrace feature is enabled we will send a SIGUSR2
+ signal to thread waiting for the semaphore. Signal handler
+ will then dump the current stack to error log. */
+ if (srv_use_stacktrace && cell && cell->thread) {
+#ifdef __linux__
+ pthread_kill(cell->thread, SIGUSR2);
+#endif
+ }
if (type == SYNC_PRIO_MUTEX) {
@@ -529,40 +563,47 @@ sync_array_cell_print(
rwlock = &prio_rwlock->base_lock;
}
- fprintf(file,
- " RW-latch at %p '%s'\n",
- (void*) rwlock, rwlock->lock_name);
- writer = rw_lock_get_writer(rwlock);
- if (writer != RW_LOCK_NOT_LOCKED) {
+ if (rwlock) {
fprintf(file,
- "a writer (thread id %lu) has"
- " reserved it in mode %s",
- (ulong) os_thread_pf(rwlock->writer_thread),
- writer == RW_LOCK_EX
- ? " exclusive\n"
- : " wait exclusive\n");
- }
+ " RW-latch at %p '%s'\n",
+ (void*) rwlock, rwlock->lock_name);
- fprintf(file,
- "number of readers %lu, waiters flag %lu, "
- "lock_word: %lx\n"
- "Last time read locked in file %s line %lu\n"
- "Last time write locked in file %s line %lu\n",
- (ulong) rw_lock_get_reader_count(rwlock),
- (ulong) rwlock->waiters,
- rwlock->lock_word,
- innobase_basename(rwlock->last_s_file_name),
- (ulong) rwlock->last_s_line,
- rwlock->last_x_file_name,
- (ulong) rwlock->last_x_line);
+ writer = rw_lock_get_writer(rwlock);
- /* If stacktrace feature is enabled we will send a SIGUSR2
- signal to thread that has locked RW-latch with write mode.
- Signal handler will then dump the current stack to error log. */
- if (writer != RW_LOCK_NOT_LOCKED && srv_use_stacktrace) {
+ if (writer && writer != RW_LOCK_NOT_LOCKED) {
+ fprintf(file,
+ "a writer (thread id %lu) has"
+ " reserved it in mode %s",
+ (ulong) os_thread_pf(rwlock->writer_thread),
+ writer == RW_LOCK_EX
+ ? " exclusive\n"
+ : " wait exclusive\n");
+
+ *reserver = rwlock->writer_thread;
+ }
+
+ fprintf(file,
+ "number of readers %lu, waiters flag %lu, "
+ "lock_word: %lx\n"
+ "Last time read locked in file %s line %lu\n"
+ "Last time write locked in file %s line %lu\n",
+ (ulong) rw_lock_get_reader_count(rwlock),
+ (ulong) rwlock->waiters,
+ rwlock->lock_word,
+ innobase_basename(rwlock->last_s_file_name),
+ (ulong) rwlock->last_s_line,
+ rwlock->last_x_file_name,
+ (ulong) rwlock->last_x_line);
+
+ /* If stacktrace feature is enabled we will send a SIGUSR2
+ signal to thread that has locked RW-latch with write mode.
+ Signal handler will then dump the current stack to error log. */
+ if (writer != RW_LOCK_NOT_LOCKED && srv_use_stacktrace &&
+ rwlock && rwlock->writer_thread) {
#ifdef __linux__
- pthread_kill(rwlock->writer_thread, SIGUSR2);
+ pthread_kill(rwlock->writer_thread, SIGUSR2);
#endif
+ }
}
if (prio_rwlock) {
@@ -584,32 +625,6 @@ sync_array_cell_print(
}
#ifdef UNIV_SYNC_DEBUG
-/******************************************************************//**
-Looks for a cell with the given thread id.
-@return pointer to cell or NULL if not found */
-static
-sync_cell_t*
-sync_array_find_thread(
-/*===================*/
- sync_array_t* arr, /*!< in: wait array */
- os_thread_id_t thread) /*!< in: thread id */
-{
- ulint i;
- sync_cell_t* cell;
-
- for (i = 0; i < arr->n_cells; i++) {
-
- cell = sync_array_get_nth_cell(arr, i);
-
- if (cell->wait_object != NULL
- && os_thread_eq(cell->thread, thread)) {
-
- return(cell); /* Found */
- }
- }
-
- return(NULL); /* Not found */
-}
/******************************************************************//**
Recursion step for deadlock detection.
@@ -671,6 +686,7 @@ sync_array_detect_deadlock(
os_thread_id_t thread;
ibool ret;
rw_lock_debug_t*debug;
+ os_thread_id_t r = 0;
ut_a(arr);
ut_a(start);
@@ -715,7 +731,7 @@ sync_array_detect_deadlock(
"Mutex %p owned by thread %lu file %s line %lu\n",
mutex, (ulong) os_thread_pf(mutex->thread_id),
mutex->file_name, (ulong) mutex->line);
- sync_array_cell_print(stderr, cell);
+ sync_array_cell_print(stderr, cell, &r);
return(TRUE);
}
@@ -754,7 +770,7 @@ sync_array_detect_deadlock(
print:
fprintf(stderr, "rw-lock %p ",
(void*) lock);
- sync_array_cell_print(stderr, cell);
+ sync_array_cell_print(stderr, cell, &r);
rw_lock_debug_print(stderr, debug);
return(TRUE);
}
@@ -1009,6 +1025,7 @@ sync_array_print_long_waits_low(
double diff;
sync_cell_t* cell;
void* wait_object;
+ os_thread_id_t reserver=0;
cell = sync_array_get_nth_cell(arr, i);
@@ -1024,7 +1041,7 @@ sync_array_print_long_waits_low(
if (diff > SYNC_ARRAY_TIMEOUT) {
fputs("InnoDB: Warning: a long semaphore wait:\n",
stderr);
- sync_array_cell_print(stderr, cell);
+ sync_array_cell_print(stderr, cell, &reserver);
*noticed = TRUE;
}
@@ -1039,6 +1056,57 @@ sync_array_print_long_waits_low(
}
}
+ /* We found a long semaphore wait, wait all threads that are
+ waiting for a semaphore. */
+ if (*noticed) {
+ for (i = 0; i < arr->n_cells; i++) {
+ void* wait_object;
+ sync_cell_t* cell;
+ os_thread_id_t reserver=(os_thread_id_t)ULINT_UNDEFINED;
+ ulint loop=0;
+
+ cell = sync_array_get_nth_cell(arr, i);
+
+ wait_object = cell->wait_object;
+
+ if (wait_object == NULL || !cell->waiting) {
+
+ continue;
+ }
+
+ fputs("InnoDB: Warning: semaphore wait:\n",
+ stderr);
+ sync_array_cell_print(stderr, cell, &reserver);
+
+ /* Try to output cell information for writer recursive way */
+ while (reserver != (os_thread_id_t)ULINT_UNDEFINED) {
+ sync_cell_t* reserver_wait;
+
+ reserver_wait = sync_array_find_thread(arr, reserver);
+
+ if (reserver_wait &&
+ reserver_wait->wait_object != NULL &&
+ reserver_wait->waiting) {
+ fputs("InnoDB: Warning: Writer thread is waiting this semaphore:\n",
+ stderr);
+ sync_array_cell_print(stderr, reserver_wait, &reserver);
+
+ if (reserver_wait->thread == reserver) {
+ reserver = (os_thread_id_t)ULINT_UNDEFINED;
+ }
+ } else {
+ reserver = (os_thread_id_t)ULINT_UNDEFINED;
+ }
+
+ /* This is protection against loop */
+ if (loop > 100) {
+ fputs("InnoDB: Warning: Too many waiting threads.\n", stderr);
+ break;
+ }
+ }
+ }
+ }
+
#undef SYNC_ARRAY_TIMEOUT
return(fatal);
@@ -1098,7 +1166,7 @@ sync_array_print_long_waits(
os_thread_sleep(30000000);
- srv_print_innodb_monitor = old_val;
+ srv_print_innodb_monitor = static_cast<my_bool>(old_val);
fprintf(stderr,
"InnoDB: ###### Diagnostic info printed"
" to the standard error stream\n");
@@ -1125,12 +1193,13 @@ sync_array_print_info_low(
for (i = 0; count < arr->n_reserved; ++i) {
sync_cell_t* cell;
+ os_thread_id_t r = 0;
cell = sync_array_get_nth_cell(arr, i);
if (cell->wait_object != NULL) {
count++;
- sync_array_cell_print(file, cell);
+ sync_array_cell_print(file, cell, &r);
}
}
}
diff --git a/storage/xtradb/sync/sync0rw.cc b/storage/xtradb/sync/sync0rw.cc
index 2ff75b55cf6..79741e3cdce 100644
--- a/storage/xtradb/sync/sync0rw.cc
+++ b/storage/xtradb/sync/sync0rw.cc
@@ -151,18 +151,12 @@ UNIV_INTERN mysql_pfs_key_t rw_lock_mutex_key;
To modify the debug info list of an rw-lock, this mutex has to be
acquired in addition to the mutex protecting the lock. */
-UNIV_INTERN ib_mutex_t rw_lock_debug_mutex;
+UNIV_INTERN os_fast_mutex_t rw_lock_debug_mutex;
# ifdef UNIV_PFS_MUTEX
UNIV_INTERN mysql_pfs_key_t rw_lock_debug_mutex_key;
# endif
-/* If deadlock detection does not get immediately the mutex,
-it may wait for this event */
-UNIV_INTERN os_event_t rw_lock_debug_event;
-/* This is set to TRUE, if there may be waiters for the event */
-UNIV_INTERN ibool rw_lock_debug_waiters;
-
/******************************************************************//**
Creates a debug info struct. */
static
@@ -920,22 +914,7 @@ void
rw_lock_debug_mutex_enter(void)
/*===========================*/
{
-loop:
- if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
- return;
- }
-
- os_event_reset(rw_lock_debug_event);
-
- rw_lock_debug_waiters = TRUE;
-
- if (0 == mutex_enter_nowait(&rw_lock_debug_mutex)) {
- return;
- }
-
- os_event_wait(rw_lock_debug_event);
-
- goto loop;
+ os_fast_mutex_lock(&rw_lock_debug_mutex);
}
/******************************************************************//**
@@ -945,12 +924,7 @@ void
rw_lock_debug_mutex_exit(void)
/*==========================*/
{
- mutex_exit(&rw_lock_debug_mutex);
-
- if (rw_lock_debug_waiters) {
- rw_lock_debug_waiters = FALSE;
- os_event_set(rw_lock_debug_event);
- }
+ os_fast_mutex_unlock(&rw_lock_debug_mutex);
}
/******************************************************************//**
diff --git a/storage/xtradb/sync/sync0sync.cc b/storage/xtradb/sync/sync0sync.cc
index d6033d9d2ab..875b89e29c5 100644
--- a/storage/xtradb/sync/sync0sync.cc
+++ b/storage/xtradb/sync/sync0sync.cc
@@ -209,7 +209,10 @@ UNIV_INTERN mysql_pfs_key_t sync_thread_mutex_key;
/** Global list of database mutexes (not OS mutexes) created. */
UNIV_INTERN ut_list_base_node_t mutex_list;
-/** Mutex protecting the mutex_list variable */
+/** Global list of priority mutexes. A subset of mutex_list */
+UNIV_INTERN UT_LIST_BASE_NODE_T(ib_prio_mutex_t) prio_mutex_list;
+
+/** Mutex protecting the mutex_list and prio_mutex_list variables */
UNIV_INTERN ib_mutex_t mutex_list_mutex;
#ifdef UNIV_PFS_MUTEX
@@ -353,6 +356,10 @@ mutex_create_func(
cmutex_name);
mutex->high_priority_waiters = 0;
mutex->high_priority_event = os_event_create();
+
+ mutex_enter(&mutex_list_mutex);
+ UT_LIST_ADD_FIRST(list, prio_mutex_list, mutex);
+ mutex_exit(&mutex_list_mutex);
}
/******************************************************************//**
@@ -426,6 +433,10 @@ mutex_free_func(
/*============*/
ib_prio_mutex_t* mutex) /*!< in: mutex */
{
+ mutex_enter(&mutex_list_mutex);
+ UT_LIST_REMOVE(list, prio_mutex_list, mutex);
+ mutex_exit(&mutex_list_mutex);
+
ut_a(mutex->high_priority_waiters == 0);
os_event_free(mutex->high_priority_event);
mutex_free_func(&mutex->base_mutex);
@@ -1572,6 +1583,7 @@ sync_init(void)
/* Init the mutex list and create the mutex to protect it. */
UT_LIST_INIT(mutex_list);
+ UT_LIST_INIT(prio_mutex_list);
mutex_create(mutex_list_mutex_key, &mutex_list_mutex,
SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG
@@ -1586,11 +1598,7 @@ sync_init(void)
SYNC_NO_ORDER_CHECK);
#ifdef UNIV_SYNC_DEBUG
- mutex_create(rw_lock_debug_mutex_key, &rw_lock_debug_mutex,
- SYNC_NO_ORDER_CHECK);
-
- rw_lock_debug_event = os_event_create();
- rw_lock_debug_waiters = FALSE;
+ os_fast_mutex_init(rw_lock_debug_mutex_key, &rw_lock_debug_mutex);
#endif /* UNIV_SYNC_DEBUG */
}
@@ -1630,10 +1638,16 @@ void
sync_close(void)
/*===========*/
{
- ib_mutex_t* mutex;
+ ib_mutex_t* mutex;
+ ib_prio_mutex_t* prio_mutex;
sync_array_close();
+ for (prio_mutex = UT_LIST_GET_FIRST(prio_mutex_list); prio_mutex;) {
+ mutex_free(prio_mutex);
+ prio_mutex = UT_LIST_GET_FIRST(prio_mutex_list);
+ }
+
for (mutex = UT_LIST_GET_FIRST(mutex_list);
mutex != NULL;
/* No op */) {
@@ -1658,6 +1672,7 @@ sync_close(void)
sync_order_checks_on = FALSE;
sync_thread_level_arrays_free();
+ os_fast_mutex_free(&rw_lock_debug_mutex);
#endif /* UNIV_SYNC_DEBUG */
sync_initialized = FALSE;
diff --git a/storage/xtradb/trx/trx0trx.cc b/storage/xtradb/trx/trx0trx.cc
index 8c4bc087038..1239dd2e026 100644
--- a/storage/xtradb/trx/trx0trx.cc
+++ b/storage/xtradb/trx/trx0trx.cc
@@ -51,6 +51,9 @@ Created 3/26/1996 Heikki Tuuri
#include<set>
+extern "C"
+int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2);
+
/** Set of table_id */
typedef std::set<table_id_t> table_id_set;
@@ -738,6 +741,13 @@ trx_resurrect_insert(
trx->no = TRX_ID_MAX;
}
+ /* trx_start_low() is not called with resurrect, so need to initialize
+ start time here.*/
+ if (trx->state == TRX_STATE_ACTIVE
+ || trx->state == TRX_STATE_PREPARED) {
+ trx->start_time = ut_time();
+ }
+
if (undo->dict_operation) {
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
trx->table_id = undo->table_id;
@@ -825,6 +835,13 @@ trx_resurrect_update(
trx->no = TRX_ID_MAX;
}
+ /* trx_start_low() is not called with resurrect, so need to initialize
+ start time here.*/
+ if (trx->state == TRX_STATE_ACTIVE
+ || trx->state == TRX_STATE_PREPARED) {
+ trx->start_time = ut_time();
+ }
+
if (undo->dict_operation) {
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
trx->table_id = undo->table_id;
@@ -2030,7 +2047,8 @@ state_ok:
}
if (trx->mysql_thd != NULL) {
- innobase_mysql_print_thd(f, trx->mysql_thd, max_query_len);
+ innobase_mysql_print_thd(
+ f, trx->mysql_thd, static_cast<uint>(max_query_len));
}
}
@@ -2124,9 +2142,8 @@ trx_assert_started(
#endif /* UNIV_DEBUG */
/*******************************************************************//**
-Compares the "weight" (or size) of two transactions. Transactions that
-have edited non-transactional tables are considered heavier than ones
-that have not.
+Compares the "weight" (or size) of two transactions. The heavier the weight,
+the more reluctant we will be to choose the transaction as a deadlock victim.
@return TRUE if weight(a) >= weight(b) */
UNIV_INTERN
ibool
@@ -2135,26 +2152,19 @@ trx_weight_ge(
const trx_t* a, /*!< in: the first transaction to be compared */
const trx_t* b) /*!< in: the second transaction to be compared */
{
- ibool a_notrans_edit;
- ibool b_notrans_edit;
-
- /* If mysql_thd is NULL for a transaction we assume that it has
- not edited non-transactional tables. */
-
- a_notrans_edit = a->mysql_thd != NULL
- && thd_has_edited_nontrans_tables(a->mysql_thd);
-
- b_notrans_edit = b->mysql_thd != NULL
- && thd_has_edited_nontrans_tables(b->mysql_thd);
-
- if (a_notrans_edit != b_notrans_edit) {
+ int pref;
- return(a_notrans_edit);
+ /* First ask the upper server layer if it has any preference for which
+ to prefer as a deadlock victim. */
+ pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd);
+ if (pref < 0) {
+ return FALSE;
+ } else if (pref > 0) {
+ return TRUE;
}
- /* Either both had edited non-transactional tables or both had
- not, we fall back to comparing the number of altered/locked
- rows. */
+ /* Upper server layer had no preference, we fall back to comparing the
+ number of altered/locked rows. */
#if 0
fprintf(stderr,
diff --git a/storage/xtradb/ut/ut0ut.cc b/storage/xtradb/ut/ut0ut.cc
index f600ba1a895..15c7bb503cb 100644
--- a/storage/xtradb/ut/ut0ut.cc
+++ b/storage/xtradb/ut/ut0ut.cc
@@ -823,6 +823,8 @@ ut_strerr(
return("FTS query exceeds result cache limit");
case DB_TEMP_FILE_WRITE_FAILURE:
return("Temp file write failure");
+ case DB_FTS_TOO_MANY_WORDS_IN_PHRASE:
+ return("Too many words in a FTS phrase or proximity search");
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */