lab.nexedi.com will be down from Thursday, 20 March 2025, 07:30:00 UTC for a duration of approximately 2 hours

Commit 43293b7a authored by unknown's avatar unknown

Merge XtraDB from Percona-Server 5.1.66-rel14.1 into MariaDB 5.1.

parents fb90c362 1d812468
No related merge requests found
......@@ -54,9 +54,13 @@ EVENTS
FILES
GLOBAL_STATUS
GLOBAL_VARIABLES
INNODB_BUFFER_PAGE
INNODB_BUFFER_PAGE_LRU
INNODB_BUFFER_POOL_PAGES
INNODB_BUFFER_POOL_PAGES_BLOB
INNODB_BUFFER_POOL_PAGES_INDEX
INNODB_BUFFER_POOL_STATS
INNODB_CHANGED_PAGES
INNODB_CMP
INNODB_CMPMEM
INNODB_CMPMEM_RESET
......@@ -89,7 +93,6 @@ TRIGGERS
USER_PRIVILEGES
VIEWS
XTRADB_ADMIN_COMMAND
XTRADB_ENHANCEMENTS
columns_priv
db
event
......@@ -860,6 +863,8 @@ TABLE_NAME COLUMN_NAME PRIVILEGES
COLUMNS TABLE_NAME select
COLUMN_PRIVILEGES TABLE_NAME select
FILES TABLE_NAME select
INNODB_BUFFER_PAGE TABLE_NAME select
INNODB_BUFFER_PAGE_LRU TABLE_NAME select
INNODB_INDEX_STATS table_name select
INNODB_TABLE_STATS table_name select
KEY_COLUMN_USAGE TABLE_NAME select
......@@ -1245,12 +1250,12 @@ DROP PROCEDURE p1;
DROP USER mysql_bug20230@localhost;
SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test');
MAX(table_name)
XTRADB_ENHANCEMENTS
XTRADB_ADMIN_COMMAND
SELECT table_name from information_schema.tables
WHERE table_name=(SELECT MAX(table_name)
FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test'));
table_name
XTRADB_ENHANCEMENTS
XTRADB_ADMIN_COMMAND
DROP TABLE IF EXISTS bug23037;
DROP FUNCTION IF EXISTS get_value;
SELECT COLUMN_NAME, MD5(COLUMN_DEFAULT), LENGTH(COLUMN_DEFAULT) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='bug23037';
......
......@@ -33,13 +33,13 @@ INNODB_BUFFER_POOL_PAGES
PBXT_STATISTICS
INNODB_CMP
INNODB_RSEG
XTRADB_ENHANCEMENTS
INNODB_INDEX_STATS
INNODB_BUFFER_POOL_PAGES_INDEX
XTRADB_ADMIN_COMMAND
INNODB_TRX
INNODB_SYS_TABLES
INNODB_LOCK_WAITS
INNODB_SYS_STATS
INNODB_BUFFER_POOL_STATS
INNODB_LOCKS
INNODB_CMPMEM
INNODB_TABLE_STATS
......@@ -47,7 +47,10 @@ INNODB_SYS_INDEXES
INNODB_CMP_RESET
INNODB_BUFFER_POOL_PAGES_BLOB
INNODB_CMPMEM_RESET
INNODB_INDEX_STATS
INNODB_BUFFER_PAGE
INNODB_CHANGED_PAGES
INNODB_SYS_STATS
INNODB_BUFFER_PAGE_LRU
SELECT t.table_name, c1.column_name
FROM information_schema.tables t
INNER JOIN
......@@ -95,13 +98,13 @@ INNODB_BUFFER_POOL_PAGES page_type
PBXT_STATISTICS ID
INNODB_CMP page_size
INNODB_RSEG rseg_id
XTRADB_ENHANCEMENTS name
INNODB_INDEX_STATS table_schema
INNODB_BUFFER_POOL_PAGES_INDEX index_id
XTRADB_ADMIN_COMMAND result_message
INNODB_TRX trx_id
INNODB_SYS_TABLES SCHEMA
INNODB_LOCK_WAITS requesting_trx_id
INNODB_SYS_STATS INDEX_ID
INNODB_BUFFER_POOL_STATS POOL_SIZE
INNODB_LOCKS lock_id
INNODB_CMPMEM page_size
INNODB_TABLE_STATS table_schema
......@@ -109,7 +112,10 @@ INNODB_SYS_INDEXES TABLE_ID
INNODB_CMP_RESET page_size
INNODB_BUFFER_POOL_PAGES_BLOB space_id
INNODB_CMPMEM_RESET page_size
INNODB_INDEX_STATS table_schema
INNODB_BUFFER_PAGE BLOCK_ID
INNODB_CHANGED_PAGES space_id
INNODB_SYS_STATS INDEX_ID
INNODB_BUFFER_PAGE_LRU LRU_POSITION
SELECT t.table_name, c1.column_name
FROM information_schema.tables t
INNER JOIN
......@@ -157,13 +163,13 @@ INNODB_BUFFER_POOL_PAGES page_type
PBXT_STATISTICS ID
INNODB_CMP page_size
INNODB_RSEG rseg_id
XTRADB_ENHANCEMENTS name
INNODB_INDEX_STATS table_schema
INNODB_BUFFER_POOL_PAGES_INDEX index_id
XTRADB_ADMIN_COMMAND result_message
INNODB_TRX trx_id
INNODB_SYS_TABLES SCHEMA
INNODB_LOCK_WAITS requesting_trx_id
INNODB_SYS_STATS INDEX_ID
INNODB_BUFFER_POOL_STATS POOL_SIZE
INNODB_LOCKS lock_id
INNODB_CMPMEM page_size
INNODB_TABLE_STATS table_schema
......@@ -171,7 +177,10 @@ INNODB_SYS_INDEXES TABLE_ID
INNODB_CMP_RESET page_size
INNODB_BUFFER_POOL_PAGES_BLOB space_id
INNODB_CMPMEM_RESET page_size
INNODB_INDEX_STATS table_schema
INNODB_BUFFER_PAGE BLOCK_ID
INNODB_CHANGED_PAGES space_id
INNODB_SYS_STATS INDEX_ID
INNODB_BUFFER_PAGE_LRU LRU_POSITION
select 1 as f1 from information_schema.tables where "CHARACTER_SETS"=
(select cast(table_name as char) from information_schema.tables
order by table_name limit 1) limit 1;
......@@ -203,9 +212,13 @@ EVENTS information_schema.EVENTS 1
FILES information_schema.FILES 1
GLOBAL_STATUS information_schema.GLOBAL_STATUS 1
GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1
INNODB_BUFFER_PAGE information_schema.INNODB_BUFFER_PAGE 1
INNODB_BUFFER_PAGE_LRU information_schema.INNODB_BUFFER_PAGE_LRU 1
INNODB_BUFFER_POOL_PAGES information_schema.INNODB_BUFFER_POOL_PAGES 1
INNODB_BUFFER_POOL_PAGES_BLOB information_schema.INNODB_BUFFER_POOL_PAGES_BLOB 1
INNODB_BUFFER_POOL_PAGES_INDEX information_schema.INNODB_BUFFER_POOL_PAGES_INDEX 1
INNODB_BUFFER_POOL_STATS information_schema.INNODB_BUFFER_POOL_STATS 1
INNODB_CHANGED_PAGES information_schema.INNODB_CHANGED_PAGES 1
INNODB_CMP information_schema.INNODB_CMP 1
INNODB_CMPMEM information_schema.INNODB_CMPMEM 1
INNODB_CMPMEM_RESET information_schema.INNODB_CMPMEM_RESET 1
......@@ -238,7 +251,6 @@ TABLE_PRIVILEGES information_schema.TABLE_PRIVILEGES 1
TRIGGERS information_schema.TRIGGERS 1
USER_PRIVILEGES information_schema.USER_PRIVILEGES 1
VIEWS information_schema.VIEWS 1
XTRADB_ENHANCEMENTS information_schema.XTRADB_ENHANCEMENTS 1
Database: information_schema
+---------------------------------------+
| Tables |
......@@ -275,13 +287,13 @@ Database: information_schema
| PBXT_STATISTICS |
| INNODB_CMP |
| INNODB_RSEG |
| XTRADB_ENHANCEMENTS |
| INNODB_INDEX_STATS |
| INNODB_BUFFER_POOL_PAGES_INDEX |
| XTRADB_ADMIN_COMMAND |
| INNODB_TRX |
| INNODB_SYS_TABLES |
| INNODB_LOCK_WAITS |
| INNODB_SYS_STATS |
| INNODB_BUFFER_POOL_STATS |
| INNODB_LOCKS |
| INNODB_CMPMEM |
| INNODB_TABLE_STATS |
......@@ -289,7 +301,10 @@ Database: information_schema
| INNODB_CMP_RESET |
| INNODB_BUFFER_POOL_PAGES_BLOB |
| INNODB_CMPMEM_RESET |
| INNODB_INDEX_STATS |
| INNODB_BUFFER_PAGE |
| INNODB_CHANGED_PAGES |
| INNODB_SYS_STATS |
| INNODB_BUFFER_PAGE_LRU |
+---------------------------------------+
Database: INFORMATION_SCHEMA
+---------------------------------------+
......@@ -327,13 +342,13 @@ Database: INFORMATION_SCHEMA
| PBXT_STATISTICS |
| INNODB_CMP |
| INNODB_RSEG |
| XTRADB_ENHANCEMENTS |
| INNODB_INDEX_STATS |
| INNODB_BUFFER_POOL_PAGES_INDEX |
| XTRADB_ADMIN_COMMAND |
| INNODB_TRX |
| INNODB_SYS_TABLES |
| INNODB_LOCK_WAITS |
| INNODB_SYS_STATS |
| INNODB_BUFFER_POOL_STATS |
| INNODB_LOCKS |
| INNODB_CMPMEM |
| INNODB_TABLE_STATS |
......@@ -341,7 +356,10 @@ Database: INFORMATION_SCHEMA
| INNODB_CMP_RESET |
| INNODB_BUFFER_POOL_PAGES_BLOB |
| INNODB_CMPMEM_RESET |
| INNODB_INDEX_STATS |
| INNODB_BUFFER_PAGE |
| INNODB_CHANGED_PAGES |
| INNODB_SYS_STATS |
| INNODB_BUFFER_PAGE_LRU |
+---------------------------------------+
Wildcard: inf_rmation_schema
+--------------------+
......@@ -351,5 +369,5 @@ Wildcard: inf_rmation_schema
+--------------------+
SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA;
table_schema count(*)
information_schema 47
information_schema 50
mysql 22
......@@ -3198,7 +3198,7 @@ c21 CHAR(255), c22 CHAR(255), c23 CHAR(255), c24 CHAR(255),
c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255),
c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255)
) ENGINE = InnoDB;
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
......
......@@ -1096,7 +1096,7 @@ PRIMARY KEY (b(10), a), INDEX (c(10))
INSERT INTO bug12547647 VALUES (5,repeat('khdfo5AlOq',1900),repeat('g',7731));
COMMIT;
UPDATE bug12547647 SET c = REPEAT('b',16928);
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
DROP TABLE bug12547647;
SET @r=REPEAT('a',500);
CREATE TABLE t1(a INT,
......
......@@ -125,12 +125,12 @@ CREATE TABLE t1(
c TEXT NOT NULL, d TEXT NOT NULL,
PRIMARY KEY (c(767),d(767)))
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
CREATE TABLE t1(
c TEXT NOT NULL, d TEXT NOT NULL,
PRIMARY KEY (c(767),d(767)))
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2 CHARSET=ASCII;
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
CREATE TABLE t1(
c TEXT NOT NULL, d TEXT NOT NULL,
PRIMARY KEY (c(767),d(767)))
......@@ -138,7 +138,7 @@ ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 CHARSET=ASCII;
drop table t1;
CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440)))
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438)))
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512));
......
......@@ -3151,7 +3151,7 @@ c21 CHAR(255), c22 CHAR(255), c23 CHAR(255), c24 CHAR(255),
c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255),
c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255)
) ENGINE = InnoDB;
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
DROP TABLE IF EXISTS t1;
Warnings:
Note 1051 Unknown table 't1'
......
......@@ -8,7 +8,7 @@ ERROR HY000: Too big row
SHOW WARNINGS;
Level Code Message
Error 139 Too big row
Error 1118 Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
Error 1118 Row size too large (> 8126). Changing some columns to TEXT or BLOB may help. In current row format, BLOB prefix of 0 bytes is stored inline.
DROP TABLE bug53591;
SET GLOBAL innodb_file_format=Antelope;
SET GLOBAL innodb_file_per_table=0;
......@@ -774,7 +774,7 @@ c21 CHAR(255), c22 CHAR(255), c23 CHAR(255), c24 CHAR(255),
c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255),
c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255)
) ENGINE = InnoDB;
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
ERROR 42000: Row size too large (> 8126). Changing some columns to TEXT or BLOB or using ROW_FORMAT=DYNAMIC or ROW_FORMAT=COMPRESSED may help. In current row format, BLOB prefix of 768 bytes is stored inline.
SET innodb_strict_mode=OFF;
DROP TABLE IF EXISTS t1;
Warnings:
......
......@@ -62,7 +62,7 @@ SET(XTRADB_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
ibuf/ibuf0ibuf.c
pars/lexyy.c pars/pars0grm.c pars/pars0opt.c pars/pars0pars.c pars/pars0sym.c
lock/lock0lock.c lock/lock0iter.c
log/log0log.c log/log0recv.c
log/log0log.c log/log0recv.c log/log0online.c
mach/mach0data.c
mem/mem0mem.c mem/mem0pool.c
mtr/mtr0log.c mtr/mtr0mtr.c
......
2012-08-29 The InnoDB Team
* btr/btr0btr.c, page/page0cur.c, page/page0page.c:
Fix Bug#14554000 CRASH IN PAGE_REC_GET_NTH_CONST(NTH=0)
DURING COMPRESSED PAGE SPLIT
2012-08-16 The InnoDB Team
* btr/btr0cur.c:
Fix Bug#12595091 POSSIBLY INVALID ASSERTION IN
BTR_CUR_PESSIMISTIC_UPDATE()
2012-08-16 The InnoDB Team
* btr/btr0btr.c, btr/btr0cur.c:
Fix Bug#12845774 OPTIMISTIC INSERT/UPDATE USES WRONG HEURISTICS FOR
COMPRESSED PAGE SIZE
2012-08-16 The InnoDB Team
* btr/btr0cur.c, page/page0page.c:
Fix Bug#13523839 ASSERTION FAILURES ON COMPRESSED INNODB TABLES
2012-08-07 The InnoDB Team
* btr/btr0pcur.c, row/row0merge.c:
Fix Bug#14399148 INNODB TABLES UNDER LOAD PRODUCE DUPLICATE COPIES
OF ROWS IN QUERIES
2012-03-15 The InnoDB Team
* fil/fil0fil.c, ibuf/ibuf0ibuf.c, include/fil0fil.h,
......
......@@ -101,6 +101,7 @@ noinst_HEADERS= \
include/lock0types.h \
include/log0log.h \
include/log0log.ic \
include/log0online.h \
include/log0recv.h \
include/log0recv.ic \
include/mach0data.h \
......@@ -226,7 +227,6 @@ noinst_HEADERS= \
include/ut0vec.h \
include/ut0vec.ic \
include/ut0wqueue.h \
handler/innodb_patch_info.h \
mem/mem0dbg.c
noinst_LTLIBRARIES= @plugin_xtradb_static_target@
......@@ -265,6 +265,7 @@ libxtradb_la_SOURCES= \
lock/lock0iter.c \
lock/lock0lock.c \
log/log0log.c \
log/log0online.c \
log/log0recv.c \
mach/mach0data.c \
mem/mem0mem.c \
......
......@@ -664,6 +664,12 @@ btr_root_fseg_validate(
{
ulint offset = mach_read_from_2(seg_header + FSEG_HDR_OFFSET);
if (UNIV_UNLIKELY(srv_pass_corrupt_table)) {
return (mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space)
&& (offset >= FIL_PAGE_DATA)
&& (offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
}
ut_a(mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space);
ut_a(offset >= FIL_PAGE_DATA);
ut_a(offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
......@@ -704,6 +710,17 @@ btr_root_block_get(
if (!dict_index_is_ibuf(index)) {
const page_t* root = buf_block_get_frame(block);
if (UNIV_UNLIKELY(srv_pass_corrupt_table)) {
if (!btr_root_fseg_validate(FIL_PAGE_DATA
+ PAGE_BTR_SEG_LEAF
+ root, space))
return(NULL);
if (!btr_root_fseg_validate(FIL_PAGE_DATA
+ PAGE_BTR_SEG_TOP
+ root, space))
return(NULL);
return(block);
}
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ root, space));
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
......@@ -1852,6 +1869,7 @@ btr_root_raise_and_insert(
root = btr_cur_get_page(cursor);
root_block = btr_cur_get_block(cursor);
root_page_zip = buf_block_get_page_zip(root_block);
ut_ad(page_get_n_recs(root) > 0);
#ifdef UNIV_ZIP_DEBUG
ut_a(!root_page_zip || page_zip_validate(root_page_zip, root));
#endif /* UNIV_ZIP_DEBUG */
......@@ -2332,12 +2350,20 @@ btr_insert_on_non_leaf_level_func(
BTR_CONT_MODIFY_TREE,
&cursor, 0, file, line, mtr);
err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
| BTR_KEEP_SYS_FLAG
| BTR_NO_UNDO_LOG_FLAG,
&cursor, tuple, &rec,
&dummy_big_rec, 0, NULL, mtr);
ut_a(err == DB_SUCCESS);
ut_ad(cursor.flag == BTR_CUR_BINARY);
err = btr_cur_optimistic_insert(
BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG
| BTR_NO_UNDO_LOG_FLAG, &cursor, tuple, &rec,
&dummy_big_rec, 0, NULL, mtr);
if (err == DB_FAIL) {
err = btr_cur_pessimistic_insert(
BTR_NO_LOCKING_FLAG | BTR_KEEP_SYS_FLAG
| BTR_NO_UNDO_LOG_FLAG,
&cursor, tuple, &rec, &dummy_big_rec, 0, NULL, mtr);
ut_a(err == DB_SUCCESS);
}
}
/**************************************************************//**
......@@ -3262,6 +3288,7 @@ btr_compress(
if (adjust) {
nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor));
ut_ad(nth_rec > 0);
}
/* Decide the page to which we try to merge and which will inherit
......@@ -3497,6 +3524,7 @@ btr_compress(
mem_heap_free(heap);
if (adjust) {
ut_ad(nth_rec > 0);
btr_cur_position(
index,
page_rec_get_nth(merge_block->frame, nth_rec),
......@@ -4009,8 +4037,22 @@ btr_index_page_validate(
{
page_cur_t cur;
ibool ret = TRUE;
#ifndef DBUG_OFF
ulint nth = 1;
#endif /* !DBUG_OFF */
page_cur_set_before_first(block, &cur);
/* Directory slot 0 should only contain the infimum record. */
DBUG_EXECUTE_IF("check_table_rec_next",
ut_a(page_rec_get_nth_const(
page_cur_get_page(&cur), 0)
== cur.rec);
ut_a(page_dir_slot_get_n_owned(
page_dir_get_nth_slot(
page_cur_get_page(&cur), 0))
== 1););
page_cur_move_to_next(&cur);
for (;;) {
......@@ -4024,6 +4066,16 @@ btr_index_page_validate(
return(FALSE);
}
/* Verify that page_rec_get_nth_const() is correctly
retrieving each record. */
DBUG_EXECUTE_IF("check_table_rec_next",
ut_a(cur.rec == page_rec_get_nth_const(
page_cur_get_page(&cur),
page_rec_get_n_recs_before(
cur.rec)));
ut_a(nth++ == page_rec_get_n_recs_before(
cur.rec)););
page_cur_move_to_next(&cur);
}
......@@ -4435,6 +4487,12 @@ btr_validate_index(
mtr_x_lock(dict_index_get_lock(index), &mtr);
root = btr_root_get(index, &mtr);
if (UNIV_UNLIKELY(srv_pass_corrupt_table && !root)) {
mtr_commit(&mtr);
return(FALSE);
}
n = btr_page_get_level(root, &mtr);
for (i = 0; i <= n && !trx_is_interrupted(trx); i++) {
......
......@@ -1307,7 +1307,12 @@ btr_cur_optimistic_insert(
if (UNIV_UNLIKELY(reorg)) {
ut_a(zip_size);
ut_a(*rec);
/* It's possible for rec to be NULL if the
page is compressed. This is because a
reorganized page may become incompressible. */
if (!*rec) {
goto fail;
}
}
}
......@@ -1443,20 +1448,9 @@ btr_cur_pessimistic_insert(
ut_ad((thr && thr_get_trx(thr)->fake_changes) || mtr_memo_contains(mtr, btr_cur_get_block(cursor),
MTR_MEMO_PAGE_X_FIX));
/* Try first an optimistic insert; reset the cursor flag: we do not
assume anything of how it was positioned */
cursor->flag = BTR_CUR_BINARY;
err = btr_cur_optimistic_insert(flags, cursor, entry, rec,
big_rec, n_ext, thr, mtr);
if (err != DB_FAIL) {
return(err);
}
/* Retry with a pessimistic insert. Check locks and write to undo log,
if specified */
/* Check locks and write to undo log, if specified */
err = btr_cur_ins_lock_and_undo(flags, cursor, entry,
thr, mtr, &dummy_inh);
......@@ -2083,8 +2077,12 @@ btr_cur_optimistic_update(
goto err_exit;
}
max_size = old_rec_size
+ page_get_max_insert_size_after_reorganize(page, 1);
/* We do not attempt to reorganize if the page is compressed.
This is because the page may fail to compress after reorganization. */
max_size = page_zip
? page_get_max_insert_size(page, 1)
: (old_rec_size
+ page_get_max_insert_size_after_reorganize(page, 1));
if (!(((max_size >= BTR_CUR_PAGE_REORGANIZE_LIMIT)
&& (max_size >= new_rec_size))
......@@ -2452,7 +2450,12 @@ btr_cur_pessimistic_update(
err = DB_SUCCESS;
goto return_after_reservations;
} else {
ut_a(optim_err != DB_UNDERFLOW);
/* If the page is compressed and it initially
compresses very well, and there is a subsequent insert
of a badly-compressing record, it is possible for
btr_cur_optimistic_update() to return DB_UNDERFLOW and
btr_cur_insert_if_possible() to return FALSE. */
ut_a(page_zip || optim_err != DB_UNDERFLOW);
/* Out of space: reset the free bits. */
if (!dict_index_is_clust(index)
......@@ -2480,8 +2483,10 @@ btr_cur_pessimistic_update(
record on its page? */
was_first = page_cur_is_before_first(page_cursor);
/* The first parameter means that no lock checking and undo logging
is made in the insert */
/* Lock checks and undo logging were already performed by
btr_cur_upd_lock_and_undo(). We do not try
btr_cur_optimistic_insert() because
btr_cur_insert_if_possible() already failed above. */
err = btr_cur_pessimistic_insert(BTR_NO_UNDO_LOG_FLAG
| BTR_NO_LOCKING_FLAG
......@@ -3483,6 +3488,8 @@ btr_estimate_n_rows_in_range(
n_rows = n_rows * 2;
}
DBUG_EXECUTE_IF("bug14007649", return(n_rows););
/* Do not estimate the number of rows in the range
to over 1 / 2 of the estimated rows in the whole
table */
......@@ -3582,9 +3589,9 @@ btr_record_not_null_field_in_rec(
for (i = 0; i < n_unique; i++) {
if (rec_offs_nth_sql_null(offsets, i)) {
/* Break if we hit the first NULL value */
break;
}
n_not_null[i]++;
}
}
......
......@@ -342,44 +342,39 @@ btr_pcur_restore_position_func(
/* Restore the old search mode */
cursor->search_mode = old_mode;
if (btr_pcur_is_on_user_rec(cursor)) {
switch (cursor->rel_pos) {
case BTR_PCUR_ON:
if (!cmp_dtuple_rec(
tuple, btr_pcur_get_rec(cursor),
rec_get_offsets(btr_pcur_get_rec(cursor),
index, NULL,
ULINT_UNDEFINED, &heap))) {
/* We have to store the NEW value for
the modify clock, since the cursor can
now be on a different page! But we can
retain the value of old_rec */
cursor->block_when_stored =
btr_pcur_get_block(cursor);
cursor->modify_clock =
buf_block_get_modify_clock(
cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
mem_heap_free(heap);
return(TRUE);
}
break;
case BTR_PCUR_BEFORE:
page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
break;
case BTR_PCUR_AFTER:
page_cur_move_to_prev(btr_pcur_get_page_cur(cursor));
break;
switch (cursor->rel_pos) {
case BTR_PCUR_ON:
if (btr_pcur_is_on_user_rec(cursor)
&& !cmp_dtuple_rec(
tuple, btr_pcur_get_rec(cursor),
rec_get_offsets(btr_pcur_get_rec(cursor),
index, NULL,
ULINT_UNDEFINED, &heap))) {
/* We have to store the NEW value for
the modify clock, since the cursor can
now be on a different page! But we can
retain the value of old_rec */
cursor->block_when_stored =
btr_pcur_get_block(cursor);
cursor->modify_clock =
buf_block_get_modify_clock(
cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
mem_heap_free(heap);
return(TRUE);
}
#ifdef UNIV_DEBUG
default:
ut_error;
/* fall through */
case BTR_PCUR_BEFORE:
case BTR_PCUR_AFTER:
break;
default:
ut_error;
#endif /* UNIV_DEBUG */
}
}
mem_heap_free(heap);
......
......@@ -2123,6 +2123,7 @@ buf_page_get_gen(
if (mode == BUF_GET_IF_IN_POOL && ibuf_debug) {
/* Try to evict the block from the buffer pool, to use the
insert buffer as much as possible. */
ulint page_no = buf_block_get_page_no(block);
if (buf_LRU_free_block(&block->page, TRUE, FALSE)) {
//buf_pool_mutex_exit();
......@@ -2131,6 +2132,18 @@ buf_page_get_gen(
"innodb_change_buffering_debug evict %u %u\n",
(unsigned) space, (unsigned) offset);
return(NULL);
} else if (UNIV_UNLIKELY(buf_block_get_state(block)
!= BUF_BLOCK_FILE_PAGE
|| (buf_block_get_page_no(block) != page_no)
|| (buf_block_get_space(block) != space))) {
/* buf_LRU_free_block temporarily releases the
block mutex, and now block points to something
else. */
mutex_exit(block_mutex);
block = NULL;
goto loop2;
} else if (buf_flush_page_try(block)) {
fprintf(stderr,
"innodb_change_buffering_debug flush %u %u\n",
......@@ -4078,6 +4091,133 @@ buf_get_free_list_len(void)
return(len);
}
/*******************************************************************//**
Collect buffer pool stats information for a buffer pool. Also
record aggregated stats if there are more than one buffer pool
in the server */
UNIV_INTERN
void
buf_stats_get_pool_info(
/*====================*/
buf_pool_info_t* pool_info) /*!< in/out: buffer pool info
to fill */
{
time_t current_time;
double time_elapsed;
buf_pool_mutex_enter();
pool_info->pool_size = buf_pool->curr_size;
pool_info->lru_len = UT_LIST_GET_LEN(buf_pool->LRU);
pool_info->old_lru_len = buf_pool->LRU_old_len;
pool_info->free_list_len = UT_LIST_GET_LEN(buf_pool->free);
pool_info->flush_list_len = UT_LIST_GET_LEN(buf_pool->flush_list);
pool_info->n_pend_unzip = UT_LIST_GET_LEN(buf_pool->unzip_LRU);
pool_info->n_pend_reads = buf_pool->n_pend_reads;
pool_info->n_pending_flush_lru =
(buf_pool->n_flush[BUF_FLUSH_LRU]
+ buf_pool->init_flush[BUF_FLUSH_LRU]);
pool_info->n_pending_flush_list =
(buf_pool->n_flush[BUF_FLUSH_LIST]
+ buf_pool->init_flush[BUF_FLUSH_LIST]);
pool_info->n_pending_flush_single_page =
(buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]
+ buf_pool->init_flush[BUF_FLUSH_SINGLE_PAGE]);
current_time = time(NULL);
time_elapsed = 0.001 + difftime(current_time,
buf_pool->last_printout_time);
pool_info->n_pages_made_young = buf_pool->stat.n_pages_made_young;
pool_info->n_pages_not_made_young =
buf_pool->stat.n_pages_not_made_young;
pool_info->n_pages_read = buf_pool->stat.n_pages_read;
pool_info->n_pages_created = buf_pool->stat.n_pages_created;
pool_info->n_pages_written = buf_pool->stat.n_pages_written;
pool_info->n_page_gets = buf_pool->stat.n_page_gets;
pool_info->n_ra_pages_read_rnd = buf_pool->stat.n_ra_pages_read_rnd;
pool_info->n_ra_pages_read = buf_pool->stat.n_ra_pages_read;
pool_info->n_ra_pages_evicted = buf_pool->stat.n_ra_pages_evicted;
pool_info->page_made_young_rate =
(buf_pool->stat.n_pages_made_young
- buf_pool->old_stat.n_pages_made_young) / time_elapsed;
pool_info->page_not_made_young_rate =
(buf_pool->stat.n_pages_not_made_young
- buf_pool->old_stat.n_pages_not_made_young) / time_elapsed;
pool_info->pages_read_rate =
(buf_pool->stat.n_pages_read
- buf_pool->old_stat.n_pages_read) / time_elapsed;
pool_info->pages_created_rate =
(buf_pool->stat.n_pages_created
- buf_pool->old_stat.n_pages_created) / time_elapsed;
pool_info->pages_written_rate =
(buf_pool->stat.n_pages_written
- buf_pool->old_stat.n_pages_written) / time_elapsed;
pool_info->n_page_get_delta = buf_pool->stat.n_page_gets
- buf_pool->old_stat.n_page_gets;
if (pool_info->n_page_get_delta) {
pool_info->page_read_delta = buf_pool->stat.n_pages_read
- buf_pool->old_stat.n_pages_read;
pool_info->young_making_delta =
buf_pool->stat.n_pages_made_young
- buf_pool->old_stat.n_pages_made_young;
pool_info->not_young_making_delta =
buf_pool->stat.n_pages_not_made_young
- buf_pool->old_stat.n_pages_not_made_young;
}
pool_info->pages_readahead_rnd_rate =
(buf_pool->stat.n_ra_pages_read_rnd
- buf_pool->old_stat.n_ra_pages_read_rnd) / time_elapsed;
pool_info->pages_readahead_rate =
(buf_pool->stat.n_ra_pages_read
- buf_pool->old_stat.n_ra_pages_read) / time_elapsed;
pool_info->pages_evicted_rate =
(buf_pool->stat.n_ra_pages_evicted
- buf_pool->old_stat.n_ra_pages_evicted) / time_elapsed;
pool_info->unzip_lru_len = UT_LIST_GET_LEN(buf_pool->unzip_LRU);
pool_info->io_sum = buf_LRU_stat_sum.io;
pool_info->io_cur = buf_LRU_stat_cur.io;
pool_info->unzip_sum = buf_LRU_stat_sum.unzip;
pool_info->unzip_cur = buf_LRU_stat_cur.unzip;
buf_refresh_io_stats();
buf_pool_mutex_exit();
}
#else /* !UNIV_HOTBACKUP */
/********************************************************************//**
Inits a page to the buffer buf_pool, for use in ibbackup --restore. */
......@@ -4108,3 +4248,5 @@ buf_page_init_for_backup_restore(
}
}
#endif /* !UNIV_HOTBACKUP */
......@@ -48,6 +48,7 @@ Created 11/5/1995 Heikki Tuuri
#include "page0zip.h"
#include "log0recv.h"
#include "srv0srv.h"
#include "srv0start.h"
/** The number of blocks from the LRU_old pointer onward, including
the block pointed to, must be buf_LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV
......@@ -1428,13 +1429,12 @@ buf_LRU_make_block_old(
Try to free a block. If bpage is a descriptor of a compressed-only
page, the descriptor object will be freed as well.
NOTE: If this function returns TRUE, it will temporarily
release buf_pool_mutex. Furthermore, the page frame will no longer be
accessible via bpage.
NOTE: This will temporarily release buf_pool_mutex. Furthermore, the
page frame will no longer be accessible via bpage.
The caller must hold buf_pool_mutex and buf_page_get_mutex(bpage) and
release these two mutexes after the call. No other
buf_page_get_mutex() may be held when calling this function.
The caller must hold buf_page_get_mutex(bpage) and release this mutex
after the call. No other buf_page_get_mutex() may be held when
calling this function.
@return TRUE if freed, FALSE otherwise. */
UNIV_INTERN
ibool
......@@ -2098,6 +2098,12 @@ buf_LRU_stat_update(void)
/********************************************************************//**
Dump the LRU page list to the specific file. */
#define LRU_DUMP_FILE "ib_lru_dump"
#define LRU_DUMP_TEMP_FILE "ib_lru_dump.tmp"
#define LRU_OS_FILE_WRITE() \
os_file_write(LRU_DUMP_FILE, dump_file, buffer, \
(buffers << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL, \
(buffers >> (32 - UNIV_PAGE_SIZE_SHIFT)), \
UNIV_PAGE_SIZE)
UNIV_INTERN
ibool
......@@ -2109,17 +2115,19 @@ buf_LRU_file_dump(void)
byte* buffer_base = NULL;
byte* buffer = NULL;
buf_page_t* bpage;
buf_page_t* first_bpage;
ulint buffers;
ulint offset;
ibool ret = FALSE;
ulint pages_written;
ulint i;
ulint total_pages;
for (i = 0; i < srv_n_data_files; i++) {
if (strstr(srv_data_file_names[i], LRU_DUMP_FILE) != NULL) {
fprintf(stderr,
" InnoDB: The name '%s' seems to be used for"
" innodb_data_file_path. Dumping LRU list is not"
" done for safeness.\n", LRU_DUMP_FILE);
" innodb_data_file_path. Dumping LRU list is"
" not done for safeness.\n", LRU_DUMP_FILE);
goto end;
}
}
......@@ -2132,7 +2140,7 @@ buf_LRU_file_dump(void)
goto end;
}
dump_file = os_file_create(LRU_DUMP_FILE, OS_FILE_OVERWRITE,
dump_file = os_file_create(LRU_DUMP_TEMP_FILE, OS_FILE_OVERWRITE,
OS_FILE_NORMAL, OS_DATA_FILE, &success);
if (!success) {
os_file_get_last_error(TRUE);
......@@ -2142,12 +2150,21 @@ buf_LRU_file_dump(void)
}
mutex_enter(&LRU_list_mutex);
bpage = UT_LIST_GET_LAST(buf_pool->LRU);
bpage = first_bpage = UT_LIST_GET_FIRST(buf_pool->LRU);
total_pages = UT_LIST_GET_LEN(buf_pool->LRU);
buffers = offset = 0;
while (bpage != NULL) {
if (offset == 0) {
memset(buffer, 0, UNIV_PAGE_SIZE);
buffers = offset = pages_written = 0;
while (bpage != NULL && (pages_written++ < total_pages)) {
buf_page_t* next_bpage = UT_LIST_GET_NEXT(LRU, bpage);
if (next_bpage == first_bpage) {
mutex_exit(&LRU_list_mutex);
success = FALSE;
fprintf(stderr,
"InnoDB: detected cycle in LRU, skipping "
"dump\n");
goto end;
}
mach_write_to_4(buffer + offset * 4, bpage->space);
......@@ -2156,50 +2173,79 @@ buf_LRU_file_dump(void)
offset++;
if (offset == UNIV_PAGE_SIZE/4) {
success = os_file_write(LRU_DUMP_FILE, dump_file, buffer,
(buffers << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL,
(buffers >> (32 - UNIV_PAGE_SIZE_SHIFT)),
UNIV_PAGE_SIZE);
mutex_t *next_block_mutex = NULL;
if (srv_shutdown_state != SRV_SHUTDOWN_NONE) {
mutex_exit(&LRU_list_mutex);
success = FALSE;
fprintf(stderr,
" InnoDB: stopped dumping lru pages"
" because of server shutdown.\n");
goto end;
}
/* while writing file, release buffer pool mutex but
keep the next page fixed so we don't worry about
our list iterator becoming invalid */
if (next_bpage) {
next_block_mutex = buf_page_get_mutex(
next_bpage);
mutex_enter(next_block_mutex);
next_bpage->buf_fix_count++;
mutex_exit(next_block_mutex);
}
mutex_exit(&LRU_list_mutex);
success = LRU_OS_FILE_WRITE();
/* grab this again here so that next_bpage
can't be purged when we drop the fix_count */
mutex_enter(&LRU_list_mutex);
if (next_bpage) {
mutex_enter(next_block_mutex);
next_bpage->buf_fix_count--;
mutex_exit(next_block_mutex);
}
if (!success) {
mutex_exit(&LRU_list_mutex);
fprintf(stderr,
" InnoDB: cannot write page %lu of %s\n",
" InnoDB: cannot write page"
" %lu of %s\n",
buffers, LRU_DUMP_FILE);
goto end;
}
buffers++;
offset = 0;
bpage = next_bpage;
} else {
bpage = UT_LIST_GET_NEXT(LRU, bpage);
}
bpage = UT_LIST_GET_PREV(LRU, bpage);
}
} /* while(bpage ...) */
mutex_exit(&LRU_list_mutex);
if (offset == 0) {
memset(buffer, 0, UNIV_PAGE_SIZE);
}
mach_write_to_4(buffer + offset * 4, 0xFFFFFFFFUL);
offset++;
mach_write_to_4(buffer + offset * 4, 0xFFFFFFFFUL);
offset++;
success = os_file_write(LRU_DUMP_FILE, dump_file, buffer,
(buffers << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL,
(buffers >> (32 - UNIV_PAGE_SIZE_SHIFT)),
UNIV_PAGE_SIZE);
if (!success) {
goto end;
}
ret = TRUE;
success = LRU_OS_FILE_WRITE();
end:
if (dump_file != (os_file_t) -1)
if (dump_file != (os_file_t) -1) {
if (success) {
success = os_file_flush(dump_file, TRUE);
}
os_file_close(dump_file);
}
if (success) {
success = os_file_rename(LRU_DUMP_TEMP_FILE,
LRU_DUMP_FILE);
}
if (buffer_base)
ut_free(buffer_base);
return(ret);
return(success);
}
typedef struct {
......@@ -2241,6 +2287,7 @@ buf_LRU_file_restore(void)
dump_record_t* records = NULL;
ulint size;
ulint size_high;
ulint recsize = sizeof(dump_record_t);
ulint length;
dump_file = os_file_create_simple_no_error_handling(
......@@ -2248,7 +2295,15 @@ buf_LRU_file_restore(void)
if (!success || !os_file_get_size(dump_file, &size, &size_high)) {
os_file_get_last_error(TRUE);
fprintf(stderr,
" InnoDB: cannot open %s\n", LRU_DUMP_FILE);
" InnoDB: cannot open %s,"
" buffer pool preload not done\n",
LRU_DUMP_FILE);
goto end;
}
if (size == 0 || size_high > 0 || size % recsize) {
fprintf(stderr, " InnoDB: broken LRU dump file,"
" buffer pool preload not done\n");
goto end;
}
......@@ -2332,6 +2387,14 @@ buf_LRU_file_restore(void)
if (offset % 16 == 15) {
os_aio_simulated_wake_handler_threads();
buf_flush_free_margin(FALSE);
/* skip loading of the rest of the file if we are
terminating anyway*/
if (srv_shutdown_state != SRV_SHUTDOWN_NONE) {
fprintf(stderr,
" InnoDB: stopped loading LRU pages"
" because of server shutdown.\n");
break;
}
}
zip_size = fil_space_get_zip_size(space_id);
......
......@@ -236,6 +236,166 @@ dict_hdr_create(
return(TRUE);
}
/*****************************************************************//**
Verifies the SYS_STATS table by scanning its clustered index. This
function may only be called at InnoDB startup time.
@return TRUE if SYS_STATS was verified successfully */
UNIV_INTERN
ibool
dict_verify_xtradb_sys_stats(void)
/*==============================*/
{
dict_index_t* sys_stats_index;
ulint saved_srv_pass_corrupt_table = srv_pass_corrupt_table;
ibool result;
sys_stats_index = dict_table_get_first_index(dict_sys->sys_stats);
/* Since this may be called only during server startup, avoid hitting
various asserts by using XtraDB pass_corrupt_table option. */
srv_pass_corrupt_table = 1;
result = btr_validate_index(sys_stats_index, NULL);
srv_pass_corrupt_table = saved_srv_pass_corrupt_table;
return result;
}
/*****************************************************************//**
Creates the B-tree for the SYS_STATS clustered index, adds the XtraDB
mark and the id of the index to the dictionary header page. Rewrites
both passed args. */
static
void
dict_create_xtradb_sys_stats(
/*=========================*/
dict_hdr_t** dict_hdr, /*!< in/out: dictionary header */
mtr_t* mtr) /*!< in/out: mtr */
{
ulint root_page_no;
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_STATS_ID,
dict_ind_redundant, mtr);
if (root_page_no == FIL_NULL) {
fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
srv_use_sys_stats_table = FALSE;
} else {
mlog_write_ulint(*dict_hdr + DICT_HDR_STATS, root_page_no,
MLOG_4BYTES, mtr);
mlog_write_dulint(*dict_hdr + DICT_HDR_XTRADB_MARK,
DICT_HDR_XTRADB_FLAG, mtr);
}
mtr_commit(mtr);
/* restart mtr */
mtr_start(mtr);
*dict_hdr = dict_hdr_get(mtr);
}
/*****************************************************************//**
Create the table and index structure of SYS_STATS for the dictionary
cache and add it there. If called for the first time, also support
wrong root page id injection for testing purposes. */
static
void
dict_add_to_cache_xtradb_sys_stats(
/*===============================*/
ibool first_time __attribute__((unused)),
/*!< in: first invocation flag. If
TRUE, optionally inject wrong root page
id */
mem_heap_t* heap, /*!< in: memory heap for table/index
allocation */
dict_hdr_t* dict_hdr, /*!< in: dictionary header */
mtr_t* mtr) /*!< in: mtr */
{
dict_table_t* table;
dict_index_t* index;
ulint root_page_id;
ulint error;
table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 4, 0);
table->n_mysql_handles_opened = 1; /* for pin */
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "NON_NULL_VALS", DATA_BINARY, 0, 0);
/* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
#endif
#if DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2
#error "DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2"
#endif
table->id = DICT_STATS_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_stats = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 2);
dict_mem_index_add_field(index, "INDEX_ID", 0);
dict_mem_index_add_field(index, "KEY_COLS", 0);
index->id = DICT_STATS_ID;
root_page_id = mtr_read_ulint(dict_hdr + DICT_HDR_STATS, MLOG_4BYTES,
mtr);
#ifdef UNIV_DEBUG
if ((srv_sys_stats_root_page != 0) && first_time)
root_page_id = srv_sys_stats_root_page;
#endif
error = dict_index_add_to_cache(table, index, root_page_id, FALSE);
ut_a(error == DB_SUCCESS);
mem_heap_empty(heap);
}
/*****************************************************************//**
Discard the existing dictionary cache SYS_STATS information, create and
add it there anew. Does not touch the old SYS_STATS tablespace page
under the assumption that they are corrupted or overwritten for other
purposes. */
UNIV_INTERN
void
dict_recreate_xtradb_sys_stats(void)
/*================================*/
{
mtr_t mtr;
dict_hdr_t* dict_hdr;
dict_index_t* sys_stats_clust_idx;
mem_heap_t* heap;
heap = mem_heap_create(450);
mutex_enter(&(dict_sys->mutex));
sys_stats_clust_idx = dict_table_get_first_index(dict_sys->sys_stats);
dict_index_remove_from_cache(dict_sys->sys_stats, sys_stats_clust_idx);
dict_table_remove_from_cache(dict_sys->sys_stats);
dict_sys->sys_stats = NULL;
mtr_start(&mtr);
dict_hdr = dict_hdr_get(&mtr);
dict_create_xtradb_sys_stats(&dict_hdr, &mtr);
dict_add_to_cache_xtradb_sys_stats(FALSE, heap, dict_hdr, &mtr);
mem_heap_free(heap);
mtr_commit(&mtr);
mutex_exit(&(dict_sys->mutex));
}
/*****************************************************************//**
Initializes the data dictionary memory structures when the database is
started. This function is also called when the data dictionary is created. */
......@@ -251,39 +411,23 @@ dict_boot(void)
mtr_t mtr;
ulint error;
heap = mem_heap_create(450);
mtr_start(&mtr);
/* Create the hash tables etc. */
dict_init();
heap = mem_heap_create(450);
mutex_enter(&(dict_sys->mutex));
/* Get the dictionary header */
dict_hdr = dict_hdr_get(&mtr);
if (ut_dulint_cmp(mtr_read_dulint(dict_hdr + DICT_HDR_XTRADB_MARK, &mtr),
DICT_HDR_XTRADB_FLAG) != 0) {
if (ut_dulint_cmp(mtr_read_dulint(dict_hdr + DICT_HDR_XTRADB_MARK,
&mtr), DICT_HDR_XTRADB_FLAG) != 0) {
/* not extended yet by XtraDB, need to be extended */
ulint root_page_no;
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_STATS_ID,
dict_ind_redundant, &mtr);
if (root_page_no == FIL_NULL) {
fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
srv_use_sys_stats_table = FALSE;
} else {
mlog_write_ulint(dict_hdr + DICT_HDR_STATS, root_page_no,
MLOG_4BYTES, &mtr);
mlog_write_dulint(dict_hdr + DICT_HDR_XTRADB_MARK,
DICT_HDR_XTRADB_FLAG, &mtr);
}
mtr_commit(&mtr);
/* restart mtr */
mtr_start(&mtr);
dict_hdr = dict_hdr_get(&mtr);
dict_create_xtradb_sys_stats(&dict_hdr, &mtr);
}
/* Because we only write new row ids to disk-based data structure
......@@ -464,42 +608,7 @@ dict_boot(void)
FALSE);
ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 4, 0);
table->n_mysql_handles_opened = 1; /* for pin */
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "NON_NULL_VALS", DATA_BINARY, 0, 0);
/* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
#endif
#if DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2
#error "DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2"
#endif
table->id = DICT_STATS_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_stats = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 2);
dict_mem_index_add_field(index, "INDEX_ID", 0);
dict_mem_index_add_field(index, "KEY_COLS", 0);
index->id = DICT_STATS_ID;
error = dict_index_add_to_cache(table, index,
mtr_read_ulint(dict_hdr
+ DICT_HDR_STATS,
MLOG_4BYTES, &mtr),
FALSE);
ut_a(error == DB_SUCCESS);
dict_add_to_cache_xtradb_sys_stats(TRUE, heap, dict_hdr, &mtr);
mem_heap_free(heap);
......
......@@ -4622,12 +4622,6 @@ dict_store_statistics(
}
btr_pcur_close(&pcur);
mtr_commit(&mtr);
if (rests) {
fprintf(stderr, "InnoDB: Warning: failed to store %lu stats entries"
" of %s/%s to SYS_STATS system table.\n",
rests, index->table_name, index->name);
}
}
/*===========================================*/
......@@ -5394,6 +5388,28 @@ dict_table_replace_index_in_foreign_list(
foreign->foreign_index = new_index;
}
}
for (foreign = UT_LIST_GET_FIRST(table->referenced_list);
foreign;
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
dict_index_t* new_index;
if (foreign->referenced_index == index) {
ut_ad(foreign->referenced_table == index->table);
new_index = dict_foreign_find_index(
foreign->referenced_table,
foreign->referenced_col_names,
foreign->n_fields, index,
/*check_charsets=*/TRUE, /*check_null=*/FALSE);
ut_ad(new_index || !trx->check_foreigns);
ut_ad(!new_index || new_index->table == index->table);
foreign->referenced_index = new_index;
}
}
}
/**********************************************************************//**
......
......@@ -165,7 +165,7 @@ dict_print(void)
monitor printout */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
mutex_enter(&(dict_sys->mutex));
......@@ -193,7 +193,7 @@ dict_print(void)
/* Restore the fatal semaphore wait timeout */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
return;
......
......@@ -1876,7 +1876,7 @@ fil_inc_pending_ops(
if (space == NULL) {
fprintf(stderr,
"InnoDB: Error: trying to do ibuf merge to a"
"InnoDB: Error: trying to do an operation on a"
" dropped tablespace %lu\n",
(ulong) id);
}
......@@ -3375,6 +3375,7 @@ fil_open_single_table_tablespace(
for (offset = 0; offset < free_limit_bytes;
offset += zip_size ? zip_size : UNIV_PAGE_SIZE) {
ibool page_is_corrupt;
ibool is_descr_page = FALSE;
success = os_file_read(file, page,
(ulint)(offset & 0xFFFFFFFFUL),
......@@ -3413,6 +3414,7 @@ fil_open_single_table_tablespace(
/* store as descr page */
memcpy(descr_page, page, (zip_size ? zip_size : UNIV_PAGE_SIZE));
is_descr_page = TRUE;
} else if (descr_is_corrupt) {
/* unknown state of the page */
......@@ -3489,7 +3491,8 @@ fil_open_single_table_tablespace(
}
}
if (fil_page_get_type(page) == FIL_PAGE_INDEX) {
if (fil_page_get_type(page) ==
FIL_PAGE_INDEX && !is_descr_page) {
dulint tmp = mach_read_from_8(page + (PAGE_HEADER + PAGE_INDEX_ID));
for (i = 0; i < n_index; i++) {
......
......@@ -195,6 +195,9 @@ static my_bool innobase_rollback_on_timeout = FALSE;
static my_bool innobase_create_status_file = FALSE;
static my_bool innobase_stats_on_metadata = TRUE;
static my_bool innobase_use_sys_stats_table = FALSE;
#ifdef UNIV_DEBUG
static ulong innobase_sys_stats_root_page = 0;
#endif
static my_bool innobase_buffer_pool_shm_checksum = TRUE;
static uint innobase_buffer_pool_shm_key = 0;
......@@ -939,11 +942,23 @@ convert_error_code_to_mysql(
case DB_TABLE_NOT_FOUND:
return(HA_ERR_NO_SUCH_TABLE);
case DB_TOO_BIG_RECORD:
my_error(ER_TOO_BIG_ROWSIZE, MYF(0),
page_get_free_space_of_empty(flags
& DICT_TF_COMPACT) / 2);
case DB_TOO_BIG_RECORD: {
/* If prefix is true then a 768-byte prefix is stored
locally for BLOB fields. Refer to dict_table_get_format() */
bool prefix = ((flags & DICT_TF_FORMAT_MASK)
>> DICT_TF_FORMAT_SHIFT) < UNIV_FORMAT_B;
my_printf_error(ER_TOO_BIG_ROWSIZE,
"Row size too large (> %lu). Changing some columns "
"to TEXT or BLOB %smay help. In current row "
"format, BLOB prefix of %d bytes is stored inline.",
MYF(0),
page_get_free_space_of_empty(flags &
DICT_TF_COMPACT) / 2,
prefix ? "or using ROW_FORMAT=DYNAMIC "
"or ROW_FORMAT=COMPRESSED ": "",
prefix ? DICT_MAX_INDEX_COL_LEN : 0);
return(HA_ERR_TO_BIG_ROW);
}
case DB_NO_SAVEPOINT:
return(HA_ERR_NO_SAVEPOINT);
......@@ -2369,6 +2384,10 @@ innobase_init(
srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table;
#ifdef UNIV_DEBUG
srv_sys_stats_root_page = innobase_sys_stats_root_page;
#endif
/* -------------- Log files ---------------------------*/
/* The default dir for log files is the datadir of MySQL */
......@@ -4267,6 +4286,27 @@ ha_innobase::open(
DBUG_RETURN(0);
}
UNIV_INTERN
handler*
ha_innobase::clone(
/*===============*/
const char* name, /*!< in: table name */
MEM_ROOT* mem_root) /*!< in: memory context */
{
ha_innobase* new_handler;
DBUG_ENTER("ha_innobase::clone");
new_handler = static_cast<ha_innobase*>(handler::clone(name,
mem_root));
if (new_handler) {
new_handler->prebuilt->select_lock_type
= prebuilt->select_lock_type;
}
DBUG_RETURN(new_handler);
}
UNIV_INTERN
uint
ha_innobase::max_supported_key_part_length() const
......@@ -8684,7 +8724,7 @@ ha_innobase::check(
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
for (index = dict_table_get_first_index(prebuilt->table);
......@@ -8780,7 +8820,7 @@ ha_innobase::check(
/* Restore the fatal lock wait timeout after CHECK TABLE. */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
prebuilt->trx->op_info = "";
......@@ -11751,6 +11791,13 @@ static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table,
"So you should use ANALYZE TABLE command intentionally.",
NULL, NULL, FALSE);
#ifdef UNIV_DEBUG
static MYSQL_SYSVAR_ULONG(persistent_stats_root_page,
innobase_sys_stats_root_page, PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Override the SYS_STATS root page id, 0 = no override (for testing only)",
NULL, NULL, 0, 0, ULONG_MAX, 0);
#endif
static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
PLUGIN_VAR_OPCMDARG,
"Enable InnoDB adaptive hash index (enabled by default). "
......@@ -11934,6 +11981,18 @@ static MYSQL_SYSVAR_ENUM(stats_method, srv_innodb_stats_method,
"NULLS_UNEQUAL and NULLS_IGNORED",
NULL, NULL, SRV_STATS_NULLS_EQUAL, &innodb_stats_method_typelib);
static MYSQL_SYSVAR_BOOL(track_changed_pages, srv_track_changed_pages,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
"Track the redo log for changed pages and output a changed page bitmap",
NULL, NULL, FALSE);
static MYSQL_SYSVAR_ULONGLONG(changed_pages_limit, srv_changed_pages_limit,
PLUGIN_VAR_RQCMDARG,
"The maximum number of rows for "
"INFORMATION_SCHEMA.INNODB_CHANGED_PAGES table, "
"0 - unlimited",
NULL, NULL, 1000000, 0, ~0ULL, 0);
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
static MYSQL_SYSVAR_UINT(change_buffering_debug, ibuf_debug,
PLUGIN_VAR_RQCMDARG,
......@@ -12070,7 +12129,7 @@ static MYSQL_SYSVAR_UINT(auto_lru_dump, srv_auto_lru_dump,
NULL, NULL, 0, 0, UINT_MAX32, 0);
static MYSQL_SYSVAR_BOOL(blocking_lru_restore, innobase_blocking_lru_restore,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
"Block XtraDB startup process until buffer pool is full restored from a "
"dump file (if present). Disabled by default.",
NULL, NULL, FALSE);
......@@ -12149,6 +12208,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(stats_auto_update),
MYSQL_SYSVAR(stats_update_need_lock),
MYSQL_SYSVAR(use_sys_stats_table),
#ifdef UNIV_DEBUG
MYSQL_SYSVAR(persistent_stats_root_page),
#endif
MYSQL_SYSVAR(stats_sample_pages),
MYSQL_SYSVAR(adaptive_hash_index),
MYSQL_SYSVAR(stats_method),
......@@ -12180,6 +12242,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(dict_size_limit),
MYSQL_SYSVAR(use_sys_malloc),
MYSQL_SYSVAR(change_buffering),
MYSQL_SYSVAR(track_changed_pages),
MYSQL_SYSVAR(changed_pages_limit),
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
MYSQL_SYSVAR(change_buffering_debug),
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
......@@ -12230,7 +12294,10 @@ i_s_innodb_admin_command,
i_s_innodb_sys_tables,
i_s_innodb_sys_indexes,
i_s_innodb_sys_stats,
i_s_innodb_patches
i_s_innodb_changed_pages,
i_s_innodb_buffer_page,
i_s_innodb_buffer_page_lru,
i_s_innodb_buffer_stats
mysql_declare_plugin_end;
/** @brief Initialize the default value of innodb_commit_concurrency.
......
......@@ -133,6 +133,7 @@ class ha_innobase: public handler
const key_map* keys_to_use_for_scanning();
int open(const char *name, int mode, uint test_if_locked);
handler* clone(const char *name, MEM_ROOT *mem_root);
int close(void);
double scan_time();
double read_time(uint index, uint ranges, ha_rows rows);
......
......@@ -668,6 +668,10 @@ ha_innobase::add_index(
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
if (innodb_table->tablespace_discarded) {
DBUG_RETURN(-1);
}
/* Check that index keys are sensible */
error = innobase_check_index_keys(key_info, num_of_keys, innodb_table);
......@@ -823,6 +827,8 @@ ha_innobase::add_index(
innodb_table, indexed_table,
index, num_of_idx, table);
DBUG_EXECUTE_IF("crash_innodb_add_index_after", DBUG_SUICIDE(););
error_handling:
/* After an error, remove all those index definitions from the
dictionary which were defined. */
......
This diff is collapsed.
......@@ -36,7 +36,6 @@ extern struct st_mysql_plugin i_s_innodb_cmp;
extern struct st_mysql_plugin i_s_innodb_cmp_reset;
extern struct st_mysql_plugin i_s_innodb_cmpmem;
extern struct st_mysql_plugin i_s_innodb_cmpmem_reset;
extern struct st_mysql_plugin i_s_innodb_patches;
extern struct st_mysql_plugin i_s_innodb_rseg;
extern struct st_mysql_plugin i_s_innodb_table_stats;
extern struct st_mysql_plugin i_s_innodb_index_stats;
......@@ -44,5 +43,9 @@ extern struct st_mysql_plugin i_s_innodb_admin_command;
extern struct st_mysql_plugin i_s_innodb_sys_tables;
extern struct st_mysql_plugin i_s_innodb_sys_indexes;
extern struct st_mysql_plugin i_s_innodb_sys_stats;
extern struct st_mysql_plugin i_s_innodb_changed_pages;
extern struct st_mysql_plugin i_s_innodb_buffer_page;
extern struct st_mysql_plugin i_s_innodb_buffer_page_lru;
extern struct st_mysql_plugin i_s_innodb_buffer_stats;
#endif /* i_s_h */
/* Copyright (C) 2002-2006 MySQL AB
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; version 2 of the License.
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, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#ifdef USE_PRAGMA_INTERFACE
#pragma interface /* gcc class implementation */
#endif
struct innodb_enhancement {
const char *file;
const char *name;
const char *comment;
const char *link;
}innodb_enhancements[] = {
{"xtradb_show_enhancements","I_S.XTRADB_ENHANCEMENTS","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_show_status","Improvements to SHOW INNODB STATUS","Memory information and lock info fixes","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_io","Improvements to InnoDB IO","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_opt_lru_count","Fix of buffer_pool mutex","Decreases contention on buffer_pool mutex on LRU operations","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_buffer_pool_pages","Information of buffer pool content","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_expand_undo_slots","expandable maximum number of undo slots","from 1024 (default) to about 4000","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_extra_rseg","allow to create extra rollback segments","When create new db, the new parameter allows to create more rollback segments","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_overwrite_relay_log_info","overwrite relay-log.info when slave recovery","Building as plugin, it is not used.","http://www.percona.com/docs/wiki/percona-xtradb:innodb_overwrite_relay_log_info"},
{"innodb_thread_concurrency_timer_based","use InnoDB timer based concurrency throttling (backport from MySQL 5.4.0)","",""},
{"innodb_expand_import","convert .ibd file automatically when import tablespace","the files are generated by xtrabackup export mode.","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_dict_size_limit","Limit dictionary cache size","Variable innodb_dict_size_limit in bytes","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_split_buf_pool_mutex","More fix of buffer_pool mutex","Spliting buf_pool_mutex and optimizing based on innodb_opt_lru_count","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_stats","Additional features about InnoDB statistics/optimizer","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_recovery_patches","Bugfixes and adjustments about recovery process","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_purge_thread","Enable to use purge devoted thread","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_admin_command_base","XtraDB specific command interface through i_s","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_show_lock_name","Show mutex/lock name instead of crated file/line","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_extend_slow","Extended statistics in slow.log","It is InnoDB-part only. It needs to patch also to mysqld.","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_lru_dump_restore","Dump and restore command for content of buffer pool","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_separate_doublewrite","Add option 'innodb_doublewrite_file' to separate doublewrite dedicated tablespace","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_pass_corrupt_table","Treat tables as corrupt instead of crash, when meet corrupt blocks","","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_fast_checksum","Using the checksum on 32bit-unit calculation","incompatible for unpatched ver.","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_files_extend","allow >4GB transaction log files, and can vary universal page size of datafiles","incompatible for unpatched ver.","http://www.percona.com/docs/wiki/percona-xtradb"},
{"innodb_sys_tables_sys_indexes","Expose InnoDB SYS_TABLES and SYS_INDEXES schema tables","","http://www.percona.com/docs/wiki/percona-xtradb"},
{NULL, NULL, NULL, NULL}
};
......@@ -2759,11 +2759,19 @@ ibuf_insert_low(
root = ibuf_tree_root_get(&mtr);
err = btr_cur_pessimistic_insert(BTR_NO_LOCKING_FLAG
| BTR_NO_UNDO_LOG_FLAG,
cursor,
ibuf_entry, &ins_rec,
&dummy_big_rec, 0, thr, &mtr);
err = btr_cur_optimistic_insert(
BTR_NO_LOCKING_FLAG | BTR_NO_UNDO_LOG_FLAG,
cursor, ibuf_entry, &ins_rec,
&dummy_big_rec, 0, thr, &mtr);
if (err == DB_FAIL) {
err = btr_cur_pessimistic_insert(
BTR_NO_LOCKING_FLAG
| BTR_NO_UNDO_LOG_FLAG,
cursor, ibuf_entry, &ins_rec,
&dummy_big_rec, 0, thr, &mtr);
}
if (err == DB_SUCCESS) {
/* Update the page max trx id field */
page_update_max_trx_id(btr_cur_get_block(cursor), NULL,
......
......@@ -103,6 +103,81 @@ enum buf_page_state {
before putting to the free list */
};
/** This structure defines information we will fetch from each buffer pool. It
will be used to print table IO stats */
struct buf_pool_info_struct{
/* General buffer pool info */
ulint pool_size; /*!< Buffer Pool size in pages */
ulint lru_len; /*!< Length of buf_pool->LRU */
ulint old_lru_len; /*!< buf_pool->LRU_old_len */
ulint free_list_len; /*!< Length of buf_pool->free list */
ulint flush_list_len; /*!< Length of buf_pool->flush_list */
ulint n_pend_unzip; /*!< buf_pool->n_pend_unzip, pages
pending decompress */
ulint n_pend_reads; /*!< buf_pool->n_pend_reads, pages
pending read */
ulint n_pending_flush_lru; /*!< Pages pending flush in LRU */
ulint n_pending_flush_single_page;/*!< Pages pending to be
flushed as part of single page
flushes issued by various user
threads */
ulint n_pending_flush_list; /*!< Pages pending flush in FLUSH
LIST */
ulint n_pages_made_young; /*!< number of pages made young */
ulint n_pages_not_made_young; /*!< number of pages not made young */
ulint n_pages_read; /*!< buf_pool->n_pages_read */
ulint n_pages_created; /*!< buf_pool->n_pages_created */
ulint n_pages_written; /*!< buf_pool->n_pages_written */
ulint n_page_gets; /*!< buf_pool->n_page_gets */
ulint n_ra_pages_read_rnd; /*!< buf_pool->n_ra_pages_read_rnd,
number of pages readahead */
ulint n_ra_pages_read; /*!< buf_pool->n_ra_pages_read, number
of pages readahead */
ulint n_ra_pages_evicted; /*!< buf_pool->n_ra_pages_evicted,
number of readahead pages evicted
without access */
ulint n_page_get_delta; /*!< num of buffer pool page gets since
last printout */
/* Buffer pool access stats */
double page_made_young_rate; /*!< page made young rate in pages
per second */
double page_not_made_young_rate;/*!< page not made young rate
in pages per second */
double pages_read_rate; /*!< num of pages read per second */
double pages_created_rate; /*!< num of pages create per second */
double pages_written_rate; /*!< num of pages written per second */
ulint page_read_delta; /*!< num of pages read since last
printout */
ulint young_making_delta; /*!< num of pages made young since
last printout */
ulint not_young_making_delta; /*!< num of pages not make young since
last printout */
/* Statistics about read ahead algorithm. */
double pages_readahead_rnd_rate;/*!< random readahead rate in pages per
second */
double pages_readahead_rate; /*!< readahead rate in pages per
second */
double pages_evicted_rate; /*!< rate of readahead page evicted
without access, in pages per second */
/* Stats about LRU eviction */
ulint unzip_lru_len; /*!< length of buf_pool->unzip_LRU
list */
/* Counters for LRU policy */
ulint io_sum; /*!< buf_LRU_stat_sum.io */
ulint io_cur; /*!< buf_LRU_stat_cur.io, num of IO
for current interval */
ulint unzip_sum; /*!< buf_LRU_stat_sum.unzip */
ulint unzip_cur; /*!< buf_LRU_stat_cur.unzip, num
pages decompressed in current
interval */
};
typedef struct buf_pool_info_struct buf_pool_info_t;
#ifndef UNIV_HOTBACKUP
/********************************************************************//**
Creates the buffer pool.
......@@ -623,6 +698,16 @@ void
buf_print_io(
/*=========*/
FILE* file); /*!< in: file where to print */
/*******************************************************************//**
Collect buffer pool stats information for a buffer pool. Also
record aggregated stats if there are more than one buffer pool
in the server */
UNIV_INTERN
void
buf_stats_get_pool_info(
/*====================*/
buf_pool_info_t* pool_info); /*!< in/out: buffer pool info
to fill */
/*********************************************************************//**
Returns the ratio in percents of modified pages in the buffer pool /
database pages in the buffer pool.
......@@ -1051,12 +1136,27 @@ UNIV_INTERN
ulint
buf_get_free_list_len(void);
/*=======================*/
/*********************************************************************//**
Get the nth chunk's buffer block in the specified buffer pool.
@return the nth chunk's buffer block. */
UNIV_INLINE
buf_block_t*
buf_get_nth_chunk_block(
/*====================*/
const buf_pool_t* buf_pool, /*!< in: buffer pool instance */
ulint n, /*!< in: nth chunk in the buffer pool */
ulint* chunk_size); /*!< in: chunk size */
#endif /* !UNIV_HOTBACKUP */
/** The common buffer control block structure
for compressed and uncompressed frames */
/** Number of bits used for buffer page states. */
#define BUF_PAGE_STATE_BITS 3
struct buf_page_struct{
/** @name General fields
None of these bit-fields must be modified without holding
......@@ -1071,7 +1171,8 @@ struct buf_page_struct{
unsigned offset:32; /*!< page number; also protected
by buf_pool_mutex. */
unsigned state:3; /*!< state of the control block; also
unsigned state:BUF_PAGE_STATE_BITS;
/*!< state of the control block; also
protected by buf_pool_mutex.
State transitions from
BUF_BLOCK_READY_FOR_USE to
......
......@@ -36,6 +36,7 @@ Created 11/5/1995 Heikki Tuuri
#include "buf0lru.h"
#include "buf0rea.h"
#include "srv0srv.h"
/********************************************************************//**
Reads the freed_page_clock of a buffer block.
@return freed_page_clock */
......@@ -1154,4 +1155,23 @@ 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.
@return the nth chunk's buffer block. */
UNIV_INLINE
buf_block_t*
buf_get_nth_chunk_block(
/*====================*/
const buf_pool_t* buf_pool, /*!< in: buffer pool instance */
ulint n, /*!< in: nth chunk in the buffer pool */
ulint* chunk_size) /*!< in: chunk size */
{
const buf_chunk_t* chunk;
chunk = buf_pool->chunks + n;
*chunk_size = chunk->size;
return(chunk->blocks);
}
#endif /* !UNIV_HOTBACKUP */
......@@ -93,13 +93,12 @@ buf_LRU_insert_zip_clean(
Try to free a block. If bpage is a descriptor of a compressed-only
page, the descriptor object will be freed as well.
NOTE: If this function returns TRUE, it will temporarily
release buf_pool_mutex. Furthermore, the page frame will no longer be
accessible via bpage.
NOTE: This will temporarily release buf_pool_mutex. Furthermore, the
page frame will no longer be accessible via bpage.
The caller must hold buf_pool_mutex and buf_page_get_mutex(bpage) and
release these two mutexes after the call. No other
buf_page_get_mutex() may be held when calling this function.
The caller must hold buf_page_get_mutex(bpage) and release this mutex
after the call. No other buf_page_get_mutex() may be held when
calling this function.
@return TRUE if freed, FALSE otherwise. */
UNIV_INTERN
ibool
......
......@@ -91,6 +91,26 @@ void
dict_create(void);
/*=============*/
/*****************************************************************//**
Verifies the SYS_STATS table by scanning its clustered index. This
function may only be called at InnoDB startup time.
@return TRUE if SYS_STATS was verified successfully */
UNIV_INTERN
ibool
dict_verify_xtradb_sys_stats(void);
/*==============================*/
/*****************************************************************//**
Discard the existing dictionary cache SYS_STATS information, create and
add it there anew. Does not touch the old SYS_STATS tablespace page
under the assumption that they are corrupted or overwritten for other
purposes. */
UNIV_INTERN
void
dict_recreate_xtradb_sys_stats(void);
/*================================*/
/* Space id and page no where the dictionary header resides */
#define DICT_HDR_SPACE 0 /* the SYSTEM tablespace */
......
......@@ -142,6 +142,8 @@ extern fil_addr_t fil_addr_null;
#define FIL_PAGE_TYPE_BLOB 10 /*!< Uncompressed BLOB page */
#define FIL_PAGE_TYPE_ZBLOB 11 /*!< First compressed BLOB page */
#define FIL_PAGE_TYPE_ZBLOB2 12 /*!< Subsequent compressed BLOB page */
#define FIL_PAGE_TYPE_LAST FIL_PAGE_TYPE_ZBLOB2
/*!< Last page type */
/* @} */
/** Space types @{ */
......
......@@ -41,6 +41,9 @@ Created 12/9/1995 Heikki Tuuri
#include "sync0rw.h"
#endif /* !UNIV_HOTBACKUP */
/* Type used for all log sequence number storage and arithmetics */
typedef ib_uint64_t lsn_t;
/** Redo log buffer */
typedef struct log_struct log_t;
/** Redo log group */
......@@ -953,6 +956,11 @@ struct log_struct{
become signaled */
/* @} */
#endif /* UNIV_LOG_ARCHIVE */
ib_uint64_t tracked_lsn; /*!< log tracking has advanced to this
lsn. Field accessed atomically where
64-bit atomic ops are supported,
protected by the log sys mutex
otherwise. */
};
#ifdef UNIV_LOG_ARCHIVE
......
/*****************************************************************************
Copyright (c) 2011-2012, Percona Inc. 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
Foundation; version 2 of the License.
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, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
*****************************************************************************/
/**************************************************//**
@file include/log0online.h
Online database log parsing for changed page tracking
*******************************************************/
#ifndef log0online_h
#define log0online_h
#include "univ.i"
#include "os0file.h"
/*********************************************************************//**
Initializes the online log following subsytem. */
UNIV_INTERN
void
log_online_read_init();
/*===================*/
/*********************************************************************//**
Shuts down the online log following subsystem. */
UNIV_INTERN
void
log_online_read_shutdown();
/*=======================*/
/*********************************************************************//**
Reads and parses the redo log up to last checkpoint LSN to build the changed
page bitmap which is then written to disk. */
UNIV_INTERN
void
log_online_follow_redo_log();
/*=========================*/
/** The iterator through all bits of changed pages bitmap blocks */
struct log_bitmap_iterator_struct
{
char in_name[FN_REFLEN]; /*!< the file name for bitmap
input */
os_file_t in; /*!< the bitmap input file */
ib_uint64_t in_offset; /*!< the next write position in the
bitmap output file */
ib_uint32_t bit_offset; /*!< bit offset inside of bitmap
block*/
ib_uint64_t start_lsn; /*!< Start lsn of the block */
ib_uint64_t end_lsn; /*!< End lsn of the block */
ib_uint32_t space_id; /*!< Block space id */
ib_uint32_t first_page_id; /*!< First block page id */
ibool changed; /*!< true if current page was changed */
byte* page; /*!< Bitmap block */
};
typedef struct log_bitmap_iterator_struct log_bitmap_iterator_t;
#define LOG_BITMAP_ITERATOR_START_LSN(i) \
((i).start_lsn)
#define LOG_BITMAP_ITERATOR_END_LSN(i) \
((i).end_lsn)
#define LOG_BITMAP_ITERATOR_SPACE_ID(i) \
((i).space_id)
#define LOG_BITMAP_ITERATOR_PAGE_NUM(i) \
((i).first_page_id + (i).bit_offset)
#define LOG_BITMAP_ITERATOR_PAGE_CHANGED(i) \
((i).changed)
/*********************************************************************//**
Initializes log bitmap iterator.
@return TRUE if the iterator is initialized OK, FALSE otherwise. */
UNIV_INTERN
ibool
log_online_bitmap_iterator_init(
/*============================*/
log_bitmap_iterator_t *i); /*!<in/out: iterator */
/*********************************************************************//**
Releases log bitmap iterator. */
UNIV_INTERN
void
log_online_bitmap_iterator_release(
/*===============================*/
log_bitmap_iterator_t *i); /*!<in/out: iterator */
/*********************************************************************//**
Iterates through bits of saved bitmap blocks.
Sequentially reads blocks from bitmap file(s) and interates through
their bits. Ignores blocks with wrong checksum.
@return TRUE if iteration is successful, FALSE if all bits are iterated. */
UNIV_INTERN
ibool
log_online_bitmap_iterator_next(
/*============================*/
log_bitmap_iterator_t *i); /*!<in/out: iterator */
#endif
......@@ -32,6 +32,28 @@ Created 9/20/1997 Heikki Tuuri
#include "hash0hash.h"
#include "log0log.h"
/******************************************************//**
Checks the 4-byte checksum to the trailer checksum field of a log
block. We also accept a log block in the old format before
InnoDB-3.23.52 where the checksum field contains the log block number.
@return TRUE if ok, or if the log block may be in the format of InnoDB
version predating 3.23.52 */
UNIV_INTERN
ibool
log_block_checksum_is_ok_or_old_format(
/*===================================*/
const byte* block); /*!< in: pointer to a log block */
/*******************************************************//**
Calculates the new value for lsn when more data is added to the log. */
UNIV_INTERN
ib_uint64_t
recv_calc_lsn_on_data_add(
/*======================*/
ib_uint64_t lsn, /*!< in: old lsn */
ib_uint64_t len); /*!< in: this many bytes of data is
added, log block headers not included */
#ifdef UNIV_HOTBACKUP
extern ibool recv_replay_file_ops;
......@@ -182,6 +204,21 @@ UNIV_INTERN
void
recv_recovery_rollback_active(void);
/*===============================*/
/*******************************************************************//**
Tries to parse a single log record and returns its length.
@return length of the record, or 0 if the record was not complete */
UNIV_INTERN
ulint
recv_parse_log_rec(
/*===============*/
byte* ptr, /*!< in: pointer to a buffer */
byte* end_ptr,/*!< in: pointer to the buffer end */
byte* type, /*!< out: type */
ulint* space, /*!< out: space id */
ulint* page_no,/*!< out: page number */
byte** body); /*!< out: log record body start */
/*******************************************************//**
Scans log from a buffer and stores new log data to the parsing buffer.
Parses and hashes the log records if new data found. Unless
......
......@@ -463,6 +463,14 @@ os_file_set_eof(
/*============*/
FILE* file); /*!< in: file to be truncated */
/***********************************************************************//**
Truncates a file at the specified position.
@return TRUE if success */
UNIV_INTERN
ibool
os_file_set_eof_at(
os_file_t file, /*!< in: handle to a file */
ib_uint64_t new_len);/*!< in: new file length */
/***********************************************************************//**
Flushes the write buffers of a given file to the disk.
@return TRUE if success */
UNIV_INTERN
......
......@@ -287,7 +287,11 @@ Atomic compare-and-swap and increment for InnoDB. */
#if defined(HAVE_IB_GCC_ATOMIC_BUILTINS)
#define HAVE_ATOMIC_BUILTINS
# define HAVE_ATOMIC_BUILTINS
# ifdef HAVE_IB_GCC_ATOMIC_BUILTINS_64
# define HAVE_ATOMIC_BUILTINS_64
# endif
/**********************************************************//**
Returns true if swapped, ptr is pointer to target, old_val is value to
......@@ -326,6 +330,9 @@ amount of increment. */
# define os_atomic_increment_ulint(ptr, amount) \
os_atomic_increment(ptr, amount)
# define os_atomic_increment_uint64(ptr, amount) \
os_atomic_increment(ptr, amount)
/**********************************************************//**
Returns the old value of *ptr, atomically sets *ptr to new_val */
......@@ -334,12 +341,13 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
#elif defined(HAVE_IB_SOLARIS_ATOMICS)
#define HAVE_ATOMIC_BUILTINS
# define HAVE_ATOMIC_BUILTINS
# define HAVE_ATOMIC_BUILTINS_64
/* If not compiling with GCC or GCC doesn't support the atomic
intrinsics and running on Solaris >= 10 use Solaris atomics */
#include <atomic.h>
# include <atomic.h>
/**********************************************************//**
Returns true if swapped, ptr is pointer to target, old_val is value to
......@@ -379,6 +387,9 @@ amount of increment. */
# define os_atomic_increment_ulint(ptr, amount) \
atomic_add_long_nv(ptr, amount)
# define os_atomic_increment_uint64(ptr, amount) \
atomic_add_64_nv(ptr, amount)
/**********************************************************//**
Returns the old value of *ptr, atomically sets *ptr to new_val */
......@@ -387,7 +398,11 @@ Returns the old value of *ptr, atomically sets *ptr to new_val */
#elif defined(HAVE_WINDOWS_ATOMICS)
#define HAVE_ATOMIC_BUILTINS
# define HAVE_ATOMIC_BUILTINS
# ifndef _WIN32
# define HAVE_ATOMIC_BUILTINS_64
# endif
/* On Windows, use Windows atomics / interlocked */
# ifdef _WIN64
......@@ -425,6 +440,11 @@ amount of increment. */
# define os_atomic_increment_ulint(ptr, amount) \
((ulint) (win_xchg_and_add(ptr, amount) + amount))
# define os_atomic_increment_uint64(ptr, amount) \
((ib_uint64_t) (InterlockedExchangeAdd64( \
(ib_int64_t*) ptr, \
(ib_int64_t) amount) + amount))
/**********************************************************//**
Returns the old value of *ptr, atomically sets *ptr to new_val.
InterlockedExchange() operates on LONG, and the LONG will be
......
......@@ -60,6 +60,14 @@ extern os_event_t srv_lock_timeout_thread_event;
/* This event is set at shutdown to wakeup threads from sleep */
extern os_event_t srv_shutdown_event;
/* This event is set on checkpoint completion to wake the redo log parser
thread */
extern os_event_t srv_checkpoint_completed_event;
/* This event is set on the online redo log following thread exit to signal
that the (slow) shutdown may proceed */
extern os_event_t srv_redo_log_thread_finished_event;
/* If the last data file is auto-extended, we add this many pages to it
at a time */
#define SRV_AUTO_EXTEND_INCREMENT \
......@@ -126,6 +134,11 @@ extern ibool srv_recovery_stats;
extern ulint srv_use_purge_thread;
extern my_bool srv_track_changed_pages;
extern
ulonglong srv_changed_pages_limit;
extern ibool srv_auto_extend_last_data_file;
extern ulint srv_last_file_size_max;
extern char** srv_log_group_home_dirs;
......@@ -213,6 +226,9 @@ extern unsigned long long srv_stats_sample_pages;
extern ulong srv_stats_auto_update;
extern ulint srv_stats_update_need_lock;
extern ibool srv_use_sys_stats_table;
#ifdef UNIV_DEBUG
extern ulong srv_sys_stats_root_page;
#endif
extern ibool srv_use_doublewrite_buf;
extern ibool srv_use_checksums;
......@@ -284,6 +300,7 @@ extern ibool srv_print_latch_waits;
extern ulint srv_activity_count;
extern ulint srv_fatal_semaphore_wait_threshold;
#define SRV_SEMAPHORE_WAIT_EXTENSION 7200
extern ulint srv_dml_needed_delay;
extern long long srv_kill_idle_transaction;
......@@ -644,6 +661,15 @@ srv_LRU_dump_restore_thread(
void* arg); /*!< in: a dummy parameter required by
os_thread_create */
/******************************************************************//**
A thread which follows the redo log and outputs the changed page bitmap.
@return a dummy value */
UNIV_INTERN
os_thread_ret_t
srv_redo_log_follow_thread(
/*=======================*/
void* arg); /*!< in: a dummy parameter required by
os_thread_create */
/******************************************************************//**
Outputs to a file the output of the InnoDB Monitor.
@return FALSE if not all information printed
due to failure to obtain necessary mutex */
......
......@@ -46,7 +46,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 1
#define INNODB_VERSION_MINOR 0
#define INNODB_VERSION_BUGFIX 17
#define PERCONA_INNODB_VERSION 13.0
#define PERCONA_INNODB_VERSION 14.1
/* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins;
......@@ -270,6 +270,24 @@ management to ensure correct alignment for doubles etc. */
========================
*/
/** There are currently two InnoDB file formats which are used to group
features with similar restrictions and dependencies. Using an enum allows
switch statements to give a compiler warning when a new one is introduced. */
enum innodb_file_formats_enum {
/** Antelope File Format: InnoDB/MySQL up to 5.1.
This format includes REDUNDANT and COMPACT row formats */
UNIV_FORMAT_A = 0,
/** Barracuda File Format: Introduced in InnoDB plugin for 5.1:
This format includes COMPRESSED and DYNAMIC row formats. It
includes the ability to create secondary indexes from data that
is not on the clustered index page and the ability to store more
data off the clustered index page. */
UNIV_FORMAT_B = 1
};
typedef enum innodb_file_formats_enum innodb_file_formats_t;
/* The 2-logarithm of UNIV_PAGE_SIZE: */
/* #define UNIV_PAGE_SIZE_SHIFT 14 */
#define UNIV_PAGE_SIZE_SHIFT_MAX 14
......
......@@ -110,6 +110,10 @@ struct ib_rbt_bound_struct {
/* Compare a key with the node value (t is tree, k is key, n is node)*/
#define rbt_compare(t, k, n) (t->compare(k, n->value))
/* Node size. FIXME: name might clash, but currently it does not, so for easier
maintenance do not rename it for now. */
#define SIZEOF_NODE(t) ((sizeof(ib_rbt_node_t) + t->sizeof_value) - 1)
/****************************************************************//**
Free an instance of a red black tree */
UNIV_INTERN
......@@ -181,6 +185,18 @@ rbt_add_node(
const void* value); /*!< in: this value is copied
to the node */
/****************************************************************//**
Add a new caller-provided node to tree at the specified position.
The node must have its key fields initialized correctly.
@return added node */
UNIV_INTERN
const ib_rbt_node_t*
rbt_add_preallocated_node(
/*======================*/
ib_rbt_t* tree, /*!< in: rb tree */
ib_rbt_bound_t* parent, /*!< in: parent */
ib_rbt_node_t* node); /*!< in: node */
/****************************************************************//**
Return the left most data node in the tree
@return left most node */
UNIV_INTERN
......@@ -267,6 +283,13 @@ rbt_clear(
/*======*/
ib_rbt_t* tree); /*!< in: rb tree */
/****************************************************************//**
Clear the tree without deleting and freeing its nodes. */
UNIV_INTERN
void
rbt_reset(
/*======*/
ib_rbt_t* tree); /*!< in: rb tree */
/****************************************************************//**
Merge the node from dst into src. Return the number of nodes merged.
@return no. of recs merged */
UNIV_INTERN
......
......@@ -201,6 +201,54 @@ log_buf_pool_get_oldest_modification(void)
return(lsn);
}
/****************************************************************//**
Safely reads the log_sys->tracked_lsn value. Uses atomic operations
if available, otherwise this field is protected with the log system
mutex. The writer counterpart function is log_set_tracked_lsn() in
log0online.c.
@return log_sys->tracked_lsn value. */
UNIV_INLINE
ib_uint64_t
log_get_tracked_lsn()
{
#ifdef HAVE_ATOMIC_BUILTINS_64
return os_atomic_increment_uint64(&log_sys->tracked_lsn, 0);
#else
ut_ad(mutex_own(&(log_sys->mutex)));
return log_sys->tracked_lsn;
#endif
}
/****************************************************************//**
Checks if the log groups have a big enough margin of free space in
so that a new log entry can be written without overwriting log data
that is not read by the changed page bitmap thread.
@return TRUE if there is not enough free space. */
static
ibool
log_check_tracking_margin(
ulint lsn_advance) /*!< in: an upper limit on how much log data we
plan to write. If zero, the margin will be
checked for the already-written log. */
{
ib_uint64_t tracked_lsn;
ulint tracked_lsn_age;
if (!srv_track_changed_pages) {
return FALSE;
}
ut_ad(mutex_own(&(log_sys->mutex)));
tracked_lsn = log_get_tracked_lsn();
tracked_lsn_age = log_sys->lsn - tracked_lsn;
/* The overwrite would happen when log_sys->log_group_capacity is
exceeded, but we use max_checkpoint_age for an extra safety margin. */
return tracked_lsn_age + lsn_advance > log_sys->max_checkpoint_age;
}
/************************************************************//**
Opens the log for log_write_low. The log must be closed with log_close and
released with log_release.
......@@ -217,9 +265,7 @@ log_reserve_and_open(
ulint archived_lsn_age;
ulint dummy;
#endif /* UNIV_LOG_ARCHIVE */
#ifdef UNIV_DEBUG
ulint count = 0;
#endif /* UNIV_DEBUG */
ut_a(len < log->buf_size / 2);
loop:
......@@ -247,6 +293,19 @@ log_reserve_and_open(
goto loop;
}
if (log_check_tracking_margin(len_upper_limit) && (++count < 50)) {
/* This log write would violate the untracked LSN free space
margin. Limit this to 50 retries as there might be situations
where we have no choice but to proceed anyway, i.e. if the log
is about to be overflown, log tracking or not. */
mutex_exit(&(log->mutex));
os_thread_sleep(10000);
goto loop;
}
#ifdef UNIV_LOG_ARCHIVE
if (log->archiving_state != LOG_ARCH_OFF) {
......@@ -385,6 +444,8 @@ log_close(void)
ulint first_rec_group;
ib_uint64_t oldest_lsn;
ib_uint64_t lsn;
ib_uint64_t tracked_lsn;
ulint tracked_lsn_age;
log_t* log = log_sys;
ib_uint64_t checkpoint_age;
......@@ -411,6 +472,19 @@ log_close(void)
log->check_flush_or_checkpoint = TRUE;
}
if (srv_track_changed_pages) {
tracked_lsn = log_get_tracked_lsn();
tracked_lsn_age = lsn - tracked_lsn;
if (tracked_lsn_age >= log->log_group_capacity) {
fprintf(stderr, " InnoDB: Error: the age of the "
"oldest untracked record exceeds the log "
"group capacity!\n");
}
}
checkpoint_age = lsn - log->last_checkpoint_lsn;
if (checkpoint_age >= log->log_group_capacity) {
......@@ -872,6 +946,8 @@ log_init(void)
log_sys->archiving_on = os_event_create(NULL);
#endif /* UNIV_LOG_ARCHIVE */
log_sys->tracked_lsn = 0;
/*----------------------------*/
log_block_init(log_sys->buf, log_sys->lsn);
......@@ -1721,6 +1797,12 @@ log_io_complete_checkpoint(void)
}
mutex_exit(&(log_sys->mutex));
/* Wake the redo log watching thread to parse the log up to this
checkpoint. */
if (srv_track_changed_pages) {
os_event_set(srv_checkpoint_completed_event);
}
}
/*******************************************************************//**
......@@ -3065,6 +3147,15 @@ log_check_margins(void)
log_checkpoint_margin();
mutex_enter(&(log_sys->mutex));
if (log_check_tracking_margin(0)) {
mutex_exit(&(log_sys->mutex));
os_thread_sleep(10000);
goto loop;
}
mutex_exit(&(log_sys->mutex));
#ifdef UNIV_LOG_ARCHIVE
log_archive_margin();
#endif /* UNIV_LOG_ARCHIVE */
......@@ -3093,6 +3184,7 @@ logs_empty_and_mark_files_at_shutdown(void)
/*=======================================*/
{
ib_uint64_t lsn;
ib_uint64_t tracked_lsn;
ulint arch_log_no;
if (srv_print_verbose_log) {
......@@ -3198,9 +3290,12 @@ logs_empty_and_mark_files_at_shutdown(void)
mutex_enter(&(log_sys->mutex));
tracked_lsn = log_get_tracked_lsn();
lsn = log_sys->lsn;
if (lsn != log_sys->last_checkpoint_lsn
|| (srv_track_changed_pages && (tracked_lsn != log_sys->last_checkpoint_lsn))
#ifdef UNIV_LOG_ARCHIVE
|| (srv_log_archive_on
&& lsn != log_sys->archived_lsn + LOG_BLOCK_HDR_SIZE)
......@@ -3255,6 +3350,11 @@ logs_empty_and_mark_files_at_shutdown(void)
srv_shutdown_state = SRV_SHUTDOWN_LAST_PHASE;
/* Signal the log following thread to quit */
if (srv_track_changed_pages) {
os_event_set(srv_checkpoint_completed_event);
}
/* Make some checks that the server really is quiet */
ut_a(srv_n_threads_active[SRV_MASTER] == 0);
ut_a(buf_all_freed());
......@@ -3274,6 +3374,10 @@ logs_empty_and_mark_files_at_shutdown(void)
fil_flush_file_spaces(FIL_TABLESPACE);
if (srv_track_changed_pages) {
os_event_wait(srv_redo_log_thread_finished_event);
}
fil_close_all_files();
/* Make some checks that the server really is quiet */
......@@ -3399,6 +3503,18 @@ log_print(
((log_sys->n_log_ios - log_sys->n_log_ios_old)
/ time_elapsed));
if (srv_track_changed_pages) {
/* The maximum tracked LSN age is equal to the maximum
checkpoint age */
fprintf(file,
"Log tracking enabled\n"
"Log tracked up to %llu\n"
"Max tracked LSN age %lu\n",
log_get_tracked_lsn(),
log_sys->max_checkpoint_age);
}
log_sys->n_log_ios_old = log_sys->n_log_ios;
log_sys->last_printout_time = current_time;
......
This diff is collapsed.
......@@ -840,7 +840,7 @@ block. We also accept a log block in the old format before
InnoDB-3.23.52 where the checksum field contains the log block number.
@return TRUE if ok, or if the log block may be in the format of InnoDB
version predating 3.23.52 */
static
UNIV_INTERN
ibool
log_block_checksum_is_ok_or_old_format(
/*===================================*/
......@@ -2084,7 +2084,7 @@ recv_apply_log_recs_for_backup(void)
/*******************************************************************//**
Tries to parse a single log record and returns its length.
@return length of the record, or 0 if the record was not complete */
static
UNIV_INTERN
ulint
recv_parse_log_rec(
/*===============*/
......@@ -2155,7 +2155,7 @@ recv_parse_log_rec(
/*******************************************************//**
Calculates the new value for lsn when more data is added to the log. */
static
UNIV_INTERN
ib_uint64_t
recv_calc_lsn_on_data_add(
/*======================*/
......@@ -3542,6 +3542,8 @@ recv_reset_logs(
log_sys->archived_lsn = log_sys->lsn;
#endif /* UNIV_LOG_ARCHIVE */
log_sys->tracked_lsn = log_sys->lsn;
log_block_init(log_sys->buf, log_sys->lsn);
log_block_set_first_rec_group(log_sys->buf, LOG_BLOCK_HDR_SIZE);
......
......@@ -1939,6 +1939,25 @@ os_file_set_eof(
#endif /* __WIN__ */
}
/***********************************************************************//**
Truncates a file at the specified position.
@return TRUE if success */
UNIV_INTERN
ibool
os_file_set_eof_at(
os_file_t file, /*!< in: handle to a file */
ib_uint64_t new_len)/*!< in: new file length */
{
#ifdef __WIN__
/* TODO: untested! */
return(!_chsize_s(file, new_len));
#else
/* TODO: works only with -D_FILE_OFFSET_BITS=64 ? */
return(!ftruncate(file, new_len));
#endif
}
#ifndef __WIN__
/***********************************************************************//**
Wrapper to fsync(2) that retries the call on some errors.
......
......@@ -1902,6 +1902,7 @@ page_cur_delete_rec(
/* Save to local variables some data associated with current_rec */
cur_slot_no = page_dir_find_owner_slot(current_rec);
ut_ad(cur_slot_no > 0);
cur_dir_slot = page_dir_get_nth_slot(page, cur_slot_no);
cur_n_owned = page_dir_slot_get_n_owned(cur_dir_slot);
......
......@@ -780,17 +780,23 @@ page_copy_rec_list_start(
if (UNIV_LIKELY_NULL(new_page_zip)) {
mtr_set_log_mode(mtr, log_mode);
DBUG_EXECUTE_IF("page_copy_rec_list_start_compress_fail",
goto zip_reorganize;);
if (UNIV_UNLIKELY
(!page_zip_compress(new_page_zip, new_page, index, mtr))) {
ulint ret_pos;
#ifndef DBUG_OFF
zip_reorganize:
#endif /* DBUG_OFF */
/* Before trying to reorganize the page,
store the number of preceding records on the page. */
ulint ret_pos
= page_rec_get_n_recs_before(ret);
ret_pos = page_rec_get_n_recs_before(ret);
/* Before copying, "ret" was the predecessor
of the predefined supremum record. If it was
the predefined infimum record, then it would
still be the infimum. Thus, the assertion
ut_a(ret_pos > 0) would fail here. */
still be the infimum, and we would have
ret_pos == 0. */
if (UNIV_UNLIKELY
(!page_zip_reorganize(new_block, index, mtr))) {
......@@ -806,15 +812,10 @@ page_copy_rec_list_start(
btr_blob_dbg_add(new_page, index,
"copy_start_reorg_fail");
return(NULL);
} else {
/* The page was reorganized:
Seek to ret_pos. */
ret = new_page + PAGE_NEW_INFIMUM;
do {
ret = rec_get_next_ptr(ret, TRUE);
} while (--ret_pos);
}
/* The page was reorganized: Seek to ret_pos. */
ret = page_rec_get_nth(new_page, ret_pos);
}
}
......@@ -1050,6 +1051,7 @@ page_delete_rec_list_end(
n_owned = rec_get_n_owned_new(rec2) - count;
slot_index = page_dir_find_owner_slot(rec2);
ut_ad(slot_index > 0);
slot = page_dir_get_nth_slot(page, slot_index);
} else {
rec_t* rec2 = rec;
......@@ -1065,6 +1067,7 @@ page_delete_rec_list_end(
n_owned = rec_get_n_owned_old(rec2) - count;
slot_index = page_dir_find_owner_slot(rec2);
ut_ad(slot_index > 0);
slot = page_dir_get_nth_slot(page, slot_index);
}
......@@ -1491,6 +1494,10 @@ page_rec_get_nth_const(
ulint n_owned;
const rec_t* rec;
if (nth == 0) {
return(page_get_infimum_rec(page));
}
ut_ad(nth < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1));
for (i = 0;; i++) {
......@@ -1584,7 +1591,7 @@ page_rec_get_n_recs_before(
n--;
ut_ad(n >= 0);
ut_ad(n < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1));
ut_ad((ulint) n < UNIV_PAGE_SIZE / (REC_N_NEW_EXTRA_BYTES + 1));
return((ulint) n);
}
......
......@@ -93,7 +93,6 @@ MYSQL_PLUGIN_ACTIONS(xtradb, [
if (res != 10 || c != 123) {
return(1);
}
return(0);
}
],
......@@ -107,6 +106,42 @@ MYSQL_PLUGIN_ACTIONS(xtradb, [
]
)
AC_MSG_CHECKING(whether GCC 64-bit atomic builtins are available)
# either define HAVE_IB_GCC_ATOMIC_BUILTINS_64 or not
AC_TRY_RUN(
[
#include <stdint.h>
int main()
{
int64_t x, y, res;
x = 10;
y = 123;
res = __sync_bool_compare_and_swap(&x, x, y);
if (!res || x != y) {
return(1);
}
x = 10;
y = 123;
res = __sync_add_and_fetch(&x, y);
if (res != 123 + 10 || x != 123 + 10) {
return(1);
}
return(0);
}
],
[
AC_DEFINE([HAVE_IB_GCC_ATOMIC_BUILTINS_64], [1],
[GCC 64-bit atomic builtins are available])
AC_MSG_RESULT(yes)
],
[
AC_MSG_RESULT(no)
]
)
AC_MSG_CHECKING(whether pthread_t can be used by GCC atomic builtins)
# either define HAVE_IB_ATOMIC_PTHREAD_T_GCC or not
AC_TRY_RUN(
......
......@@ -1296,7 +1296,8 @@ row_ins_check_foreign_constraint(
check_index = foreign->foreign_index;
}
if (check_table == NULL || check_table->ibd_file_missing) {
if (check_table == NULL || check_table->ibd_file_missing
|| check_index == NULL) {
if (check_ref) {
FILE* ef = dict_foreign_err_file;
......@@ -1331,9 +1332,6 @@ row_ins_check_foreign_constraint(
goto exit_func;
}
ut_a(check_table);
ut_a(check_index);
if (check_table != table) {
/* We already have a LOCK_IX on table, but not necessarily
on check_table */
......@@ -2194,9 +2192,16 @@ row_ins_index_entry_low(
goto function_exit;
}
err = btr_cur_pessimistic_insert(
err = btr_cur_optimistic_insert(
0, &cursor, entry, &insert_rec, &big_rec,
n_ext, thr, &mtr);
if (err == DB_FAIL) {
err = btr_cur_pessimistic_insert(
0, &cursor, entry, &insert_rec,
&big_rec, n_ext, thr, &mtr);
}
}
}
......
......@@ -1214,11 +1214,25 @@ row_merge_read_clustered_index(
goto err_exit;
}
/* Store the cursor position on the last user
record on the page. */
btr_pcur_move_to_prev_on_page(&pcur);
/* Leaf pages must never be empty, unless
this is the only page in the index tree. */
ut_ad(btr_pcur_is_on_user_rec(&pcur)
|| buf_block_get_page_no(
btr_pcur_get_block(&pcur))
== clust_index->page);
btr_pcur_store_position(&pcur, &mtr);
mtr_commit(&mtr);
mtr_start(&mtr);
/* Restore position on the record, or its
predecessor if the record was purged
meanwhile. */
btr_pcur_restore_position(BTR_SEARCH_LEAF,
&pcur, &mtr);
/* Move to the successor of the original record. */
has_next = btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
......
......@@ -3636,7 +3636,7 @@ row_mysql_drop_temp_tables(void)
btr_pcur_store_position(&pcur, &mtr);
btr_pcur_commit_specify_mtr(&pcur, &mtr);
table = dict_load_table(table_name);
table = dict_table_get_low(table_name);
if (table) {
row_drop_table_for_mysql(table_name, trx, FALSE);
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment