Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
M
MariaDB
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
nexedi
MariaDB
Commits
00164ea4
Commit
00164ea4
authored
Oct 13, 2018
by
Kristian Nielsen
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'gtid_table_garbage_rows_10.3' into 10.3
parents
2fd77064
3eb2c466
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
167 additions
and
21 deletions
+167
-21
mysql-test/suite/rpl/r/rpl_parallel_optimistic.result
mysql-test/suite/rpl/r/rpl_parallel_optimistic.result
+8
-0
mysql-test/suite/rpl/t/rpl_parallel_optimistic.test
mysql-test/suite/rpl/t/rpl_parallel_optimistic.test
+24
-0
sql/log_event.cc
sql/log_event.cc
+3
-3
sql/rpl_gtid.cc
sql/rpl_gtid.cc
+41
-17
sql/rpl_gtid.h
sql/rpl_gtid.h
+1
-1
sql/rpl_rli.cc
sql/rpl_rli.cc
+79
-0
sql/rpl_rli.h
sql/rpl_rli.h
+11
-0
No files found.
mysql-test/suite/rpl/r/rpl_parallel_optimistic.result
View file @
00164ea4
...
...
@@ -648,4 +648,12 @@ SET GLOBAL slave_parallel_threads=@old_parallel_threads;
include/start_slave.inc
connection server_1;
DROP TABLE t1, t2, t3;
include/save_master_gtid.inc
connection server_2;
include/sync_with_master_gtid.inc
Check that no more than the expected last four GTIDs are in mysql.gtid_slave_pos
select count(4) <= 4 from mysql.gtid_slave_pos order by domain_id, sub_id;
count(4) <= 4
1
connection server_1;
include/rpl_end.inc
mysql-test/suite/rpl/t/rpl_parallel_optimistic.test
View file @
00164ea4
...
...
@@ -553,5 +553,29 @@ SET GLOBAL slave_parallel_threads=@old_parallel_threads;
--
connection
server_1
DROP
TABLE
t1
,
t2
,
t3
;
--
source
include
/
save_master_gtid
.
inc
--
connection
server_2
--
source
include
/
sync_with_master_gtid
.
inc
# Check for left-over rows in table mysql.gtid_slave_pos (MDEV-12147).
#
# There was a bug when a transaction got a conflict and was rolled back. It
# might have also handled deletion of some old rows, and these deletions would
# then also be rolled back. And since the deletes were never re-tried, old no
# longer needed rows would accumulate in the table without limit.
#
# The earlier part of this test file have plenty of transactions being rolled
# back. But the last DROP TABLE statement runs on its own and should never
# conflict, thus at this point the mysql.gtid_slave_pos table should be clean.
#
# To support @@gtid_pos_auto_engines, when a row is inserted in the table, it
# is associated with the engine of the table at insertion time, and it will
# only be deleted during record_gtid from a table of the same engine. Since we
# alter the table from MyISAM to InnoDB at the start of this test, we should
# end up with 4 rows: two left-over from when the table was MyISAM, and two
# left-over from the InnoDB part.
--
echo
Check
that
no
more
than
the
expected
last
four
GTIDs
are
in
mysql
.
gtid_slave_pos
select
count
(
4
)
<=
4
from
mysql
.
gtid_slave_pos
order
by
domain_id
,
sub_id
;
--
connection
server_1
--
source
include
/
rpl_end
.
inc
sql/log_event.cc
View file @
00164ea4
...
...
@@ -5565,7 +5565,7 @@ int Query_log_event::do_apply_event(rpl_group_info *rgi,
gtid
=
rgi
->
current_gtid
;
if
(
unlikely
(
rpl_global_gtid_slave_state
->
record_gtid
(
thd
,
&
gtid
,
sub_id
,
true
,
false
,
rgi
,
false
,
&
hton
)))
{
int
errcode
=
thd
->
get_stmt_da
()
->
sql_errno
();
...
...
@@ -8362,7 +8362,7 @@ Gtid_list_log_event::do_apply_event(rpl_group_info *rgi)
{
if
((
ret
=
rpl_global_gtid_slave_state
->
record_gtid
(
thd
,
&
list
[
i
],
sub_id_list
[
i
],
false
,
false
,
&
hton
)))
NULL
,
false
,
&
hton
)))
return
ret
;
rpl_global_gtid_slave_state
->
update_state_hash
(
sub_id_list
[
i
],
&
list
[
i
],
hton
,
NULL
);
...
...
@@ -8899,7 +8899,7 @@ int Xid_log_event::do_apply_event(rpl_group_info *rgi)
rgi
->
gtid_pending
=
false
;
gtid
=
rgi
->
current_gtid
;
err
=
rpl_global_gtid_slave_state
->
record_gtid
(
thd
,
&
gtid
,
sub_id
,
true
,
err
=
rpl_global_gtid_slave_state
->
record_gtid
(
thd
,
&
gtid
,
sub_id
,
rgi
,
false
,
&
hton
);
if
(
unlikely
(
err
))
{
...
...
sql/rpl_gtid.cc
View file @
00164ea4
...
...
@@ -79,7 +79,7 @@ rpl_slave_state::record_and_update_gtid(THD *thd, rpl_group_info *rgi)
rgi
->
gtid_pending
=
false
;
if
(
rgi
->
gtid_ignore_duplicate_state
!=
rpl_group_info
::
GTID_DUPLICATE_IGNORE
)
{
if
(
record_gtid
(
thd
,
&
rgi
->
current_gtid
,
sub_id
,
false
,
false
,
&
hton
))
if
(
record_gtid
(
thd
,
&
rgi
->
current_gtid
,
sub_id
,
NULL
,
false
,
&
hton
))
DBUG_RETURN
(
1
);
update_state_hash
(
sub_id
,
&
rgi
->
current_gtid
,
hton
,
rgi
);
}
...
...
@@ -331,6 +331,8 @@ rpl_slave_state::update(uint32 domain_id, uint32 server_id, uint64 sub_id,
}
}
rgi
->
gtid_ignore_duplicate_state
=
rpl_group_info
::
GTID_DUPLICATE_NULL
;
rgi
->
pending_gtid_deletes_clear
();
}
if
(
!
(
list_elem
=
(
list_element
*
)
my_malloc
(
sizeof
(
*
list_elem
),
MYF
(
MY_WME
))))
...
...
@@ -381,15 +383,24 @@ int
rpl_slave_state
::
put_back_list
(
uint32
domain_id
,
list_element
*
list
)
{
element
*
e
;
int
err
=
0
;
mysql_mutex_lock
(
&
LOCK_slave_state
);
if
(
!
(
e
=
(
element
*
)
my_hash_search
(
&
hash
,
(
const
uchar
*
)
&
domain_id
,
0
)))
return
1
;
{
err
=
1
;
goto
end
;
}
while
(
list
)
{
list_element
*
next
=
list
->
next
;
e
->
add
(
list
);
list
=
next
;
}
return
0
;
end:
mysql_mutex_unlock
(
&
LOCK_slave_state
);
return
err
;
}
...
...
@@ -559,12 +570,12 @@ rpl_slave_state::select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename)
/*
Write a gtid to the replication slave state table.
Do it as part of the transaction, to get slave crash safety, or as a separate
transaction if !in_transaction (eg. MyISAM or DDL).
gtid The global transaction id for this event group.
sub_id Value allocated within the sub_id when the event group was
read (sub_id must be consistent with commit order in master binlog).
rgi rpl_group_info context, if we are recording the gtid transactionally
as part of replicating a transactional event. NULL if called from
outside of a replicated transaction.
Note that caller must later ensure that the new gtid and sub_id is inserted
into the appropriate HASH element with rpl_slave_state.add(), so that it can
...
...
@@ -572,7 +583,7 @@ rpl_slave_state::select_gtid_pos_table(THD *thd, LEX_CSTRING *out_tablename)
*/
int
rpl_slave_state
::
record_gtid
(
THD
*
thd
,
const
rpl_gtid
*
gtid
,
uint64
sub_id
,
bool
in_transaction
,
bool
in_statement
,
rpl_group_info
*
rgi
,
bool
in_statement
,
void
**
out_hton
)
{
TABLE_LIST
tlist
;
...
...
@@ -671,7 +682,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
thd
->
wsrep_ignore_table
=
true
;
#endif
if
(
!
in_transaction
)
if
(
!
rgi
)
{
DBUG_PRINT
(
"info"
,
(
"resetting OPTION_BEGIN"
));
thd
->
variables
.
option_bits
&=
...
...
@@ -776,7 +787,8 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
table
->
file
->
print_error
(
err
,
MYF
(
0
));
goto
end
;
}
while
(
delete_list
)
cur
=
delete_list
;
while
(
cur
)
{
uchar
key_buffer
[
4
+
8
];
...
...
@@ -786,9 +798,9 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
/* `break' does not work inside DBUG_EXECUTE_IF */
goto
dbug_break
;
});
next
=
delete_list
->
next
;
next
=
cur
->
next
;
table
->
field
[
1
]
->
store
(
delete_list
->
sub_id
,
true
);
table
->
field
[
1
]
->
store
(
cur
->
sub_id
,
true
);
/* domain_id is already set in table->record[0] from write_row() above. */
key_copy
(
key_buffer
,
table
->
record
[
0
],
&
table
->
key_info
[
0
],
0
,
false
);
if
(
table
->
file
->
ha_index_read_map
(
table
->
record
[
1
],
key_buffer
,
...
...
@@ -802,8 +814,7 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
not want to endlessly error on the same element in case of table
corruption or such.
*/
my_free
(
delete_list
);
delete_list
=
next
;
cur
=
next
;
if
(
err
)
break
;
}
...
...
@@ -826,18 +837,31 @@ IF_DBUG(dbug_break:, )
*/
if
(
delete_list
)
{
mysql_mutex_lock
(
&
LOCK_slave_state
);
put_back_list
(
gtid
->
domain_id
,
delete_list
);
mysql_mutex_unlock
(
&
LOCK_slave_state
)
;
delete_list
=
0
;
}
ha_rollback_trans
(
thd
,
FALSE
);
}
close_thread_tables
(
thd
);
if
(
in_transaction
)
if
(
rgi
)
{
thd
->
mdl_context
.
release_statement_locks
();
/*
Save the list of old gtid entries we deleted. If this transaction
fails later for some reason and is rolled back, the deletion of those
entries will be rolled back as well, and we will need to put them back
on the to-be-deleted list so we can re-do the deletion. Otherwise
redundant rows in mysql.gtid_slave_pos may accumulate if transactions
are rolled back and retried after record_gtid().
*/
rgi
->
pending_gtid_deletes_save
(
gtid
->
domain_id
,
delete_list
);
}
else
{
thd
->
mdl_context
.
release_transactional_locks
();
rpl_group_info
::
pending_gtid_deletes_free
(
delete_list
);
}
}
thd
->
lex
->
restore_backup_query_tables_list
(
&
lex_backup
);
thd
->
variables
.
option_bits
=
thd_saved_option
;
...
...
@@ -1221,7 +1245,7 @@ rpl_slave_state::load(THD *thd, const char *state_from_master, size_t len,
if
(
gtid_parser_helper
(
&
state_from_master
,
end
,
&
gtid
)
||
!
(
sub_id
=
next_sub_id
(
gtid
.
domain_id
))
||
record_gtid
(
thd
,
&
gtid
,
sub_id
,
false
,
in_statement
,
&
hton
)
||
record_gtid
(
thd
,
&
gtid
,
sub_id
,
NULL
,
in_statement
,
&
hton
)
||
update
(
gtid
.
domain_id
,
gtid
.
server_id
,
sub_id
,
gtid
.
seq_no
,
hton
,
NULL
))
return
1
;
if
(
state_from_master
==
end
)
...
...
sql/rpl_gtid.h
View file @
00164ea4
...
...
@@ -233,7 +233,7 @@ struct rpl_slave_state
int
truncate_state_table
(
THD
*
thd
);
void
select_gtid_pos_table
(
THD
*
thd
,
LEX_CSTRING
*
out_tablename
);
int
record_gtid
(
THD
*
thd
,
const
rpl_gtid
*
gtid
,
uint64
sub_id
,
bool
in_transaction
,
bool
in_statement
,
void
**
out_hton
);
rpl_group_info
*
rgi
,
bool
in_statement
,
void
**
out_hton
);
uint64
next_sub_id
(
uint32
domain_id
);
int
iterate
(
int
(
*
cb
)(
rpl_gtid
*
,
void
*
),
void
*
data
,
rpl_gtid
*
extra_gtids
,
uint32
num_extra
,
...
...
sql/rpl_rli.cc
View file @
00164ea4
...
...
@@ -2086,6 +2086,7 @@ rpl_group_info::reinit(Relay_log_info *rli)
long_find_row_note_printed
=
false
;
did_mark_start_commit
=
false
;
gtid_ev_flags2
=
0
;
pending_gtid_delete_list
=
NULL
;
last_master_timestamp
=
0
;
gtid_ignore_duplicate_state
=
GTID_DUPLICATE_NULL
;
speculation
=
SPECULATE_NO
;
...
...
@@ -2216,6 +2217,12 @@ void rpl_group_info::cleanup_context(THD *thd, bool error)
erroneously update the GTID position.
*/
gtid_pending
=
false
;
/*
Rollback will have undone any deletions of old rows we might have made
in mysql.gtid_slave_pos. Put those rows back on the list to be deleted.
*/
pending_gtid_deletes_put_back
();
}
m_table_map
.
clear_tables
();
slave_close_thread_tables
(
thd
);
...
...
@@ -2441,6 +2448,78 @@ rpl_group_info::unmark_start_commit()
}
/*
When record_gtid() has deleted any old rows from the table
mysql.gtid_slave_pos as part of a replicated transaction, save the list of
rows deleted here.
If later the transaction fails (eg. optimistic parallel replication), the
deletes will be undone when the transaction is rolled back. Then we can
put back the list of rows into the rpl_global_gtid_slave_state, so that
we can re-do the deletes and avoid accumulating old rows in the table.
*/
void
rpl_group_info
::
pending_gtid_deletes_save
(
uint32
domain_id
,
rpl_slave_state
::
list_element
*
list
)
{
/*
We should never get to a state where we try to save a new pending list of
gtid deletes while we still have an old one. But make sure we handle it
anyway just in case, so we avoid leaving stray entries in the
mysql.gtid_slave_pos table.
*/
DBUG_ASSERT
(
!
pending_gtid_delete_list
);
if
(
unlikely
(
pending_gtid_delete_list
))
pending_gtid_deletes_put_back
();
pending_gtid_delete_list
=
list
;
pending_gtid_delete_list_domain
=
domain_id
;
}
/*
Take the list recorded by pending_gtid_deletes_save() and put it back into
rpl_global_gtid_slave_state. This is needed if deletion of the rows was
rolled back due to transaction failure.
*/
void
rpl_group_info
::
pending_gtid_deletes_put_back
()
{
if
(
pending_gtid_delete_list
)
{
rpl_global_gtid_slave_state
->
put_back_list
(
pending_gtid_delete_list_domain
,
pending_gtid_delete_list
);
pending_gtid_delete_list
=
NULL
;
}
}
/*
Free the list recorded by pending_gtid_deletes_save(). Done when the deletes
in the list have been permanently committed.
*/
void
rpl_group_info
::
pending_gtid_deletes_clear
()
{
pending_gtid_deletes_free
(
pending_gtid_delete_list
);
pending_gtid_delete_list
=
NULL
;
}
void
rpl_group_info
::
pending_gtid_deletes_free
(
rpl_slave_state
::
list_element
*
list
)
{
rpl_slave_state
::
list_element
*
next
;
while
(
list
)
{
next
=
list
->
next
;
my_free
(
list
);
list
=
next
;
}
}
rpl_sql_thread_info
::
rpl_sql_thread_info
(
Rpl_filter
*
filter
)
:
rpl_filter
(
filter
)
{
...
...
sql/rpl_rli.h
View file @
00164ea4
...
...
@@ -757,6 +757,11 @@ struct rpl_group_info
/* Needs room for "Gtid D-S-N\x00". */
char
gtid_info_buf
[
5
+
10
+
1
+
10
+
1
+
20
+
1
];
/* List of not yet committed deletions in mysql.gtid_slave_pos. */
rpl_slave_state
::
list_element
*
pending_gtid_delete_list
;
/* Domain associated with pending_gtid_delete_list. */
uint32
pending_gtid_delete_list_domain
;
/*
The timestamp, from the master, of the commit event.
Used to do delayed update of rli->last_master_timestamp, for getting
...
...
@@ -898,6 +903,12 @@ struct rpl_group_info
char
*
gtid_info
();
void
unmark_start_commit
();
static
void
pending_gtid_deletes_free
(
rpl_slave_state
::
list_element
*
list
);
void
pending_gtid_deletes_save
(
uint32
domain_id
,
rpl_slave_state
::
list_element
*
list
);
void
pending_gtid_deletes_put_back
();
void
pending_gtid_deletes_clear
();
longlong
get_row_stmt_start_timestamp
()
{
return
row_stmt_start_timestamp
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment