summaryrefslogtreecommitdiff
path: root/sql/rpl_gtid.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/rpl_gtid.cc')
-rw-r--r--sql/rpl_gtid.cc150
1 files changed, 118 insertions, 32 deletions
diff --git a/sql/rpl_gtid.cc b/sql/rpl_gtid.cc
index b34b890060b..d5e9380296e 100644
--- a/sql/rpl_gtid.cc
+++ b/sql/rpl_gtid.cc
@@ -180,6 +180,22 @@ rpl_slave_state::get_element(uint32 domain_id)
int
+rpl_slave_state::put_back_list(uint32 domain_id, list_element *list)
+{
+ element *e;
+ if (!(e= (element *)my_hash_search(&hash, (const uchar *)&domain_id, 0)))
+ return 1;
+ while (list)
+ {
+ list_element *next= list->next;
+ e->add(list);
+ list= next;
+ }
+ return 0;
+}
+
+
+int
rpl_slave_state::truncate_state_table(THD *thd)
{
TABLE_LIST tlist;
@@ -330,7 +346,10 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
table->field[3]->store(gtid->seq_no, true);
DBUG_EXECUTE_IF("inject_crash_before_write_rpl_slave_state", DBUG_SUICIDE(););
if ((err= table->file->ha_write_row(table->record[0])))
- goto end;
+ {
+ table->file->print_error(err, MYF(0));
+ goto end;
+ }
lock();
if ((elem= get_element(gtid->domain_id)) == NULL)
@@ -351,23 +370,42 @@ rpl_slave_state::record_gtid(THD *thd, const rpl_gtid *gtid, uint64 sub_id,
bitmap_set_bit(table->read_set, table->field[1]->field_index);
if ((err= table->file->ha_index_init(0, 0)))
+ {
+ table->file->print_error(err, MYF(0));
goto end;
+ }
while (elist)
{
uchar key_buffer[4+8];
+ DBUG_EXECUTE_IF("gtid_slave_pos_simulate_failed_delete",
+ { err= ENOENT;
+ table->file->print_error(err, MYF(0));
+ /* `break' does not work in DBUG_EXECUTE_IF */
+ goto dbug_break; });
+
next= elist->next;
table->field[1]->store(elist->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 ((err= table->file->ha_index_read_map(table->record[1], key_buffer,
- HA_WHOLE_KEY, HA_READ_KEY_EXACT)) ||
- (err= table->file->ha_delete_row(table->record[1])))
- break;
+ if (table->file->ha_index_read_map(table->record[1], key_buffer,
+ HA_WHOLE_KEY, HA_READ_KEY_EXACT))
+ /* We cannot find the row, assume it is already deleted. */
+ ;
+ else if ((err= table->file->ha_delete_row(table->record[1])))
+ table->file->print_error(err, MYF(0));
+ /*
+ In case of error, we still discard the element from the list. We do
+ not want to endlessly error on the same element in case of table
+ corruption or such.
+ */
my_free(elist);
elist= next;
+ if (err)
+ break;
}
+IF_DBUG(dbug_break:, )
table->file->ha_index_end();
if(!err && opt_bin_log &&
@@ -382,9 +420,16 @@ end:
if (err)
{
/*
- ToDo: If error, we need to put any remaining elist back into the HASH so
- we can do another delete attempt later.
+ If error, we need to put any remaining elist back into the HASH so we
+ can do another delete attempt later.
*/
+ if (elist)
+ {
+ lock();
+ put_back_list(gtid->domain_id, elist);
+ unlock();
+ }
+
ha_rollback_trans(thd, FALSE);
close_thread_tables(thd);
}
@@ -437,26 +482,10 @@ rpl_slave_state_tostring_helper(String *dest, const rpl_gtid *gtid, bool *first)
}
-/*
- Prepare the current slave state as a string, suitable for sending to the
- master to request to receive binlog events starting from that GTID state.
-
- The state consists of the most recently applied GTID for each domain_id,
- ie. the one with the highest sub_id within each domain_id.
-
- Optinally, extra_gtids is a list of GTIDs from the binlog. This is used when
- a server was previously a master and now needs to connect to a new master as
- a slave. For each domain_id, if the GTID in the binlog was logged with our
- own server_id _and_ has a higher seq_no than what is in the slave state,
- then this should be used as the position to start replicating at. This
- allows to promote a slave as new master, and connect the old master as a
- slave with MASTER_GTID_POS=AUTO.
-*/
-
int
-rpl_slave_state::tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra)
+rpl_slave_state::iterate(int (*cb)(rpl_gtid *, void *), void *data,
+ rpl_gtid *extra_gtids, uint32 num_extra)
{
- bool first= true;
uint32 i;
HASH gtid_hash;
uchar *rec;
@@ -510,7 +539,7 @@ rpl_slave_state::tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra)
}
}
- if (rpl_slave_state_tostring_helper(dest, &best_gtid, &first))
+ if ((res= (*cb)(&best_gtid, data)))
{
unlock();
goto err;
@@ -523,7 +552,7 @@ rpl_slave_state::tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra)
for (i= 0; i < gtid_hash.records; ++i)
{
gtid= (rpl_gtid *)my_hash_element(&gtid_hash, i);
- if (rpl_slave_state_tostring_helper(dest, gtid, &first))
+ if ((res= (*cb)(gtid, data)))
goto err;
}
@@ -536,6 +565,44 @@ err:
}
+struct rpl_slave_state_tostring_data {
+ String *dest;
+ bool first;
+};
+static int
+rpl_slave_state_tostring_cb(rpl_gtid *gtid, void *data)
+{
+ rpl_slave_state_tostring_data *p= (rpl_slave_state_tostring_data *)data;
+ return rpl_slave_state_tostring_helper(p->dest, gtid, &p->first);
+}
+
+
+/*
+ Prepare the current slave state as a string, suitable for sending to the
+ master to request to receive binlog events starting from that GTID state.
+
+ The state consists of the most recently applied GTID for each domain_id,
+ ie. the one with the highest sub_id within each domain_id.
+
+ Optinally, extra_gtids is a list of GTIDs from the binlog. This is used when
+ a server was previously a master and now needs to connect to a new master as
+ a slave. For each domain_id, if the GTID in the binlog was logged with our
+ own server_id _and_ has a higher seq_no than what is in the slave state,
+ then this should be used as the position to start replicating at. This
+ allows to promote a slave as new master, and connect the old master as a
+ slave with MASTER_GTID_POS=AUTO.
+*/
+int
+rpl_slave_state::tostring(String *dest, rpl_gtid *extra_gtids, uint32 num_extra)
+{
+ struct rpl_slave_state_tostring_data data;
+ data.first= true;
+ data.dest= dest;
+
+ return iterate(rpl_slave_state_tostring_cb, &data, extra_gtids, num_extra);
+}
+
+
/*
Lookup a domain_id in the current replication slave state.
@@ -581,9 +648,6 @@ rpl_slave_state::domain_to_gtid(uint32 domain_id, rpl_gtid *out_gtid)
Parse a GTID at the start of a string, and update the pointer to point
at the first character after the parsed GTID.
- GTID can be in short form with domain_id=0 implied, SERVERID-SEQNO.
- Or long form, DOMAINID-SERVERID-SEQNO.
-
Returns 0 on ok, non-zero on parse error.
*/
static int
@@ -1172,7 +1236,7 @@ slave_connection_state::load(char *slave_request, size_t len)
rpl_gtid *gtid;
const rpl_gtid *gtid2;
- my_hash_reset(&hash);
+ reset();
p= slave_request;
end= slave_request + len;
if (p == end)
@@ -1225,7 +1289,7 @@ slave_connection_state::load(const rpl_gtid *gtid_list, uint32 count)
{
uint32 i;
- my_hash_reset(&hash);
+ reset();
for (i= 0; i < count; ++i)
if (update(&gtid_list[i]))
return 1;
@@ -1233,6 +1297,28 @@ slave_connection_state::load(const rpl_gtid *gtid_list, uint32 count)
}
+static int
+slave_connection_state_load_cb(rpl_gtid *gtid, void *data)
+{
+ slave_connection_state *state= (slave_connection_state *)data;
+ return state->update(gtid);
+}
+
+
+/*
+ Same as rpl_slave_state::tostring(), but populates a slave_connection_state
+ instead.
+*/
+int
+slave_connection_state::load(rpl_slave_state *state,
+ rpl_gtid *extra_gtids, uint32 num_extra)
+{
+ reset();
+ return state->iterate(slave_connection_state_load_cb, this,
+ extra_gtids, num_extra);
+}
+
+
rpl_gtid *
slave_connection_state::find(uint32 domain_id)
{