Automatic merge with 5.1
This commit is contained in:
commit
3797ca41b3
@ -4091,7 +4091,7 @@ static int com_source(String *buffer, char *line)
|
||||
If we got an error during source operation, don't abort the client
|
||||
if ignore_errors is set
|
||||
*/
|
||||
if (error && !batch_abort_on_error && ignore_errors)
|
||||
if (error && ignore_errors)
|
||||
error= -1; // Ignore error
|
||||
return error;
|
||||
}
|
||||
|
@ -1876,7 +1876,7 @@ void check_result()
|
||||
if (access(reject_file, W_OK) == 0)
|
||||
{
|
||||
/* Result file directory is writable, save reject file there */
|
||||
fn_format(reject_file, result_file_name, NULL,
|
||||
fn_format(reject_file, result_file_name, "",
|
||||
".reject", MY_REPLACE_EXT);
|
||||
}
|
||||
else
|
||||
|
24
dbug/dbug.c
24
dbug/dbug.c
@ -286,7 +286,7 @@ typedef struct _db_code_state_ {
|
||||
#define ListDel(A,B,C) ListAddDel(A,B,C,EXCLUDE)
|
||||
static struct link *ListAddDel(struct link *, const char *, const char *, int);
|
||||
static struct link *ListCopy(struct link *);
|
||||
static int InList(struct link *linkp,const char *cp);
|
||||
static int InList(struct link *linkp,const char *cp, int exact_match);
|
||||
static uint ListFlags(struct link *linkp);
|
||||
static void FreeList(struct link *linkp);
|
||||
|
||||
@ -1581,13 +1581,13 @@ static struct link *ListCopy(struct link *orig)
|
||||
*
|
||||
*/
|
||||
|
||||
static int InList(struct link *linkp, const char *cp)
|
||||
static int InList(struct link *linkp, const char *cp, int exact_match)
|
||||
{
|
||||
int result;
|
||||
|
||||
for (result=MATCHED; linkp != NULL; linkp= linkp->next_link)
|
||||
{
|
||||
if (!fnmatch(linkp->str, cp, 0))
|
||||
if (!(exact_match ? strcmp(linkp->str,cp) : fnmatch(linkp->str, cp, 0)))
|
||||
return linkp->flags;
|
||||
if (!(linkp->flags & EXCLUDE))
|
||||
result=NOT_MATCHED;
|
||||
@ -1752,8 +1752,8 @@ void _db_end_()
|
||||
static int DoTrace(CODE_STATE *cs)
|
||||
{
|
||||
if ((cs->stack->maxdepth == 0 || cs->level <= cs->stack->maxdepth) &&
|
||||
InList(cs->stack->processes, cs->process) & (MATCHED|INCLUDE))
|
||||
switch(InList(cs->stack->functions, cs->func)) {
|
||||
InList(cs->stack->processes, cs->process, 0) & (MATCHED|INCLUDE))
|
||||
switch(InList(cs->stack->functions, cs->func, 0)) {
|
||||
case INCLUDE|SUBDIR: return ENABLE_TRACE;
|
||||
case INCLUDE: return DO_TRACE;
|
||||
case MATCHED|SUBDIR:
|
||||
@ -1790,10 +1790,10 @@ static int DoTrace(CODE_STATE *cs)
|
||||
#ifndef THREAD
|
||||
static BOOLEAN DoProfile(CODE_STATE *cs)
|
||||
{
|
||||
return PROFILING &&
|
||||
cs->level <= cs->stack->maxdepth &&
|
||||
InList(cs->stack->p_functions, cs->func) & (INCLUDE|MATCHED) &&
|
||||
InList(cs->stack->processes, cs->process) & (INCLUDE|MATCHED);
|
||||
return (PROFILING &&
|
||||
cs->level <= cs->stack->maxdepth &&
|
||||
InList(cs->stack->p_functions, cs->func, 0) & (INCLUDE|MATCHED) &&
|
||||
InList(cs->stack->processes, cs->process, 0) & (INCLUDE|MATCHED));
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1826,11 +1826,11 @@ FILE *_db_fp_(void)
|
||||
|
||||
BOOLEAN _db_keyword_(CODE_STATE *cs, const char *keyword, int strict)
|
||||
{
|
||||
int match= strict ? INCLUDE : INCLUDE|MATCHED;
|
||||
get_code_state_if_not_set_or_return FALSE;
|
||||
strict=strict ? INCLUDE : INCLUDE|MATCHED;
|
||||
|
||||
return DEBUGGING && DoTrace(cs) & DO_TRACE &&
|
||||
InList(cs->stack->keywords, keyword) & strict;
|
||||
return (DEBUGGING && DoTrace(cs) & DO_TRACE &&
|
||||
InList(cs->stack->keywords, keyword, strict) & match);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -50,6 +50,7 @@
|
||||
#define HA_OPEN_COPY 256 /* Open copy (for repair) */
|
||||
/* Internal temp table, used for temporary results */
|
||||
#define HA_OPEN_INTERNAL_TABLE 512
|
||||
#define HA_OPEN_MERGE_TABLE 1024
|
||||
|
||||
/* The following is parameter to ha_rkey() how to use key */
|
||||
|
||||
@ -196,6 +197,7 @@ enum ha_extra_function {
|
||||
*/
|
||||
HA_EXTRA_ATTACH_CHILDREN,
|
||||
HA_EXTRA_DETACH_CHILDREN,
|
||||
HA_EXTRA_DETACH_CHILD,
|
||||
/* Inform handler we will force a close as part of flush */
|
||||
HA_EXTRA_PREPARE_FOR_FORCED_CLOSE
|
||||
};
|
||||
|
@ -82,6 +82,12 @@ enum enum_thr_lock_result { THR_LOCK_SUCCESS= 0, THR_LOCK_ABORTED= 1,
|
||||
THR_LOCK_WAIT_TIMEOUT= 2, THR_LOCK_DEADLOCK= 3 };
|
||||
|
||||
|
||||
/* Priority for locks */
|
||||
#define THR_LOCK_LATE_PRIV 1 /* For locks to be merged with org lock */
|
||||
#define THR_LOCK_MERGE_PRIV 2 /* For merge tables */
|
||||
|
||||
#define THR_UNLOCK_UPDATE_STATUS 1
|
||||
|
||||
extern ulong max_write_lock_count;
|
||||
extern ulong table_lock_wait_timeout;
|
||||
extern my_bool thr_lock_inited;
|
||||
@ -116,9 +122,10 @@ typedef struct st_thr_lock_data {
|
||||
struct st_thr_lock_data *next,**prev;
|
||||
struct st_thr_lock *lock;
|
||||
pthread_cond_t *cond;
|
||||
enum thr_lock_type type;
|
||||
void *status_param; /* Param to status functions */
|
||||
void *debug_print_param;
|
||||
enum thr_lock_type type;
|
||||
uint priority;
|
||||
} THR_LOCK_DATA;
|
||||
|
||||
struct st_lock_list {
|
||||
@ -138,8 +145,10 @@ typedef struct st_thr_lock {
|
||||
void (*get_status)(void*, my_bool); /* When one gets a lock */
|
||||
void (*copy_status)(void*,void*);
|
||||
void (*update_status)(void*); /* Before release of write */
|
||||
void (*restore_status)(void*); /* Before release of read */
|
||||
void (*restore_status)(void*); /* Before release of read */
|
||||
my_bool (*start_trans)(void*); /* When all locks are taken */
|
||||
my_bool (*check_status)(void *);
|
||||
void (*fix_status)(void *, void *);/* For thr_merge_locks() */
|
||||
my_bool allow_multiple_concurrent_insert;
|
||||
} THR_LOCK;
|
||||
|
||||
@ -154,13 +163,11 @@ void thr_lock_init(THR_LOCK *lock);
|
||||
void thr_lock_delete(THR_LOCK *lock);
|
||||
void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data,
|
||||
void *status_param);
|
||||
enum enum_thr_lock_result thr_lock(THR_LOCK_DATA *data,
|
||||
THR_LOCK_OWNER *owner,
|
||||
enum thr_lock_type lock_type);
|
||||
void thr_unlock(THR_LOCK_DATA *data);
|
||||
void thr_unlock(THR_LOCK_DATA *data, uint unlock_flags);
|
||||
enum enum_thr_lock_result thr_multi_lock(THR_LOCK_DATA **data,
|
||||
uint count, THR_LOCK_OWNER *owner);
|
||||
void thr_multi_unlock(THR_LOCK_DATA **data,uint count);
|
||||
void thr_multi_unlock(THR_LOCK_DATA **data,uint count, uint unlock_flags);
|
||||
void thr_merge_locks(THR_LOCK_DATA **data, uint org_count, uint new_count);
|
||||
void thr_abort_locks(THR_LOCK *lock, my_bool upgrade_lock);
|
||||
my_bool thr_abort_locks_for_thread(THR_LOCK *lock, my_thread_id thread);
|
||||
void thr_print_locks(void); /* For debugging */
|
||||
|
@ -4281,6 +4281,7 @@ sub extract_warning_lines ($) {
|
||||
qr/Slave SQL thread retried transaction/,
|
||||
qr/Slave \(additional info\)/,
|
||||
qr/Incorrect information in file/,
|
||||
qr/Incorrect key file for table .*crashed.*/,
|
||||
qr/Slave I\/O: Get master SERVER_ID failed with error:.*/,
|
||||
qr/Slave I\/O: Get master clock failed with error:.*/,
|
||||
qr/Slave I\/O: Get master COLLATION_SERVER failed with error:.*/,
|
||||
|
@ -1574,7 +1574,7 @@ UNLOCK TABLES;
|
||||
#
|
||||
# Trigger on parent
|
||||
DELETE FROM t4 WHERE c1 = 4;
|
||||
CREATE TRIGGER t4_ai AFTER INSERT ON t4 FOR EACH ROW SET @a=1;
|
||||
CREATE TRIGGER t4_ai1 AFTER INSERT ON t4 FOR EACH ROW SET @a=1;
|
||||
SET @a=0;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT @a;
|
||||
@ -1586,10 +1586,13 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
DROP TRIGGER t4_ai;
|
||||
DROP TRIGGER t4_ai1;
|
||||
CHECK TABLE t3;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t3 check status OK
|
||||
# Trigger on parent under LOCK TABLES
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
CREATE TRIGGER t4_ai AFTER INSERT ON t4 FOR EACH ROW SET @a=1;
|
||||
CREATE TRIGGER t4_ai2 AFTER INSERT ON t4 FOR EACH ROW SET @a=1;
|
||||
SET @a=0;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT @a;
|
||||
@ -1602,12 +1605,15 @@ c1
|
||||
3
|
||||
4
|
||||
4
|
||||
DROP TRIGGER t4_ai;
|
||||
DROP TRIGGER t4_ai2;
|
||||
UNLOCK TABLES;
|
||||
CHECK TABLE t3;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t3 check status OK
|
||||
#
|
||||
# Trigger on child
|
||||
DELETE FROM t4 WHERE c1 = 4;
|
||||
CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW SET @a=1;
|
||||
CREATE TRIGGER t3_ai3 AFTER INSERT ON t3 FOR EACH ROW SET @a=1;
|
||||
SET @a=0;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT @a;
|
||||
@ -1624,10 +1630,13 @@ c1
|
||||
3
|
||||
4
|
||||
33
|
||||
DROP TRIGGER t3_ai;
|
||||
DROP TRIGGER t3_ai3;
|
||||
CHECK TABLE t3;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t3 check status OK
|
||||
# Trigger on child under LOCK TABLES
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW SET @a=1;
|
||||
CREATE TRIGGER t3_ai4 AFTER INSERT ON t3 FOR EACH ROW SET @a=1;
|
||||
SET @a=0;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT @a;
|
||||
@ -1647,11 +1656,17 @@ c1
|
||||
33
|
||||
33
|
||||
DELETE FROM t4 WHERE c1 = 33;
|
||||
DROP TRIGGER t3_ai;
|
||||
DROP TRIGGER t3_ai4;
|
||||
CHECK TABLE t3;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t3 check status OK
|
||||
#
|
||||
# Trigger with table use on child
|
||||
DELETE FROM t4 WHERE c1 = 4;
|
||||
CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
CREATE TRIGGER t3_ai5 AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
SELECT COUNT(*) FROM t2;
|
||||
COUNT(*)
|
||||
1
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
c1
|
||||
@ -1670,10 +1685,15 @@ c1
|
||||
33
|
||||
DELETE FROM t4 WHERE c1 = 22;
|
||||
DELETE FROM t4 WHERE c1 = 33;
|
||||
DROP TRIGGER t3_ai;
|
||||
DROP TRIGGER t3_ai5;
|
||||
UNLOCK TABLES;
|
||||
CHECK TABLE t2,t3;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t2 check status OK
|
||||
test.t3 check status OK
|
||||
# Trigger with table use on child under LOCK TABLES
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
CREATE TRIGGER t3_ai6 AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
c1
|
||||
@ -1692,10 +1712,44 @@ c1
|
||||
4
|
||||
22
|
||||
33
|
||||
DROP TRIGGER t3_ai;
|
||||
DROP TRIGGER t3_ai6;
|
||||
UNLOCK TABLES;
|
||||
check table t2,t3,t4;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t2 check status OK
|
||||
test.t3 check status OK
|
||||
test.t4 check status OK
|
||||
DELETE FROM t4 WHERE c1 = 22;
|
||||
DELETE FROM t4 WHERE c1 = 33;
|
||||
# Trigger with table use on child under different LOCK TABLES
|
||||
DELETE FROM t4 WHERE c1 = 4;
|
||||
LOCK TABLES t4 WRITE,t3 WRITE, t2 WRITE, t1 WRITE;
|
||||
CREATE TRIGGER t3_ai7 AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
c1
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
INSERT INTO t3 VALUES (33);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
c1
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
22
|
||||
33
|
||||
DROP TRIGGER t3_ai7;
|
||||
UNLOCK TABLES;
|
||||
check table t2,t3,t4;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t2 check status OK
|
||||
test.t3 check status OK
|
||||
test.t4 check status OK
|
||||
DELETE FROM t4 WHERE c1 = 22;
|
||||
DELETE FROM t4 WHERE c1 = 33;
|
||||
#
|
||||
# Repair
|
||||
#
|
||||
@ -1711,7 +1765,6 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
REPAIR TABLE t4;
|
||||
Table Op Msg_type Msg_text
|
||||
@ -1725,7 +1778,6 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
UNLOCK TABLES;
|
||||
#
|
||||
# Optimize
|
||||
@ -1742,7 +1794,6 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
OPTIMIZE TABLE t4;
|
||||
Table Op Msg_type Msg_text
|
||||
@ -1756,14 +1807,13 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
UNLOCK TABLES;
|
||||
#
|
||||
# Checksum
|
||||
#
|
||||
CHECKSUM TABLE t4;
|
||||
Table Checksum
|
||||
test.t4 46622073
|
||||
test.t4 149057747
|
||||
CHECKSUM TABLE t2;
|
||||
Table Checksum
|
||||
test.t2 3700403066
|
||||
@ -1773,11 +1823,10 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
CHECKSUM TABLE t4;
|
||||
Table Checksum
|
||||
test.t4 46622073
|
||||
test.t4 149057747
|
||||
CHECKSUM TABLE t2;
|
||||
Table Checksum
|
||||
test.t2 3700403066
|
||||
@ -1787,7 +1836,6 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
UNLOCK TABLES;
|
||||
#
|
||||
# Insert delayed
|
||||
@ -1801,7 +1849,6 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
33
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
INSERT DELAYED INTO t4 VALUES(444);
|
||||
@ -1814,7 +1861,6 @@ c1
|
||||
2
|
||||
3
|
||||
4
|
||||
4
|
||||
33
|
||||
UNLOCK TABLES;
|
||||
DROP TABLE t1, t2, t3, t4;
|
||||
|
24
mysql-test/r/merge_debug.result
Normal file
24
mysql-test/r/merge_debug.result
Normal file
@ -0,0 +1,24 @@
|
||||
set global storage_engine=myisam;
|
||||
set session storage_engine=myisam;
|
||||
drop table if exists crashed,t2,t3,t4;
|
||||
SET @orig_debug=@@debug;
|
||||
CREATE TABLE crashed (c1 INT);
|
||||
CREATE TABLE t2 (c1 INT);
|
||||
CREATE TABLE t3 (c1 INT);
|
||||
CREATE TABLE t4 (c1 INT) ENGINE=MRG_MYISAM UNION=(crashed,t2,t3) INSERT_METHOD=LAST;
|
||||
INSERT INTO crashed VALUES (10);
|
||||
INSERT INTO t2 VALUES (20);
|
||||
INSERT INTO t3 VALUES (30);
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, crashed WRITE;
|
||||
SET GLOBAL debug="+d,*,myisam_pretend_crashed_table_on_open";
|
||||
CREATE TRIGGER t1_ai AFTER INSERT ON crashed FOR EACH ROW INSERT INTO t2 VALUES(29);
|
||||
SET GLOBAL debug=@orig_debug;
|
||||
INSERT INTO t4 VALUES (39);
|
||||
ERROR HY000: Table 't4' was not locked with LOCK TABLES
|
||||
INSERT INTO crashed VALUES (11);
|
||||
ERROR HY000: Table 'crashed' was not locked with LOCK TABLES
|
||||
INSERT INTO t2 VALUES (21);
|
||||
INSERT INTO t3 VALUES (31);
|
||||
UNLOCK TABLES;
|
||||
DROP TRIGGER t1_ai;
|
||||
DROP TABLE t4,crashed,t2,t3;
|
@ -3,6 +3,7 @@ CREATE FUNCTION metaphon RETURNS STRING SONAME "UDF_EXAMPLE_LIB";
|
||||
create table t1 (a char);
|
||||
set GLOBAL query_cache_size=1355776;
|
||||
reset query cache;
|
||||
flush status;
|
||||
select metaphon('MySQL') from t1;
|
||||
metaphon('MySQL')
|
||||
show status like "Qcache_hits";
|
||||
|
@ -408,7 +408,7 @@ ALTER TABLE t1_will_crash CHECK PARTITION p6;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1_will_crash check warning Size of datafile is: 868 Should be: 604
|
||||
test.t1_will_crash check error Record-count is not ok; is 8 Should be: 7
|
||||
test.t1_will_crash check warning Found 10 key parts. Should be: 7
|
||||
test.t1_will_crash check warning Found 10 parts. Should be: 7
|
||||
test.t1_will_crash check error Partition p6 returned error
|
||||
test.t1_will_crash check error Corrupt
|
||||
ALTER TABLE t1_will_crash REPAIR PARTITION p6;
|
||||
|
@ -1119,35 +1119,38 @@ UNLOCK TABLES;
|
||||
--echo #
|
||||
--echo # Trigger on parent
|
||||
DELETE FROM t4 WHERE c1 = 4;
|
||||
CREATE TRIGGER t4_ai AFTER INSERT ON t4 FOR EACH ROW SET @a=1;
|
||||
CREATE TRIGGER t4_ai1 AFTER INSERT ON t4 FOR EACH ROW SET @a=1;
|
||||
SET @a=0;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT @a;
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
DROP TRIGGER t4_ai;
|
||||
DROP TRIGGER t4_ai1;
|
||||
CHECK TABLE t3;
|
||||
--echo # Trigger on parent under LOCK TABLES
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
CREATE TRIGGER t4_ai AFTER INSERT ON t4 FOR EACH ROW SET @a=1;
|
||||
CREATE TRIGGER t4_ai2 AFTER INSERT ON t4 FOR EACH ROW SET @a=1;
|
||||
SET @a=0;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT @a;
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
DROP TRIGGER t4_ai;
|
||||
DROP TRIGGER t4_ai2;
|
||||
UNLOCK TABLES;
|
||||
CHECK TABLE t3;
|
||||
--echo #
|
||||
--echo # Trigger on child
|
||||
DELETE FROM t4 WHERE c1 = 4;
|
||||
CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW SET @a=1;
|
||||
CREATE TRIGGER t3_ai3 AFTER INSERT ON t3 FOR EACH ROW SET @a=1;
|
||||
SET @a=0;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT @a;
|
||||
INSERT INTO t3 VALUES (33);
|
||||
SELECT @a;
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
DROP TRIGGER t3_ai;
|
||||
DROP TRIGGER t3_ai3;
|
||||
CHECK TABLE t3;
|
||||
--echo # Trigger on child under LOCK TABLES
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW SET @a=1;
|
||||
CREATE TRIGGER t3_ai4 AFTER INSERT ON t3 FOR EACH ROW SET @a=1;
|
||||
SET @a=0;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT @a;
|
||||
@ -1155,29 +1158,47 @@ INSERT INTO t3 VALUES (33);
|
||||
SELECT @a;
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
DELETE FROM t4 WHERE c1 = 33;
|
||||
DROP TRIGGER t3_ai;
|
||||
DROP TRIGGER t3_ai4;
|
||||
CHECK TABLE t3;
|
||||
--echo #
|
||||
--echo # Trigger with table use on child
|
||||
DELETE FROM t4 WHERE c1 = 4;
|
||||
CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
CREATE TRIGGER t3_ai5 AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
SELECT COUNT(*) FROM t2;
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
INSERT INTO t3 VALUES (33);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
DELETE FROM t4 WHERE c1 = 22;
|
||||
DELETE FROM t4 WHERE c1 = 33;
|
||||
DROP TRIGGER t3_ai;
|
||||
DROP TRIGGER t3_ai5;
|
||||
UNLOCK TABLES;
|
||||
CHECK TABLE t2,t3;
|
||||
--echo # Trigger with table use on child under LOCK TABLES
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, t1 WRITE;
|
||||
CREATE TRIGGER t3_ai AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
CREATE TRIGGER t3_ai6 AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
INSERT INTO t3 VALUES (33);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
DROP TRIGGER t3_ai;
|
||||
DROP TRIGGER t3_ai6;
|
||||
UNLOCK TABLES;
|
||||
check table t2,t3,t4;
|
||||
DELETE FROM t4 WHERE c1 = 22;
|
||||
DELETE FROM t4 WHERE c1 = 33;
|
||||
--echo # Trigger with table use on child under different LOCK TABLES
|
||||
DELETE FROM t4 WHERE c1 = 4;
|
||||
LOCK TABLES t4 WRITE,t3 WRITE, t2 WRITE, t1 WRITE;
|
||||
CREATE TRIGGER t3_ai7 AFTER INSERT ON t3 FOR EACH ROW INSERT INTO t2 VALUES(22);
|
||||
INSERT INTO t4 VALUES (4);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
INSERT INTO t3 VALUES (33);
|
||||
SELECT * FROM t4 ORDER BY c1;
|
||||
DROP TRIGGER t3_ai7;
|
||||
UNLOCK TABLES;
|
||||
check table t2,t3,t4;
|
||||
DELETE FROM t4 WHERE c1 = 22;
|
||||
DELETE FROM t4 WHERE c1 = 33;
|
||||
#
|
||||
--echo #
|
||||
--echo # Repair
|
||||
|
42
mysql-test/t/merge_debug.test
Normal file
42
mysql-test/t/merge_debug.test
Normal file
@ -0,0 +1,42 @@
|
||||
#
|
||||
# Test failures with MERGE
|
||||
#
|
||||
|
||||
--source include/have_debug.inc
|
||||
|
||||
let $default=`select @@global.storage_engine`;
|
||||
set global storage_engine=myisam;
|
||||
set session storage_engine=myisam;
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists crashed,t2,t3,t4;
|
||||
--enable_warnings
|
||||
|
||||
SET @orig_debug=@@debug;
|
||||
|
||||
#
|
||||
# Check that MariaDB handles reopen that fails without crashing
|
||||
#
|
||||
CREATE TABLE crashed (c1 INT);
|
||||
CREATE TABLE t2 (c1 INT);
|
||||
CREATE TABLE t3 (c1 INT);
|
||||
CREATE TABLE t4 (c1 INT) ENGINE=MRG_MYISAM UNION=(crashed,t2,t3) INSERT_METHOD=LAST;
|
||||
INSERT INTO crashed VALUES (10);
|
||||
INSERT INTO t2 VALUES (20);
|
||||
INSERT INTO t3 VALUES (30);
|
||||
|
||||
LOCK TABLES t3 WRITE, t2 WRITE, t4 WRITE, crashed WRITE;
|
||||
SET GLOBAL debug="+d,*,myisam_pretend_crashed_table_on_open";
|
||||
--disable_warnings
|
||||
CREATE TRIGGER t1_ai AFTER INSERT ON crashed FOR EACH ROW INSERT INTO t2 VALUES(29);
|
||||
--enable_warnings
|
||||
SET GLOBAL debug=@orig_debug;
|
||||
--error ER_TABLE_NOT_LOCKED
|
||||
INSERT INTO t4 VALUES (39);
|
||||
--error ER_TABLE_NOT_LOCKED
|
||||
INSERT INTO crashed VALUES (11);
|
||||
INSERT INTO t2 VALUES (21);
|
||||
INSERT INTO t3 VALUES (31);
|
||||
UNLOCK TABLES;
|
||||
DROP TRIGGER t1_ai;
|
||||
DROP TABLE t4,crashed,t2,t3;
|
@ -20,6 +20,7 @@ create table t1 (a char);
|
||||
|
||||
set GLOBAL query_cache_size=1355776;
|
||||
reset query cache;
|
||||
flush status;
|
||||
|
||||
select metaphon('MySQL') from t1;
|
||||
show status like "Qcache_hits";
|
||||
|
@ -614,7 +614,6 @@ static int setval(const struct my_option *opts, void *value, char *argument,
|
||||
my_bool set_maximum_value)
|
||||
{
|
||||
int err= 0;
|
||||
int pos;
|
||||
|
||||
if (value && argument)
|
||||
{
|
||||
|
@ -34,8 +34,8 @@ File my_create_with_symlink(const char *linkname, const char *filename,
|
||||
char abs_linkname[FN_REFLEN];
|
||||
DBUG_ENTER("my_create_with_symlink");
|
||||
DBUG_PRINT("enter", ("linkname: %s filename: %s",
|
||||
linkname ? linkname : "(null)",
|
||||
filename ? filename : "(null)"));
|
||||
linkname ? linkname : "(NULL)",
|
||||
filename ? filename : "(NULL)"));
|
||||
|
||||
if (my_disable_symlinks)
|
||||
{
|
||||
|
216
mysys/thr_lock.c
216
mysys/thr_lock.c
@ -63,6 +63,11 @@ update_status:
|
||||
A storage engine should also call update_status internally
|
||||
in the ::external_lock(F_UNLCK) method.
|
||||
In MyISAM and CSV this functions updates the length of the datafile.
|
||||
MySQL does in some exceptional cases (when doing DLL statements on
|
||||
open tables calls thr_unlock() followed by thr_lock() without calling
|
||||
::external_lock() in between. In this case thr_unlock() is called with
|
||||
the THR_UNLOCK_UPDATE_STATUS flag and thr_unlock() will call
|
||||
update_status for write locks.
|
||||
get_status:
|
||||
When one gets a lock this functions is called.
|
||||
In MyISAM this stores the number of rows and size of the datafile
|
||||
@ -105,8 +110,30 @@ static inline pthread_cond_t *get_cond(void)
|
||||
return &my_thread_var->suspend;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** For the future (now the thread specific cond is alloced by my_pthread.c)
|
||||
Priority for locks (decides in which order locks are locked)
|
||||
We want all write locks to be first, followed by read locks.
|
||||
Locks from MERGE tables has a little lower priority than other
|
||||
locks, to allow one to release merge tables without having
|
||||
to unlock and re-lock other locks.
|
||||
The lower the number, the higher the priority for the lock.
|
||||
Read locks should have 4, write locks should have 0.
|
||||
UNLOCK is 8, to force these last in thr_merge_locks.
|
||||
For MERGE tables we add 2 (THR_LOCK_MERGE_PRIV) to the lock priority.
|
||||
THR_LOCK_LATE_PRIV (1) is used when one locks other tables to be merged
|
||||
with existing locks. This way we prioritize the original locks over the
|
||||
new locks.
|
||||
*/
|
||||
|
||||
static uint lock_priority[(uint)TL_WRITE_ONLY+1] =
|
||||
{ 8, 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
#define LOCK_CMP(A,B) ((uchar*) ((A)->lock) + lock_priority[(uint) (A)->type] + (A)->priority < (uchar*) ((B)->lock) + lock_priority[(uint) (B)->type] + (B)->priority)
|
||||
|
||||
|
||||
/*
|
||||
For the future (now the thread specific cond is alloced by my_pthread.c)
|
||||
*/
|
||||
|
||||
my_bool init_thr_lock()
|
||||
@ -379,6 +406,7 @@ void thr_lock_data_init(THR_LOCK *lock,THR_LOCK_DATA *data, void *param)
|
||||
data->owner= 0; /* no owner yet */
|
||||
data->status_param=param;
|
||||
data->cond=0;
|
||||
data->priority= 0;
|
||||
}
|
||||
|
||||
|
||||
@ -530,7 +558,7 @@ wait_for_lock(struct st_lock_list *wait, THR_LOCK_DATA *data,
|
||||
}
|
||||
|
||||
|
||||
enum enum_thr_lock_result
|
||||
static enum enum_thr_lock_result
|
||||
thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
|
||||
enum thr_lock_type lock_type)
|
||||
{
|
||||
@ -544,6 +572,7 @@ thr_lock(THR_LOCK_DATA *data, THR_LOCK_OWNER *owner,
|
||||
data->cond=0; /* safety */
|
||||
data->type=lock_type;
|
||||
data->owner= owner; /* Must be reset ! */
|
||||
data->priority&= ~THR_LOCK_LATE_PRIV;
|
||||
VOID(pthread_mutex_lock(&lock->mutex));
|
||||
DBUG_PRINT("lock",("data: 0x%lx thread: 0x%lx lock: 0x%lx type: %d",
|
||||
(long) data, data->owner->info->thread_id,
|
||||
@ -808,7 +837,7 @@ static inline void free_all_read_locks(THR_LOCK *lock,
|
||||
|
||||
/* Unlock lock and free next thread on same lock */
|
||||
|
||||
void thr_unlock(THR_LOCK_DATA *data)
|
||||
void thr_unlock(THR_LOCK_DATA *data, uint unlock_flags)
|
||||
{
|
||||
THR_LOCK *lock=data->lock;
|
||||
enum thr_lock_type lock_type=data->type;
|
||||
@ -832,6 +861,21 @@ void thr_unlock(THR_LOCK_DATA *data)
|
||||
}
|
||||
else
|
||||
lock->write.last=data->prev;
|
||||
|
||||
if (unlock_flags & THR_UNLOCK_UPDATE_STATUS)
|
||||
{
|
||||
/* External lock was not called; Update or restore status */
|
||||
if (lock_type >= TL_WRITE_CONCURRENT_INSERT)
|
||||
{
|
||||
if (lock->update_status)
|
||||
(*lock->update_status)(data->status_param);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (lock->restore_status)
|
||||
(*lock->restore_status)(data->status_param);
|
||||
}
|
||||
}
|
||||
if (lock_type == TL_READ_NO_INSERT)
|
||||
lock->read_no_write_count--;
|
||||
data->type=TL_UNLOCK; /* Mark unlocked */
|
||||
@ -967,14 +1011,12 @@ end:
|
||||
|
||||
|
||||
/*
|
||||
** Get all locks in a specific order to avoid dead-locks
|
||||
** Sort acording to lock position and put write_locks before read_locks if
|
||||
** lock on same lock.
|
||||
Get all locks in a specific order to avoid dead-locks
|
||||
Sort acording to lock position and put write_locks before read_locks if
|
||||
lock on same lock. Locks on MERGE tables has lower priority than other
|
||||
locks of the same type. See comment for lock_priority.
|
||||
*/
|
||||
|
||||
|
||||
#define LOCK_CMP(A,B) ((uchar*) (A->lock) - (uint) ((A)->type) < (uchar*) (B->lock)- (uint) ((B)->type))
|
||||
|
||||
static void sort_locks(THR_LOCK_DATA **data,uint count)
|
||||
{
|
||||
THR_LOCK_DATA **pos,**end,**prev,*tmp;
|
||||
@ -999,18 +1041,22 @@ static void sort_locks(THR_LOCK_DATA **data,uint count)
|
||||
enum enum_thr_lock_result
|
||||
thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner)
|
||||
{
|
||||
THR_LOCK_DATA **pos,**end;
|
||||
THR_LOCK_DATA **pos, **end, **first_lock;
|
||||
DBUG_ENTER("thr_multi_lock");
|
||||
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
|
||||
|
||||
if (count > 1)
|
||||
sort_locks(data,count);
|
||||
else if (count == 0)
|
||||
DBUG_RETURN(THR_LOCK_SUCCESS);
|
||||
|
||||
/* lock everything */
|
||||
for (pos=data,end=data+count; pos < end ; pos++)
|
||||
{
|
||||
enum enum_thr_lock_result result= thr_lock(*pos, owner, (*pos)->type);
|
||||
if (result != THR_LOCK_SUCCESS)
|
||||
{ /* Aborted */
|
||||
thr_multi_unlock(data,(uint) (pos-data));
|
||||
thr_multi_unlock(data,(uint) (pos-data), 0);
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
#ifdef MAIN
|
||||
@ -1018,63 +1064,103 @@ thr_multi_lock(THR_LOCK_DATA **data, uint count, THR_LOCK_OWNER *owner)
|
||||
(long) pos[0]->lock, pos[0]->type); fflush(stdout);
|
||||
#endif
|
||||
}
|
||||
/*
|
||||
Ensure that all get_locks() have the same status
|
||||
If we lock the same table multiple times, we must use the same
|
||||
status_param!
|
||||
*/
|
||||
#if !defined(DONT_USE_RW_LOCKS)
|
||||
if (count > 1)
|
||||
{
|
||||
THR_LOCK_DATA *last_lock= end[-1];
|
||||
pos=end-1;
|
||||
do
|
||||
{
|
||||
pos--;
|
||||
if (last_lock->lock == (*pos)->lock &&
|
||||
last_lock->lock->copy_status)
|
||||
{
|
||||
if (last_lock->type <= TL_READ_NO_INSERT)
|
||||
{
|
||||
THR_LOCK_DATA **read_lock;
|
||||
/*
|
||||
If we are locking the same table with read locks we must ensure
|
||||
that all tables share the status of the last write lock or
|
||||
the same read lock.
|
||||
*/
|
||||
for (;
|
||||
(*pos)->type <= TL_READ_NO_INSERT &&
|
||||
pos != data &&
|
||||
pos[-1]->lock == (*pos)->lock ;
|
||||
pos--) ;
|
||||
|
||||
read_lock = pos+1;
|
||||
do
|
||||
{
|
||||
(last_lock->lock->copy_status)((*read_lock)->status_param,
|
||||
(*pos)->status_param);
|
||||
} while (*(read_lock++) != last_lock);
|
||||
last_lock= (*pos); /* Point at last write lock */
|
||||
}
|
||||
else
|
||||
(*last_lock->lock->copy_status)((*pos)->status_param,
|
||||
last_lock->status_param);
|
||||
}
|
||||
else
|
||||
last_lock=(*pos);
|
||||
} while (pos != data);
|
||||
/*
|
||||
Call start_trans for all locks.
|
||||
If we lock the same table multiple times, we must use the same
|
||||
status_param; We ensure this by calling copy_status() for all
|
||||
copies of the same tables.
|
||||
*/
|
||||
if ((*data)->lock->start_trans)
|
||||
((*data)->lock->start_trans)((*data)->status_param);
|
||||
for (first_lock=data, pos= data+1 ; pos < end ; pos++)
|
||||
{
|
||||
/* Get the current status (row count, checksum, trid etc) */
|
||||
if ((*pos)->lock->start_trans)
|
||||
(*(*pos)->lock->start_trans)((*pos)->status_param);
|
||||
/*
|
||||
If same table as previous table use pointer to previous status
|
||||
information to ensure that all read/write tables shares same
|
||||
state.
|
||||
*/
|
||||
if (pos[0]->lock == pos[-1]->lock && pos[0]->lock->copy_status)
|
||||
(pos[0]->lock->copy_status)((*pos)->status_param,
|
||||
(*first_lock)->status_param);
|
||||
else
|
||||
{
|
||||
/* Different lock, use this as base for next lock */
|
||||
first_lock= pos;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
DBUG_RETURN(THR_LOCK_SUCCESS);
|
||||
}
|
||||
|
||||
/* free all locks */
|
||||
|
||||
void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
|
||||
/**
|
||||
Merge two sets of locks.
|
||||
|
||||
@param data All locks. First old locks, then new locks.
|
||||
@param old_count Original number of locks. These are first in 'data'.
|
||||
@param new_count How many new locks
|
||||
|
||||
The merge is needed if the new locks contains same tables as the old
|
||||
locks, in which case we have to ensure that same tables shares the
|
||||
same status (as after a thr_multi_lock()).
|
||||
*/
|
||||
|
||||
void thr_merge_locks(THR_LOCK_DATA **data, uint old_count, uint new_count)
|
||||
{
|
||||
THR_LOCK_DATA **pos, **end, **first_lock= 0;
|
||||
DBUG_ENTER("thr_merge_lock");
|
||||
|
||||
/* Remove marks on old locks to make them sort before new ones */
|
||||
for (pos=data, end= pos + old_count; pos < end ; pos++)
|
||||
(*pos)->priority&= ~THR_LOCK_LATE_PRIV;
|
||||
|
||||
/* Mark new locks with LATE_PRIV to make them sort after org ones */
|
||||
for (pos=data + old_count, end= pos + new_count; pos < end ; pos++)
|
||||
(*pos)->priority|= THR_LOCK_LATE_PRIV;
|
||||
|
||||
sort_locks(data, old_count + new_count);
|
||||
|
||||
for (pos=data ; pos < end ; pos++)
|
||||
{
|
||||
/* Check if lock was unlocked before */
|
||||
if (pos[0]->type == TL_UNLOCK || ! pos[0]->lock->fix_status)
|
||||
{
|
||||
DBUG_PRINT("info", ("lock skipped. unlocked: %d fix_status: %d",
|
||||
pos[0]->type == TL_UNLOCK,
|
||||
pos[0]->lock->fix_status == 0));
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
If same table as previous table use pointer to previous status
|
||||
information to ensure that all read/write tables shares same
|
||||
state.
|
||||
*/
|
||||
if (first_lock && pos[0]->lock == first_lock[0]->lock)
|
||||
(pos[0]->lock->fix_status)((*first_lock)->status_param,
|
||||
(*pos)->status_param);
|
||||
else
|
||||
{
|
||||
/* Different lock, use this as base for next lock */
|
||||
first_lock= pos;
|
||||
(pos[0]->lock->fix_status)((*first_lock)->status_param, 0);
|
||||
}
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/* Unlock all locks */
|
||||
|
||||
void thr_multi_unlock(THR_LOCK_DATA **data,uint count, uint unlock_flags)
|
||||
{
|
||||
THR_LOCK_DATA **pos,**end;
|
||||
DBUG_ENTER("thr_multi_unlock");
|
||||
DBUG_PRINT("lock",("data: 0x%lx count: %d", (long) data, count));
|
||||
DBUG_PRINT("lock",("data: 0x%lx count: %d flags: %u", (long) data, count,
|
||||
unlock_flags));
|
||||
|
||||
for (pos=data,end=data+count; pos < end ; pos++)
|
||||
{
|
||||
@ -1084,7 +1170,7 @@ void thr_multi_unlock(THR_LOCK_DATA **data,uint count)
|
||||
fflush(stdout);
|
||||
#endif
|
||||
if ((*pos)->type != TL_UNLOCK)
|
||||
thr_unlock(*pos);
|
||||
thr_unlock(*pos, unlock_flags);
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("lock",("Free lock: data: 0x%lx thread: 0x%lx lock: 0x%lx",
|
||||
@ -1400,6 +1486,7 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data,
|
||||
enum thr_lock_type new_lock_type)
|
||||
{
|
||||
THR_LOCK *lock=data->lock;
|
||||
enum enum_thr_lock_result res;
|
||||
DBUG_ENTER("thr_upgrade_write_delay_lock");
|
||||
|
||||
pthread_mutex_lock(&lock->mutex);
|
||||
@ -1420,6 +1507,8 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data,
|
||||
if (lock->get_status)
|
||||
(*lock->get_status)(data->status_param, 0);
|
||||
pthread_mutex_unlock(&lock->mutex);
|
||||
if (lock->start_trans)
|
||||
(*lock->start_trans)(data->status_param);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -1440,7 +1529,10 @@ my_bool thr_upgrade_write_delay_lock(THR_LOCK_DATA *data,
|
||||
{
|
||||
check_locks(lock,"waiting for lock",0);
|
||||
}
|
||||
DBUG_RETURN(wait_for_lock(&lock->write_wait,data,1));
|
||||
res= wait_for_lock(&lock->write_wait,data,1);
|
||||
if (res == THR_LOCK_SUCCESS && lock->start_trans)
|
||||
DBUG_RETURN((*lock->start_trans)(data->status_param));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
@ -1684,7 +1776,7 @@ static void *test_thread(void *arg)
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_thread_count);
|
||||
thr_multi_unlock(multi_locks,lock_counts[param]);
|
||||
thr_multi_unlock(multi_locks,lock_counts[param], THR_UNLOCK_UPDATE_STATUS);
|
||||
}
|
||||
|
||||
printf("Thread %s (%d) ended\n",my_thread_name(),param); fflush(stdout);
|
||||
|
@ -2643,8 +2643,18 @@ void handler::print_keydup_error(uint key_nr, const char *msg)
|
||||
- table->s->path
|
||||
- table->alias
|
||||
*/
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
#define SET_FATAL_ERROR fatal_error=1
|
||||
#else
|
||||
#define SET_FATAL_ERROR
|
||||
#endif
|
||||
|
||||
void handler::print_error(int error, myf errflag)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
bool fatal_error= 0;
|
||||
#endif
|
||||
DBUG_ENTER("handler::print_error");
|
||||
DBUG_PRINT("enter",("error: %d",error));
|
||||
|
||||
@ -2662,6 +2672,13 @@ void handler::print_error(int error, myf errflag)
|
||||
case HA_ERR_KEY_NOT_FOUND:
|
||||
case HA_ERR_NO_ACTIVE_RECORD:
|
||||
case HA_ERR_END_OF_FILE:
|
||||
/*
|
||||
This errors is not not normally fatal (for example for reads). However
|
||||
if you get it during an update or delete, then its fatal.
|
||||
As the user is calling print_error() (which is not done on read), we
|
||||
assume something when wrong with the update or delete.
|
||||
*/
|
||||
SET_FATAL_ERROR;
|
||||
textno=ER_KEY_NOT_FOUND;
|
||||
break;
|
||||
case HA_ERR_WRONG_MRG_TABLE_DEF:
|
||||
@ -2713,21 +2730,26 @@ void handler::print_error(int error, myf errflag)
|
||||
textno=ER_DUP_UNIQUE;
|
||||
break;
|
||||
case HA_ERR_RECORD_CHANGED:
|
||||
SET_FATAL_ERROR;
|
||||
textno=ER_CHECKREAD;
|
||||
break;
|
||||
case HA_ERR_CRASHED:
|
||||
SET_FATAL_ERROR;
|
||||
textno=ER_NOT_KEYFILE;
|
||||
break;
|
||||
case HA_ERR_WRONG_IN_RECORD:
|
||||
SET_FATAL_ERROR;
|
||||
textno= ER_CRASHED_ON_USAGE;
|
||||
break;
|
||||
case HA_ERR_CRASHED_ON_USAGE:
|
||||
SET_FATAL_ERROR;
|
||||
textno=ER_CRASHED_ON_USAGE;
|
||||
break;
|
||||
case HA_ERR_NOT_A_TABLE:
|
||||
textno= error;
|
||||
break;
|
||||
case HA_ERR_CRASHED_ON_REPAIR:
|
||||
SET_FATAL_ERROR;
|
||||
textno=ER_CRASHED_ON_REPAIR;
|
||||
break;
|
||||
case HA_ERR_OUT_OF_MEM:
|
||||
@ -2826,7 +2848,10 @@ void handler::print_error(int error, myf errflag)
|
||||
if (temporary)
|
||||
my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine);
|
||||
else
|
||||
{
|
||||
SET_FATAL_ERROR;
|
||||
my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine);
|
||||
}
|
||||
}
|
||||
else
|
||||
my_error(ER_GET_ERRNO,errflag,error);
|
||||
@ -2834,6 +2859,7 @@ void handler::print_error(int error, myf errflag)
|
||||
}
|
||||
}
|
||||
my_error(textno, errflag, table_share->table_name.str, error);
|
||||
DBUG_ASSERT(!fatal_error || !debug_assert_if_crashed_table);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
103
sql/lock.cc
103
sql/lock.cc
@ -211,7 +211,8 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
|
||||
for (;;)
|
||||
{
|
||||
if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
|
||||
&write_lock_used)))
|
||||
&write_lock_used)) ||
|
||||
! sql_lock->table_count)
|
||||
break;
|
||||
|
||||
if (global_read_lock && write_lock_used &&
|
||||
@ -257,8 +258,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
|
||||
|
||||
thd_proc_info(thd, "System lock");
|
||||
DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
|
||||
if (sql_lock->table_count && lock_external(thd, sql_lock->table,
|
||||
sql_lock->table_count))
|
||||
if (lock_external(thd, sql_lock->table, sql_lock->table_count))
|
||||
{
|
||||
/* Clear the lock type of all lock data to avoid reusage. */
|
||||
reset_lock_data(sql_lock);
|
||||
@ -279,8 +279,7 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
|
||||
thd->lock_id)];
|
||||
if (rc > 1) /* a timeout or a deadlock */
|
||||
{
|
||||
if (sql_lock->table_count)
|
||||
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
|
||||
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
|
||||
my_error(rc, MYF(0));
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
sql_lock= 0;
|
||||
@ -388,7 +387,7 @@ void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
|
||||
if (sql_lock->table_count)
|
||||
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
|
||||
if (sql_lock->lock_count)
|
||||
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count);
|
||||
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count, 0);
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
@ -418,25 +417,8 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
|
||||
uint i,found;
|
||||
DBUG_ENTER("mysql_unlock_read_tables");
|
||||
|
||||
/* Move all write locks first */
|
||||
THR_LOCK_DATA **lock=sql_lock->locks;
|
||||
for (i=found=0 ; i < sql_lock->lock_count ; i++)
|
||||
{
|
||||
if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
|
||||
{
|
||||
swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
|
||||
lock++;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
/* unlock the read locked tables */
|
||||
if (i != found)
|
||||
{
|
||||
thr_multi_unlock(lock,i-found);
|
||||
sql_lock->lock_count= found;
|
||||
}
|
||||
/* Call external lock for all tables to be unlocked */
|
||||
|
||||
/* Then do the same for the external locks */
|
||||
/* Move all write locked tables first */
|
||||
TABLE **table=sql_lock->table;
|
||||
for (i=found=0 ; i < sql_lock->table_count ; i++)
|
||||
@ -455,6 +437,27 @@ void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock)
|
||||
VOID(unlock_external(thd,table,i-found));
|
||||
sql_lock->table_count=found;
|
||||
}
|
||||
|
||||
/* Call thr_unlock() for all tables to be unlocked */
|
||||
|
||||
/* Move all write locks first */
|
||||
THR_LOCK_DATA **lock=sql_lock->locks;
|
||||
for (i=found=0 ; i < sql_lock->lock_count ; i++)
|
||||
{
|
||||
if (sql_lock->locks[i]->type >= TL_WRITE_ALLOW_READ)
|
||||
{
|
||||
swap_variables(THR_LOCK_DATA *, *lock, sql_lock->locks[i]);
|
||||
lock++;
|
||||
found++;
|
||||
}
|
||||
}
|
||||
/* unlock the read locked tables */
|
||||
if (i != found)
|
||||
{
|
||||
thr_multi_unlock(lock, i-found, 0);
|
||||
sql_lock->lock_count= found;
|
||||
}
|
||||
|
||||
/* Fix the lock positions in TABLE */
|
||||
table= sql_lock->table;
|
||||
found= 0;
|
||||
@ -582,8 +585,21 @@ void mysql_lock_abort(THD *thd, TABLE *table, bool upgrade_lock)
|
||||
if ((locked= get_lock_data(thd, &table, 1, GET_LOCK_UNLOCK,
|
||||
&write_lock_used)))
|
||||
{
|
||||
for (uint i=0; i < locked->lock_count; i++)
|
||||
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
|
||||
if (table->children_attached)
|
||||
{
|
||||
/*
|
||||
Don't abort locks for underlying tables just because merge table
|
||||
is deleted. Doing would cause anyone accessing these tables to
|
||||
spin in open_table/close_table forever until lock is released.
|
||||
*/
|
||||
thr_multi_unlock(locked->locks, locked->lock_count,
|
||||
THR_UNLOCK_UPDATE_STATUS);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint i=0; i < locked->lock_count; i++)
|
||||
thr_abort_locks(locked->locks[i]->lock, upgrade_lock);
|
||||
}
|
||||
my_free((uchar*) locked,MYF(0));
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
@ -624,21 +640,36 @@ bool mysql_lock_abort_for_thread(THD *thd, TABLE *table)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Merge two thr_lock:s
|
||||
mysql_lock_merge()
|
||||
|
||||
@param a Original locks
|
||||
@param b New locks
|
||||
|
||||
@retval New lock structure that contains a and b
|
||||
|
||||
@note
|
||||
a and b are freed with my_free()
|
||||
*/
|
||||
|
||||
MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
|
||||
{
|
||||
MYSQL_LOCK *sql_lock;
|
||||
TABLE **table, **end_table;
|
||||
DBUG_ENTER("mysql_lock_merge");
|
||||
DBUG_PRINT("enter", ("a->lock_count: %u b->lock_count: %u",
|
||||
a->lock_count, b->lock_count));
|
||||
|
||||
if (!(sql_lock= (MYSQL_LOCK*)
|
||||
my_malloc(sizeof(*sql_lock)+
|
||||
sizeof(THR_LOCK_DATA*)*(a->lock_count+b->lock_count)+
|
||||
sizeof(THR_LOCK_DATA*)*((a->lock_count+b->lock_count)*2) +
|
||||
sizeof(TABLE*)*(a->table_count+b->table_count),MYF(MY_WME))))
|
||||
DBUG_RETURN(0); // Fatal error
|
||||
sql_lock->lock_count=a->lock_count+b->lock_count;
|
||||
sql_lock->table_count=a->table_count+b->table_count;
|
||||
sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
|
||||
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count);
|
||||
sql_lock->table=(TABLE**) (sql_lock->locks+sql_lock->lock_count*2);
|
||||
memcpy(sql_lock->locks,a->locks,a->lock_count*sizeof(*a->locks));
|
||||
memcpy(sql_lock->locks+a->lock_count,b->locks,
|
||||
b->lock_count*sizeof(*b->locks));
|
||||
@ -659,6 +690,18 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
|
||||
(*table)->lock_data_start+= a->lock_count;
|
||||
}
|
||||
|
||||
/*
|
||||
Ensure that locks of the same tables share same data structures if we
|
||||
reopen a table that is already open. This can happen for example with
|
||||
MERGE tables.
|
||||
*/
|
||||
|
||||
/* Copy the lock data array. thr_merge_lock() reorders its content */
|
||||
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
|
||||
sql_lock->lock_count * sizeof(*sql_lock->locks));
|
||||
thr_merge_locks(sql_lock->locks + sql_lock->lock_count,
|
||||
a->lock_count, b->lock_count);
|
||||
|
||||
/* Delete old, not needed locks */
|
||||
my_free((uchar*) a,MYF(0));
|
||||
my_free((uchar*) b,MYF(0));
|
||||
@ -832,7 +875,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
||||
|
||||
/*
|
||||
Allocating twice the number of pointers for lock data for use in
|
||||
thr_mulit_lock(). This function reorders the lock data, but cannot
|
||||
thr_multi_lock(). This function reorders the lock data, but cannot
|
||||
update the table values. So the second part of the array is copied
|
||||
from the first part immediately before calling thr_multi_lock().
|
||||
*/
|
||||
@ -1062,11 +1105,13 @@ int lock_table_name(THD *thd, TABLE_LIST *table_list, bool check_in_use)
|
||||
|
||||
void unlock_table_name(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
DBUG_ENTER("unlock_table_name");
|
||||
if (table_list->table)
|
||||
{
|
||||
hash_delete(&open_cache, (uchar*) table_list->table);
|
||||
broadcast_refresh();
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2018,7 +2018,7 @@ extern ulong slave_exec_mode_options;
|
||||
extern my_bool opt_readonly, lower_case_file_system;
|
||||
extern my_bool opt_userstat_running;
|
||||
extern my_bool opt_enable_named_pipe, opt_sync_frm, opt_allow_suspicious_udfs;
|
||||
extern my_bool opt_secure_auth;
|
||||
extern my_bool opt_secure_auth, debug_assert_if_crashed_table;
|
||||
extern char* opt_secure_file_priv;
|
||||
extern my_bool opt_log_slow_admin_statements, opt_log_slow_slave_statements;
|
||||
extern my_bool sp_automatic_privileges, opt_noacl;
|
||||
|
@ -467,7 +467,7 @@ static pthread_cond_t COND_thread_cache, COND_flush_thread_cache;
|
||||
/* Global variables */
|
||||
|
||||
bool opt_update_log, opt_bin_log, opt_ignore_builtin_innodb= 0;
|
||||
my_bool opt_log, opt_slow_log;
|
||||
my_bool opt_log, opt_slow_log, debug_assert_if_crashed_table;
|
||||
my_bool opt_userstat_running;
|
||||
ulong log_output_options;
|
||||
my_bool opt_log_queries_not_using_indexes= 0;
|
||||
@ -6011,7 +6011,7 @@ enum options_mysqld
|
||||
OPT_SECURE_FILE_PRIV,
|
||||
OPT_MIN_EXAMINED_ROW_LIMIT,
|
||||
OPT_LOG_SLOW_SLAVE_STATEMENTS,
|
||||
OPT_DEBUG_CRC, OPT_DEBUG_ON, OPT_OLD_MODE,
|
||||
OPT_DEBUG_CRC, OPT_DEBUG_ON, OPT_DEBUG_ASSERT_IF_CRASHED_TABLE, OPT_OLD_MODE,
|
||||
OPT_TEST_IGNORE_WRONG_OPTIONS, OPT_TEST_RESTART,
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
OPT_DEBUG_SYNC_TIMEOUT,
|
||||
@ -6181,6 +6181,10 @@ struct my_option my_long_options[] =
|
||||
0, GET_ULONG, REQUIRED_ARG, 0, 0, ~(ulong) 0L, 0, 0, 0},
|
||||
{"debug-flush", OPT_DEBUG_FLUSH, "Default debug log with flush after write",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"debug-assert-if-crashed-table", OPT_DEBUG_ASSERT_IF_CRASHED_TABLE,
|
||||
"Do an assert in handler::print_error() if we get a crashed table",
|
||||
&debug_assert_if_crashed_table, &debug_assert_if_crashed_table,
|
||||
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#endif
|
||||
{"default-character-set", OPT_DEFAULT_CHARACTER_SET_OLD,
|
||||
"Set the default character set (deprecated option, use --character-set-server instead).",
|
||||
|
@ -216,7 +216,7 @@ sql_create_definition_file(const LEX_STRING *dir, const LEX_STRING *file_name,
|
||||
File_option *param;
|
||||
DBUG_ENTER("sql_create_definition_file");
|
||||
DBUG_PRINT("enter", ("Dir: %s, file: %s, base 0x%lx",
|
||||
dir ? dir->str : "(null)",
|
||||
dir ? dir->str : "",
|
||||
file_name->str, (ulong) base));
|
||||
|
||||
if (dir)
|
||||
|
@ -4352,7 +4352,7 @@ bool sys_var_thd_dbug::update(THD *thd, set_var *var)
|
||||
|
||||
uchar *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
|
||||
{
|
||||
char buf[256];
|
||||
char buf[1024];
|
||||
if (type == OPT_GLOBAL)
|
||||
{
|
||||
DBUG_EXPLAIN_INITIAL(buf, sizeof(buf));
|
||||
|
@ -2045,6 +2045,8 @@ static void unlink_open_merge(THD *thd, TABLE *table, TABLE ***prev_pp)
|
||||
Remove parent from open_tables list and close it.
|
||||
This includes detaching and hence clearing parent references.
|
||||
*/
|
||||
DBUG_PRINT("info", ("Closing parent to '%s'.'%s'",
|
||||
table->s->db.str, table->s->table_name.str));
|
||||
close_thread_table(thd, prv_p);
|
||||
}
|
||||
}
|
||||
@ -3076,8 +3078,9 @@ bool reopen_table(TABLE *table)
|
||||
TABLE_LIST table_list;
|
||||
THD *thd= table->in_use;
|
||||
DBUG_ENTER("reopen_table");
|
||||
DBUG_PRINT("tcache", ("table: '%s'.'%s' 0x%lx", table->s->db.str,
|
||||
table->s->table_name.str, (long) table));
|
||||
DBUG_PRINT("tcache", ("table: '%s'.'%s' table: 0x%lx share: 0x%lx",
|
||||
table->s->db.str, table->s->table_name.str,
|
||||
(long) table, (long) table->s));
|
||||
|
||||
DBUG_ASSERT(table->s->ref_count == 0);
|
||||
DBUG_ASSERT(!table->sort.io_cache);
|
||||
@ -3364,7 +3367,8 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old)
|
||||
merge_table_found= TRUE;
|
||||
if (!tables || (!db_stat && reopen_table(table)))
|
||||
{
|
||||
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias);
|
||||
my_error(ER_CANT_REOPEN_TABLE, MYF(0),
|
||||
table->alias ? table->alias : table->s->table_name.str);
|
||||
/*
|
||||
If we could not allocate 'tables', we may close open tables
|
||||
here. If a MERGE table is affected, detach the children first.
|
||||
@ -3374,9 +3378,10 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old)
|
||||
that they cannot be moved into the unused_tables chain with
|
||||
these pointers set.
|
||||
*/
|
||||
if (table->child_l || table->parent)
|
||||
detach_merge_children(table, TRUE);
|
||||
VOID(hash_delete(&open_cache,(uchar*) table));
|
||||
unlink_open_table(thd, table, 0);
|
||||
/* Restart loop */
|
||||
prev= &thd->open_tables;
|
||||
next= *prev;
|
||||
error=1;
|
||||
}
|
||||
else
|
||||
@ -3411,7 +3416,7 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old)
|
||||
}
|
||||
DBUG_PRINT("tcache", ("open tables to lock: %u",
|
||||
(uint) (tables_ptr - tables)));
|
||||
if (tables != tables_ptr) // Should we get back old locks
|
||||
if (tables != tables_ptr) // Should we get back old locks
|
||||
{
|
||||
MYSQL_LOCK *lock;
|
||||
/*
|
||||
@ -3560,7 +3565,7 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
|
||||
char *key= table->s->table_cache_key.str;
|
||||
uint key_length= table->s->table_cache_key.length;
|
||||
|
||||
DBUG_PRINT("loop", ("table_name: %s", table->alias));
|
||||
DBUG_PRINT("loop", ("table_name: %s", table->alias ? table->alias : ""));
|
||||
HASH_SEARCH_STATE state;
|
||||
for (TABLE *search= (TABLE*) hash_first(&open_cache, (uchar*) key,
|
||||
key_length, &state);
|
||||
@ -3898,6 +3903,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list,
|
||||
int error;
|
||||
TABLE_SHARE *share;
|
||||
uint discover_retry_count= 0;
|
||||
bool locked_table;
|
||||
DBUG_ENTER("open_unireg_entry");
|
||||
|
||||
safe_mutex_assert_owner(&LOCK_open);
|
||||
@ -4018,8 +4024,10 @@ retry:
|
||||
}
|
||||
if (!entry->s || !entry->s->crashed)
|
||||
goto err;
|
||||
// Code below is for repairing a crashed file
|
||||
if ((error= lock_table_name(thd, table_list, TRUE)))
|
||||
|
||||
// Code below is for repairing a crashed file
|
||||
locked_table= table_list->table != 0;
|
||||
if (! locked_table && (error= lock_table_name(thd, table_list, TRUE)))
|
||||
{
|
||||
if (error < 0)
|
||||
goto err;
|
||||
@ -4053,12 +4061,13 @@ retry:
|
||||
else
|
||||
thd->clear_error(); // Clear error message
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
unlock_table_name(thd, table_list);
|
||||
if (!locked_table)
|
||||
unlock_table_name(thd, table_list);
|
||||
|
||||
if (error)
|
||||
goto err;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (Table_triggers_list::check_n_load(thd, share->db.str,
|
||||
share->table_name.str, entry, 0))
|
||||
@ -4286,7 +4295,6 @@ void detach_merge_children(TABLE *table, bool clear_refs)
|
||||
{
|
||||
TABLE_LIST *child_l;
|
||||
TABLE *parent= table->child_l ? table : table->parent;
|
||||
bool first_detach;
|
||||
DBUG_ENTER("detach_merge_children");
|
||||
/*
|
||||
Either table->child_l or table->parent must be set. Parent must have
|
||||
@ -4304,7 +4312,7 @@ void detach_merge_children(TABLE *table, bool clear_refs)
|
||||
children attached yet. Also this is called for every child and the
|
||||
parent from close_thread_tables().
|
||||
*/
|
||||
if ((first_detach= parent->children_attached))
|
||||
if (parent->children_attached)
|
||||
{
|
||||
VOID(parent->file->extra(HA_EXTRA_DETACH_CHILDREN));
|
||||
parent->children_attached= FALSE;
|
||||
@ -4316,38 +4324,50 @@ void detach_merge_children(TABLE *table, bool clear_refs)
|
||||
|
||||
if (clear_refs)
|
||||
{
|
||||
/* In any case clear the own parent reference. (***) */
|
||||
table->parent= NULL;
|
||||
if (table->parent)
|
||||
{
|
||||
/* In any case clear the own parent reference. (***) */
|
||||
table->parent= NULL;
|
||||
table->file->extra(HA_EXTRA_DETACH_CHILD);
|
||||
}
|
||||
|
||||
/*
|
||||
On the first detach, clear all references. If this table is the
|
||||
parent, we still may need to clear the child references. The first
|
||||
detach might not have done this.
|
||||
Clear all references. If this table is the parent, we still may
|
||||
need to clear the child references. The first detach might not
|
||||
have done this.
|
||||
*/
|
||||
if (first_detach || (table == parent))
|
||||
for (child_l= parent->child_l; ; child_l= child_l->next_global)
|
||||
{
|
||||
/* Clear TABLE references to force new assignment at next open. */
|
||||
for (child_l= parent->child_l; ; child_l= child_l->next_global)
|
||||
{
|
||||
/*
|
||||
Do not DBUG_ASSERT(child_l->table); open_tables might be
|
||||
incomplete.
|
||||
/*
|
||||
Do not DBUG_ASSERT(child_l->table); open_tables might be
|
||||
incomplete or we may have been called twice.
|
||||
|
||||
Clear the parent reference of the children only on the first
|
||||
detach. The children might already be closed. They will clear
|
||||
it themseves when this function is called for them with
|
||||
'clear_refs' true. See above "(***)".
|
||||
*/
|
||||
if (first_detach && child_l->table)
|
||||
Clear the parent reference of the children only on the first
|
||||
detach. The children might already be closed. They will clear
|
||||
it themselves when this function is called for them with
|
||||
'clear_refs' true. See above "(***)".
|
||||
*/
|
||||
if (child_l->table)
|
||||
{
|
||||
if (child_l->table->parent)
|
||||
{
|
||||
child_l->table->parent= NULL;
|
||||
if (child_l->table->db_stat)
|
||||
child_l->table->file->extra(HA_EXTRA_DETACH_CHILD);
|
||||
}
|
||||
/*
|
||||
Set alias to "" to ensure that table is not used if we are in
|
||||
LOCK TABLES
|
||||
*/
|
||||
((char*) child_l->table->alias)[0]= 0;
|
||||
|
||||
/* Clear the table reference to force new assignment at next open. */
|
||||
child_l->table= NULL;
|
||||
|
||||
/* Break when this was the last child. */
|
||||
if (&child_l->next_global == parent->child_last_l)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Break when this was the last child. */
|
||||
if (&child_l->next_global == parent->child_last_l)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -5144,9 +5164,11 @@ bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags)
|
||||
|
||||
static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
|
||||
{
|
||||
DBUG_ENTER("mark_real_tables_as_free_for_reuse");
|
||||
for (; table; table= table->next_global)
|
||||
if (!table->placeholder())
|
||||
table->table->query_id= 0;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
|
@ -327,7 +327,7 @@ const char *set_thd_proc_info(THD *thd, const char *info,
|
||||
|
||||
const char *old_info= thd->proc_info;
|
||||
DBUG_PRINT("proc_info", ("%s:%d %s", calling_file, calling_line,
|
||||
(info != NULL) ? info : "(null)"));
|
||||
(info != NULL) ? info : ""));
|
||||
#if defined(ENABLED_PROFILING) && defined(COMMUNITY_SERVER)
|
||||
thd->profiling.status_change(info, calling_function, calling_file, calling_line);
|
||||
#endif
|
||||
|
@ -8011,6 +8011,8 @@ bool parse_sql(THD *thd,
|
||||
Object_creation_ctx *creation_ctx)
|
||||
{
|
||||
bool mysql_parse_status;
|
||||
DBUG_ENTER("parse_sql");
|
||||
|
||||
DBUG_ASSERT(thd->m_parser_state == NULL);
|
||||
|
||||
/* Backup creation context. */
|
||||
@ -8044,7 +8046,7 @@ bool parse_sql(THD *thd,
|
||||
|
||||
/* That's it. */
|
||||
|
||||
return mysql_parse_status || thd->is_fatal_error;
|
||||
DBUG_RETURN(mysql_parse_status || thd->is_fatal_error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -498,9 +498,6 @@ bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
|
||||
thd->in_lock_tables= 1;
|
||||
if (reopen_tables(thd, 1, 1))
|
||||
{
|
||||
/* To be safe remove this table from the set of LOCKED TABLES */
|
||||
unlink_open_table(thd, tables->table, FALSE);
|
||||
|
||||
/*
|
||||
Ignore reopen_tables errors for now. It's better not leave master/slave
|
||||
in a inconsistent state.
|
||||
|
@ -227,7 +227,8 @@ my_bool _ma_bitmap_init(MARIA_SHARE *share, File file)
|
||||
The +1 is to add the bitmap page, as this doesn't have to be covered
|
||||
*/
|
||||
bitmap->pages_covered= aligned_bit_blocks * 16 + 1;
|
||||
bitmap->flush_all_requested= bitmap->non_flushable= 0;
|
||||
bitmap->flush_all_requested= 0;
|
||||
bitmap->non_flushable= 0;
|
||||
|
||||
/* Update size for bits */
|
||||
/* TODO; Make this dependent of the row size */
|
||||
@ -311,8 +312,8 @@ my_bool _ma_bitmap_flush(MARIA_SHARE *share)
|
||||
pthread_mutex_lock(&share->bitmap.bitmap_lock);
|
||||
if (share->bitmap.changed)
|
||||
{
|
||||
share->bitmap.changed= 0;
|
||||
res= write_changed_bitmap(share, &share->bitmap);
|
||||
share->bitmap.changed= 0;
|
||||
}
|
||||
pthread_mutex_unlock(&share->bitmap.bitmap_lock);
|
||||
}
|
||||
@ -355,7 +356,7 @@ my_bool _ma_bitmap_flush_all(MARIA_SHARE *share)
|
||||
pthread_mutex_lock(&bitmap->bitmap_lock);
|
||||
if (bitmap->changed || bitmap->changed_not_flushed)
|
||||
{
|
||||
bitmap->flush_all_requested= TRUE;
|
||||
bitmap->flush_all_requested++;
|
||||
#ifndef WRONG_BITMAP_FLUSH
|
||||
while (bitmap->non_flushable > 0)
|
||||
{
|
||||
@ -363,6 +364,7 @@ my_bool _ma_bitmap_flush_all(MARIA_SHARE *share)
|
||||
pthread_cond_wait(&bitmap->bitmap_cond, &bitmap->bitmap_lock);
|
||||
}
|
||||
#endif
|
||||
DBUG_ASSERT(bitmap->flush_all_requested == 1);
|
||||
/*
|
||||
Bitmap is in a flushable state: its contents in memory are reflected by
|
||||
log records (complete REDO-UNDO groups) and all bitmap pages are
|
||||
@ -391,7 +393,7 @@ my_bool _ma_bitmap_flush_all(MARIA_SHARE *share)
|
||||
PCFLUSH_PINNED_AND_ERROR)
|
||||
res= TRUE;
|
||||
bitmap->changed_not_flushed= FALSE;
|
||||
bitmap->flush_all_requested= FALSE;
|
||||
bitmap->flush_all_requested--;
|
||||
/*
|
||||
Some well-behaved threads may be waiting for flush_all_requested to
|
||||
become false, wake them up.
|
||||
@ -404,6 +406,70 @@ my_bool _ma_bitmap_flush_all(MARIA_SHARE *share)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief Lock bitmap from being used by another thread
|
||||
|
||||
@fn _ma_bitmap_lock()
|
||||
@param share Table's share
|
||||
|
||||
@notes
|
||||
This is a temporary solution for allowing someone to delete an inserted
|
||||
duplicate-key row while someone else is doing concurrent inserts.
|
||||
This is ok for now as duplicate key errors are not that common.
|
||||
|
||||
In the future we will add locks for row-pages to ensure two threads doesn't
|
||||
work at the same time on the same page.
|
||||
*/
|
||||
|
||||
void _ma_bitmap_lock(MARIA_SHARE *share)
|
||||
{
|
||||
MARIA_FILE_BITMAP *bitmap= &share->bitmap;
|
||||
DBUG_ENTER("_ma_bitmap_lock");
|
||||
|
||||
if (!share->now_transactional)
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
pthread_mutex_lock(&bitmap->bitmap_lock);
|
||||
bitmap->flush_all_requested++;
|
||||
while (bitmap->non_flushable)
|
||||
{
|
||||
DBUG_PRINT("info", ("waiting for bitmap to be flushable"));
|
||||
pthread_cond_wait(&bitmap->bitmap_cond, &bitmap->bitmap_lock);
|
||||
}
|
||||
/*
|
||||
Ensure that _ma_bitmap_flush_all() and _ma_bitmap_lock() are blocked.
|
||||
ma_bitmap_flushable() is blocked thanks to 'flush_all_requested'.
|
||||
*/
|
||||
bitmap->non_flushable= 1;
|
||||
pthread_mutex_unlock(&bitmap->bitmap_lock);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief Unlock bitmap after _ma_bitmap_lock()
|
||||
|
||||
@fn _ma_bitmap_unlock()
|
||||
@param share Table's share
|
||||
*/
|
||||
|
||||
void _ma_bitmap_unlock(MARIA_SHARE *share)
|
||||
{
|
||||
MARIA_FILE_BITMAP *bitmap= &share->bitmap;
|
||||
DBUG_ENTER("_ma_bitmap_unlock");
|
||||
|
||||
if (!share->now_transactional)
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_ASSERT(bitmap->flush_all_requested > 0 && bitmap->non_flushable == 1);
|
||||
|
||||
pthread_mutex_lock(&bitmap->bitmap_lock);
|
||||
bitmap->flush_all_requested--;
|
||||
bitmap->non_flushable= 0;
|
||||
pthread_mutex_unlock(&bitmap->bitmap_lock);
|
||||
pthread_cond_broadcast(&bitmap->bitmap_cond);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@brief Unpin all pinned bitmap pages
|
||||
|
||||
@ -633,11 +699,12 @@ static void _ma_print_bitmap_changes(MARIA_FILE_BITMAP *bitmap)
|
||||
{
|
||||
uchar *pos, *end, *org_pos;
|
||||
ulong page;
|
||||
DBUG_ENTER("_ma_print_bitmap_changes");
|
||||
|
||||
end= bitmap->map + bitmap->used_size;
|
||||
DBUG_LOCK_FILE;
|
||||
fprintf(DBUG_FILE,"\nBitmap page changes at page %lu\n",
|
||||
(ulong) bitmap->page);
|
||||
fprintf(DBUG_FILE,"\nBitmap page changes at page: %lu bitmap: 0x%lx\n",
|
||||
(ulong) bitmap->page, (long) bitmap->map);
|
||||
|
||||
page= (ulong) bitmap->page+1;
|
||||
for (pos= bitmap->map, org_pos= bitmap->map + bitmap->block_size ;
|
||||
@ -666,6 +733,7 @@ static void _ma_print_bitmap_changes(MARIA_FILE_BITMAP *bitmap)
|
||||
fputc('\n', DBUG_FILE);
|
||||
DBUG_UNLOCK_FILE;
|
||||
memcpy(bitmap->map + bitmap->block_size, bitmap->map, bitmap->block_size);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@ -877,6 +945,7 @@ static void fill_block(MARIA_FILE_BITMAP *bitmap,
|
||||
{
|
||||
uint page, offset, tmp;
|
||||
uchar *data;
|
||||
DBUG_ENTER("fill_block");
|
||||
|
||||
/* For each 6 bytes we have 6*8/3= 16 patterns */
|
||||
page= ((uint) (best_data - bitmap->map)) / 6 * 16 + best_pos;
|
||||
@ -902,6 +971,7 @@ static void fill_block(MARIA_FILE_BITMAP *bitmap,
|
||||
int2store(data, tmp);
|
||||
bitmap->changed= 1;
|
||||
DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
@ -1016,7 +1086,11 @@ static my_bool allocate_tail(MARIA_FILE_BITMAP *bitmap, uint size,
|
||||
DBUG_PRINT("enter", ("size: %u", size));
|
||||
|
||||
LINT_INIT(best_pos);
|
||||
DBUG_ASSERT(size <= MAX_TAIL_SIZE(bitmap->block_size));
|
||||
/*
|
||||
We have to add DIR_ENTRY_SIZE here as this is not part of the data size
|
||||
See call to allocate_tail() in find_tail().
|
||||
*/
|
||||
DBUG_ASSERT(size <= MAX_TAIL_SIZE(bitmap->block_size) + DIR_ENTRY_SIZE);
|
||||
|
||||
for (; data < end; data += 6)
|
||||
{
|
||||
@ -1510,6 +1584,8 @@ static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size,
|
||||
MARIA_BITMAP_BLOCK *block;
|
||||
uchar *data;
|
||||
uint offset, tmp, offset_page;
|
||||
DBUG_ENTER("use_head");
|
||||
|
||||
DBUG_ASSERT(page % bitmap->pages_covered);
|
||||
|
||||
block= dynamic_element(&info->bitmap_blocks, block_position,
|
||||
@ -1532,6 +1608,7 @@ static void use_head(MARIA_HA *info, pgcache_page_no_t page, uint size,
|
||||
int2store(data, tmp);
|
||||
bitmap->changed= 1;
|
||||
DBUG_EXECUTE("bitmap", _ma_print_bitmap_changes(bitmap););
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
|
@ -2823,6 +2823,10 @@ static my_bool write_block_record(MARIA_HA *info,
|
||||
data+= diff_length;
|
||||
head_length= share->base.min_block_length;
|
||||
}
|
||||
/*
|
||||
If this is a redo entry (ie, undo_lsn != LSN_ERROR) then we should have
|
||||
written exactly head_length bytes (same as original record).
|
||||
*/
|
||||
DBUG_ASSERT(undo_lsn == LSN_ERROR || head_length == row_pos->length);
|
||||
int2store(row_pos->dir + 2, head_length);
|
||||
/* update empty space at start of block */
|
||||
@ -3588,7 +3592,7 @@ my_bool _ma_write_abort_block_record(MARIA_HA *info)
|
||||
MARIA_SHARE *share= info->s;
|
||||
DBUG_ENTER("_ma_write_abort_block_record");
|
||||
|
||||
_ma_bitmap_flushable(info, 1);
|
||||
_ma_bitmap_lock(share); /* Lock bitmap from other insert threads */
|
||||
if (delete_head_or_tail(info,
|
||||
ma_recordpos_to_page(info->cur_row.lastpos),
|
||||
ma_recordpos_to_dir_entry(info->cur_row.lastpos), 1,
|
||||
@ -3626,7 +3630,7 @@ my_bool _ma_write_abort_block_record(MARIA_HA *info)
|
||||
&lsn, (void*) 0))
|
||||
res= 1;
|
||||
}
|
||||
_ma_bitmap_flushable(info, -1);
|
||||
_ma_bitmap_unlock(share);
|
||||
_ma_unpin_all_pages_and_finalize_row(info, lsn);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
@ -7161,6 +7165,7 @@ my_bool _ma_apply_undo_row_update(MARIA_HA *info, LSN undo_lsn,
|
||||
header+= HA_CHECKSUM_STORE_SIZE;
|
||||
}
|
||||
length_on_head_page= uint2korr(header);
|
||||
set_if_bigger(length_on_head_page, share->base.min_block_length);
|
||||
header+= 2;
|
||||
extent_count= pagerange_korr(header);
|
||||
header+= PAGERANGE_STORE_SIZE;
|
||||
|
@ -217,6 +217,8 @@ uint _ma_bitmap_get_page_bits(MARIA_HA *info, MARIA_FILE_BITMAP *bitmap,
|
||||
void _ma_bitmap_delete_all(MARIA_SHARE *share);
|
||||
int _ma_bitmap_create_first(MARIA_SHARE *share);
|
||||
void _ma_bitmap_flushable(MARIA_HA *info, int non_flushable_inc);
|
||||
void _ma_bitmap_lock(MARIA_SHARE *share);
|
||||
void _ma_bitmap_unlock(MARIA_SHARE *share);
|
||||
void _ma_bitmap_set_pagecache_callbacks(PAGECACHE_FILE *file,
|
||||
MARIA_SHARE *share);
|
||||
#ifndef DBUG_OFF
|
||||
@ -281,7 +283,8 @@ my_bool write_hook_for_commit(enum translog_record_type type,
|
||||
TRN *trn, MARIA_HA *tbl_info, LSN *lsn,
|
||||
void *hook_arg);
|
||||
void _ma_block_get_status(void *param, my_bool concurrent_insert);
|
||||
void _ma_block_get_status_no_versioning(void *param, my_bool concurrent_ins);
|
||||
my_bool _ma_block_start_trans(void* param);
|
||||
my_bool _ma_block_start_trans_no_versioning(void *param);
|
||||
void _ma_block_update_status(void *param);
|
||||
void _ma_block_restore_status(void *param);
|
||||
my_bool _ma_block_check_status(void *param);
|
||||
|
@ -137,6 +137,7 @@ void _ma_print_keydata(FILE *stream, register HA_KEYSEG *keyseg,
|
||||
key=end;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case HA_KEYTYPE_BIT:
|
||||
{
|
||||
uint i;
|
||||
@ -146,8 +147,6 @@ void _ma_print_keydata(FILE *stream, register HA_KEYSEG *keyseg,
|
||||
key= end;
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
case HA_KEYTYPE_VARTEXT1: /* VARCHAR and TEXT */
|
||||
case HA_KEYTYPE_VARTEXT2: /* VARCHAR and TEXT */
|
||||
case HA_KEYTYPE_VARBINARY1: /* VARBINARY and BLOB */
|
||||
|
@ -63,7 +63,7 @@ int maria_lock_database(MARIA_HA *info, int lock_type)
|
||||
{
|
||||
count= --share->w_locks;
|
||||
if (share->lock.update_status)
|
||||
(*share->lock.update_status)(info);
|
||||
_ma_update_status_with_lock(info);
|
||||
}
|
||||
--share->tot_locks;
|
||||
if (info->lock_type == F_WRLCK && !share->w_locks)
|
||||
|
@ -874,8 +874,8 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
|
||||
share->have_versioning= 1;
|
||||
share->row_is_visible= _ma_row_visible_transactional_table;
|
||||
share->lock.get_status= _ma_block_get_status;
|
||||
share->lock.update_status= _ma_block_update_status;
|
||||
share->lock.check_status= _ma_block_check_status;
|
||||
share->lock.start_trans= _ma_block_start_trans;
|
||||
/*
|
||||
We can for the moment only allow multiple concurrent inserts
|
||||
only if there is no auto-increment key. To lift this restriction
|
||||
@ -903,7 +903,7 @@ MARIA_HA *maria_open(const char *name, int mode, uint open_flags)
|
||||
else if (share->now_transactional)
|
||||
{
|
||||
DBUG_ASSERT(share->data_file_type == BLOCK_RECORD);
|
||||
share->lock.get_status= _ma_block_get_status_no_versioning;
|
||||
share->lock.start_trans= _ma_block_start_trans_no_versioning;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -335,6 +335,25 @@ void _ma_update_status(void* param)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Same as ma_update_status() but take a lock in the table lock, to protect
|
||||
against someone calling ma_get_status() from thr_lock() at the same time.
|
||||
*/
|
||||
|
||||
void _ma_update_status_with_lock(MARIA_HA *info)
|
||||
{
|
||||
my_bool locked= 0;
|
||||
if (info->state == &info->state_save)
|
||||
{
|
||||
locked= 1;
|
||||
pthread_mutex_lock(&info->s->lock.mutex);
|
||||
}
|
||||
(*info->s->lock.update_status)(info);
|
||||
if (locked)
|
||||
pthread_mutex_unlock(&info->s->lock.mutex);
|
||||
}
|
||||
|
||||
|
||||
void _ma_restore_status(void *param)
|
||||
{
|
||||
MARIA_HA *info= (MARIA_HA*) param;
|
||||
@ -585,7 +604,13 @@ void _ma_block_get_status(void* param, my_bool concurrent_insert)
|
||||
{
|
||||
DBUG_ASSERT(info->lock.type != TL_WRITE_CONCURRENT_INSERT);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
my_bool _ma_block_start_trans(void* param)
|
||||
{
|
||||
MARIA_HA *info=(MARIA_HA*) param;
|
||||
if (info->s->lock_key_trees)
|
||||
{
|
||||
/*
|
||||
@ -593,24 +618,22 @@ void _ma_block_get_status(void* param, my_bool concurrent_insert)
|
||||
out of memory conditions)
|
||||
TODO: Fix this by having one extra state pre-allocated
|
||||
*/
|
||||
(void) _ma_setup_live_state(info);
|
||||
return _ma_setup_live_state(info);
|
||||
}
|
||||
else
|
||||
|
||||
/*
|
||||
Info->trn is set if this table is already handled and we are
|
||||
called from maria_versioning()
|
||||
*/
|
||||
if (info->s->base.born_transactional && !info->trn)
|
||||
{
|
||||
/*
|
||||
Info->trn is set if this table is already handled and we are
|
||||
called from maria_versioning()
|
||||
Assume for now that this doesn't fail (It can only fail in
|
||||
out of memory conditions)
|
||||
*/
|
||||
if (info->s->base.born_transactional && !info->trn)
|
||||
{
|
||||
/*
|
||||
Assume for now that this doesn't fail (It can only fail in
|
||||
out of memory conditions)
|
||||
*/
|
||||
(void) maria_create_trn_hook(info);
|
||||
}
|
||||
return maria_create_trn_hook(info) != 0;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@ -639,13 +662,10 @@ my_bool _ma_block_check_status(void *param __attribute__((unused)))
|
||||
|
||||
/* Get status when transactional but not versioned */
|
||||
|
||||
void _ma_block_get_status_no_versioning(void* param,
|
||||
my_bool concurrent_insert
|
||||
__attribute__((unused)))
|
||||
my_bool _ma_block_start_trans_no_versioning(void* param)
|
||||
{
|
||||
MARIA_HA *info=(MARIA_HA*) param;
|
||||
DBUG_ENTER("_ma_block_get_status_no_version");
|
||||
DBUG_PRINT("enter", ("concurrent_insert %d", concurrent_insert));
|
||||
DBUG_ASSERT(info->s->base.born_transactional);
|
||||
|
||||
info->state->changed= 0; /* from _ma_reset_update_flag() */
|
||||
@ -655,9 +675,9 @@ void _ma_block_get_status_no_versioning(void* param,
|
||||
Assume for now that this doesn't fail (It can only fail in
|
||||
out of memory conditions)
|
||||
*/
|
||||
(void) maria_create_trn_hook(info);
|
||||
DBUG_RETURN(maria_create_trn_hook(info));
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -62,6 +62,7 @@ MARIA_STATE_HISTORY *_ma_remove_not_visible_states(MARIA_STATE_HISTORY
|
||||
void _ma_reset_state(MARIA_HA *info);
|
||||
void _ma_get_status(void* param, my_bool concurrent_insert);
|
||||
void _ma_update_status(void* param);
|
||||
void _ma_update_status_with_lock(MARIA_HA *info);
|
||||
void _ma_restore_status(void *param);
|
||||
void _ma_copy_status(void* to, void *from);
|
||||
void _ma_reset_update_flag(void *param, my_bool concurrent_insert);
|
||||
|
@ -678,7 +678,6 @@ static int w_search(register MARIA_HA *info, uint32 comp_flag, MARIA_KEY *key,
|
||||
}
|
||||
else /* not HA_FULLTEXT, normal HA_NOSAME key */
|
||||
{
|
||||
DBUG_PRINT("warning", ("Duplicate key"));
|
||||
/*
|
||||
TODO
|
||||
When the index will support true versioning - with multiple
|
||||
@ -696,6 +695,12 @@ static int w_search(register MARIA_HA *info, uint32 comp_flag, MARIA_KEY *key,
|
||||
info->dup_key_trid= _ma_trid_from_key(&tmp_key);
|
||||
info->dup_key_pos= dup_key_pos;
|
||||
my_errno= HA_ERR_FOUND_DUPP_KEY;
|
||||
DBUG_PRINT("warning",
|
||||
("Duplicate key. dup_key_trid: %lu pos %lu visible: %d",
|
||||
(ulong) info->dup_key_trid,
|
||||
(ulong) info->dup_key_pos,
|
||||
info->trn ? trnman_can_read_from(info->trn,
|
||||
info->dup_key_trid) : 2));
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
@ -246,7 +246,7 @@ typedef struct st_maria_file_bitmap
|
||||
uint used_size; /* Size of bitmap head that is not 0 */
|
||||
my_bool changed; /* 1 if page needs to be written */
|
||||
my_bool changed_not_flushed; /* 1 if some bitmap is not flushed */
|
||||
my_bool flush_all_requested; /**< If _ma_bitmap_flush_all waiting */
|
||||
uint flush_all_requested; /**< If _ma_bitmap_flush_all waiting */
|
||||
uint non_flushable; /**< 0 if bitmap and log are in sync */
|
||||
PAGECACHE_FILE file; /* datafile where bitmap is stored */
|
||||
|
||||
|
@ -1338,7 +1338,7 @@ int chk_data_link(HA_CHECK *param, MI_INFO *info, my_bool extend)
|
||||
if (splits != info->s->state.split)
|
||||
{
|
||||
mi_check_print_warning(param,
|
||||
"Found %10s key parts. Should be: %s",
|
||||
"Found %10s parts. Should be: %s",
|
||||
llstr(splits,llbuff),
|
||||
llstr(info->s->state.split,llbuff2));
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg,
|
||||
key=end;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
case HA_KEYTYPE_BIT:
|
||||
{
|
||||
uint i;
|
||||
@ -140,8 +141,6 @@ void _mi_print_key(FILE *stream, register HA_KEYSEG *keyseg,
|
||||
key= end;
|
||||
break;
|
||||
}
|
||||
|
||||
#endif
|
||||
case HA_KEYTYPE_VARTEXT1: /* VARCHAR and TEXT */
|
||||
case HA_KEYTYPE_VARTEXT2: /* VARCHAR and TEXT */
|
||||
case HA_KEYTYPE_VARBINARY1: /* VARBINARY and BLOB */
|
||||
|
@ -392,6 +392,11 @@ int mi_extra(MI_INFO *info, enum ha_extra_function function, void *extra_arg)
|
||||
share->is_log_table= TRUE;
|
||||
pthread_mutex_unlock(&share->intern_lock);
|
||||
break;
|
||||
case HA_EXTRA_DETACH_CHILD: /* When used with MERGE tables */
|
||||
info->open_flag&= ~HA_OPEN_MERGE_TABLE;
|
||||
info->lock.priority&= ~THR_LOCK_MERGE_PRIV;
|
||||
break;
|
||||
|
||||
case HA_EXTRA_KEY_CACHE:
|
||||
case HA_EXTRA_NO_KEY_CACHE:
|
||||
default:
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include "ftdefs.h"
|
||||
|
||||
static void mi_update_status_with_lock(MI_INFO *info);
|
||||
|
||||
/* lock table by F_UNLCK, F_RDLCK or F_WRLCK */
|
||||
|
||||
int mi_lock_database(MI_INFO *info, int lock_type)
|
||||
@ -62,7 +64,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
|
||||
else
|
||||
{
|
||||
count= --share->w_locks;
|
||||
mi_update_status(info);
|
||||
mi_update_status_with_lock(info);
|
||||
}
|
||||
--share->tot_locks;
|
||||
if (info->lock_type == F_WRLCK && !share->w_locks &&
|
||||
@ -246,7 +248,7 @@ int mi_lock_database(MI_INFO *info, int lock_type)
|
||||
a crash on windows if the table is renamed and
|
||||
later on referenced by the merge table.
|
||||
*/
|
||||
if( info->owned_by_merge && (info->s)->kfile < 0 )
|
||||
if ((info->open_flag & HA_OPEN_MERGE_TABLE) && (info->s)->kfile < 0)
|
||||
{
|
||||
error = HA_ERR_NO_SUCH_TABLE;
|
||||
}
|
||||
@ -275,9 +277,11 @@ void mi_get_status(void* param, my_bool concurrent_insert)
|
||||
{
|
||||
MI_INFO *info=(MI_INFO*) param;
|
||||
DBUG_ENTER("mi_get_status");
|
||||
DBUG_PRINT("info",("key_file: %ld data_file: %ld concurrent_insert: %d",
|
||||
(long) info->s->state.state.key_file_length,
|
||||
(long) info->s->state.state.data_file_length,
|
||||
DBUG_PRINT("info",("name: %s key_file: %lu data_file: %lu rows: %lu concurrent_insert: %d",
|
||||
info->s->index_file_name,
|
||||
(ulong) info->s->state.state.key_file_length,
|
||||
(ulong) info->s->state.state.data_file_length,
|
||||
(ulong) info->s->state.state.records,
|
||||
concurrent_insert));
|
||||
#ifndef DBUG_OFF
|
||||
if (info->state->key_file_length > info->s->state.state.key_file_length ||
|
||||
@ -308,9 +312,11 @@ void mi_update_status(void* param)
|
||||
if (info->state == &info->save_state)
|
||||
{
|
||||
#ifndef DBUG_OFF
|
||||
DBUG_PRINT("info",("updating status: key_file: %ld data_file: %ld",
|
||||
(long) info->state->key_file_length,
|
||||
(long) info->state->data_file_length));
|
||||
DBUG_PRINT("info",
|
||||
("updating status: key_file: %lu data_file: %lu rows: %lu",
|
||||
(ulong) info->state->key_file_length,
|
||||
(ulong) info->state->data_file_length,
|
||||
(ulong) info->state->records));
|
||||
if (info->state->key_file_length < info->s->state.state.key_file_length ||
|
||||
info->state->data_file_length < info->s->state.state.data_file_length)
|
||||
DBUG_PRINT("warning",("old info: key_file: %ld data_file: %ld",
|
||||
@ -344,6 +350,24 @@ void mi_update_status(void* param)
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
Same as mi_update_status() but take a lock in the table lock, to protect
|
||||
against someone calling mi_get_status() from thr_lock() at the same time.
|
||||
*/
|
||||
|
||||
static void mi_update_status_with_lock(MI_INFO *info)
|
||||
{
|
||||
my_bool locked= 0;
|
||||
if (info->state == &info->save_state)
|
||||
{
|
||||
locked= 1;
|
||||
pthread_mutex_lock(&info->s->lock.mutex);
|
||||
}
|
||||
mi_update_status(info);
|
||||
if (locked)
|
||||
pthread_mutex_unlock(&info->s->lock.mutex);
|
||||
}
|
||||
|
||||
|
||||
void mi_restore_status(void *param)
|
||||
{
|
||||
@ -409,6 +433,32 @@ my_bool mi_check_status(void *param)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Fix status for thr_lock_merge()
|
||||
|
||||
@param org_table
|
||||
@param new_table that should point on org_lock. new_table is 0
|
||||
in case this is the first occurence of the table in the lock
|
||||
structure.
|
||||
*/
|
||||
|
||||
void mi_fix_status(MI_INFO *org_table, MI_INFO *new_table)
|
||||
{
|
||||
DBUG_ENTER("mi_fix_status");
|
||||
if (!new_table)
|
||||
{
|
||||
/* First in group. Set state as in mi_get_status() */
|
||||
org_table->state= &org_table->save_state;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set new_table to use state from org_table (first lock of this table) */
|
||||
new_table->state= org_table->state;
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
** functions to read / write the state
|
||||
****************************************************************************/
|
||||
|
@ -119,7 +119,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
|
||||
dflt_key_cache);
|
||||
|
||||
DBUG_EXECUTE_IF("myisam_pretend_crashed_table_on_open",
|
||||
if (strstr(name, "/t1"))
|
||||
if (strstr(name, "/crashed"))
|
||||
{
|
||||
my_errno= HA_ERR_CRASHED;
|
||||
goto err;
|
||||
@ -556,6 +556,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
|
||||
share->lock.update_status=mi_update_status;
|
||||
share->lock.restore_status= mi_restore_status;
|
||||
share->lock.check_status=mi_check_status;
|
||||
share->lock.fix_status= (void (*)(void *, void *)) mi_fix_status;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -606,6 +607,7 @@ MI_INFO *mi_open(const char *name, int mode, uint open_flags)
|
||||
info.s=share;
|
||||
info.lastpos= HA_OFFSET_ERROR;
|
||||
info.update= (short) (HA_STATE_NEXT_FOUND+HA_STATE_PREV_FOUND);
|
||||
info.open_flag= open_flags;
|
||||
info.opt_flag=READ_CHECK_USED;
|
||||
info.this_unique= (ulong) info.dfile; /* Uniq number in process */
|
||||
if (share->data_file_type == COMPRESSED_RECORD)
|
||||
|
@ -276,7 +276,9 @@ struct st_myisam_info
|
||||
*/
|
||||
ulong packed_length, blob_length; /* Length of found, packed record */
|
||||
int dfile; /* The datafile */
|
||||
uint open_flag; /* Parameters for open */
|
||||
uint opt_flag; /* Optim. for space/speed */
|
||||
uint once_flags; /* For MYISAMMRG */
|
||||
uint update; /* If file changed since open */
|
||||
int lastinx; /* Last used index */
|
||||
uint lastkey_length; /* Length of key in lastkey */
|
||||
@ -302,10 +304,6 @@ struct st_myisam_info
|
||||
my_bool page_changed;
|
||||
/* If info->buff has to be reread for rnext */
|
||||
my_bool buff_used;
|
||||
my_bool once_flags; /* For MYISAMMRG */
|
||||
#ifdef __WIN__
|
||||
my_bool owned_by_merge; /* This MyISAM table is part of a merge union */
|
||||
#endif
|
||||
#ifdef THREAD
|
||||
THR_LOCK_DATA lock;
|
||||
#endif
|
||||
@ -714,6 +712,7 @@ void mi_update_status(void *param);
|
||||
void mi_restore_status(void *param);
|
||||
void mi_copy_status(void *to, void *from);
|
||||
my_bool mi_check_status(void *param);
|
||||
void mi_fix_status(MI_INFO *org_table, MI_INFO *new_table);
|
||||
void mi_disable_non_unique_index(MI_INFO *info, ha_rows rows);
|
||||
|
||||
extern MI_INFO *test_if_reopen(char *filename);
|
||||
|
@ -86,8 +86,6 @@
|
||||
|
||||
On parent open the storage engine structures are allocated and initialized.
|
||||
They stay with the open table until its final close.
|
||||
|
||||
|
||||
*/
|
||||
|
||||
#ifdef USE_PRAGMA_IMPLEMENTATION
|
||||
@ -1070,6 +1068,8 @@ THR_LOCK_DATA **ha_myisammrg::store_lock(THD *thd,
|
||||
open_table != file->end_table ;
|
||||
open_table++)
|
||||
{
|
||||
open_table->table->lock.priority|= THR_LOCK_MERGE_PRIV;
|
||||
|
||||
*(to++)= &open_table->table->lock;
|
||||
if (lock_type != TL_IGNORE && open_table->table->lock.type == TL_UNLOCK)
|
||||
open_table->table->lock.type=lock_type;
|
||||
|
@ -27,15 +27,8 @@ int myrg_lock_database(MYRG_INFO *info, int lock_type)
|
||||
error=0;
|
||||
for (file=info->open_tables ; file != info->end_table ; file++)
|
||||
{
|
||||
#ifdef __WIN__
|
||||
/*
|
||||
Make sure this table is marked as owned by a merge table.
|
||||
The semaphore is never released as long as table remains
|
||||
in memory. This should be refactored into a more generic
|
||||
approach (observer pattern)
|
||||
*/
|
||||
(file->table)->owned_by_merge = TRUE;
|
||||
#endif
|
||||
DBUG_ASSERT(file->table->open_flag & HA_OPEN_MERGE_TABLE);
|
||||
|
||||
if ((new_error=mi_lock_database(file->table,lock_type)))
|
||||
{
|
||||
error=new_error;
|
||||
|
@ -27,8 +27,9 @@
|
||||
if handle_locking is 0 then exit with error if some table is locked
|
||||
if handle_locking is 1 then wait if table is locked
|
||||
|
||||
NOTE: This function is not used in the MySQL server. It is for
|
||||
MERGE use independent from MySQL. Currently there is some code
|
||||
NOTE: This function is only used in the MySQL server when a
|
||||
table is cloned. It is also used for usage of MERGE
|
||||
independent from MySQL. Currently there is some code
|
||||
duplication between myrg_open() and myrg_parent_open() +
|
||||
myrg_attach_children(). Please duplicate changes in these
|
||||
functions or make common sub-functions.
|
||||
@ -93,7 +94,8 @@ MYRG_INFO *myrg_open(const char *name, int mode, int handle_locking)
|
||||
}
|
||||
else
|
||||
fn_format(buff, buff, "", "", 0);
|
||||
if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0))))
|
||||
if (!(isam=mi_open(buff,mode,(handle_locking?HA_OPEN_WAIT_IF_LOCKED:0) |
|
||||
HA_OPEN_MERGE_TABLE)))
|
||||
{
|
||||
if (handle_locking & HA_OPEN_FOR_REPAIR)
|
||||
{
|
||||
@ -430,6 +432,8 @@ int myrg_attach_children(MYRG_INFO *m_info, int handle_locking,
|
||||
m_info->open_tables[child_nr].table= myisam;
|
||||
m_info->open_tables[child_nr].file_offset= (my_off_t) file_offset;
|
||||
file_offset+= myisam->state->data_file_length;
|
||||
/* Mark as MERGE table */
|
||||
myisam->open_flag|= HA_OPEN_MERGE_TABLE;
|
||||
|
||||
/* Check table definition match. */
|
||||
if (m_info->reclength != myisam->s->base.reclength)
|
||||
|
@ -1116,7 +1116,7 @@ init_again:
|
||||
if (shm_info->buf_pool_backup.LRU_old)
|
||||
shm_info->buf_pool_backup.LRU_old =
|
||||
(buf_page_t*)((byte*)(shm_info->buf_pool_backup.LRU_old)
|
||||
+ (((void*)shm_info->buf_pool_backup.LRU_old > previous_frame_address)
|
||||
+ (((byte*)shm_info->buf_pool_backup.LRU_old > previous_frame_address)
|
||||
? logi_offset : blocks_offset));
|
||||
|
||||
UT_LIST_OFFSET(unzip_LRU, buf_block_t, shm_info->buf_pool_backup.unzip_LRU,
|
||||
|
@ -2265,7 +2265,7 @@ buf_LRU_file_restore(void)
|
||||
ulint req = 0;
|
||||
ibool terminated = FALSE;
|
||||
ibool ret = FALSE;
|
||||
dump_record_t* records;
|
||||
dump_record_t* records= 0;
|
||||
ulint size;
|
||||
ulint size_high;
|
||||
ulint length;
|
||||
|
Loading…
x
Reference in New Issue
Block a user