YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftware
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/* The hash implementation comes from calc_hashnr() in mysys/hash.c. */ while (length--)
{
nr ^= (((nr & 63)+nr2)*((unsignedint) (unsignedchar) *key++))+ (nr << 8);
nr2 += 3;
} return((unsignedint) nr);
}
/* insert the binlog position in the active transaction list. */
strncpy(ins_node->log_name, log_file_name, FN_REFLEN-1);
ins_node->log_name[FN_REFLEN-1] = 0; /* make sure it ends properly */
ins_node->log_pos = log_file_pos;
ins_node->thd= thd_to_wait;
ins_node->thd_valid= false;
if (!m_trx_front)
{ /* The list is empty. */
m_trx_front = m_trx_rear = ins_node;
} else
{ int cmp = compare(ins_node, m_trx_rear); if (cmp > 0)
{ /* Compare with the tail first. If the transaction happens later in *binlog,thenmakeitthenewtail.
*/
m_trx_rear->next = ins_node;
m_trx_rear = ins_node;
} else
{ /* Otherwise, it is an error because the transaction should hold the *mysql_bin_log.LOCK_logwhenappendingevents.
*/
sql_print_error("%s: binlog write out-of-order, tail (%s, %lu), " "new node (%s, %lu)", "Active_tranx:insert_tranx_node",
m_trx_rear->log_name, (ulong)m_trx_rear->log_pos,
ins_node->log_name, (ulong)ins_node->log_pos);
result = -1; goto l_end;
}
}
int Repl_semi_sync_master::init_object()
{ int result= 0;
m_init_done = true;
/* References to the parameter works after set_options(). */
set_wait_timeout(rpl_semi_sync_master_timeout);
set_trace_level(rpl_semi_sync_master_trace_level);
set_wait_point(rpl_semi_sync_master_wait_point);
/* Mutex initialization can only be done after MY_INIT(). */
mysql_mutex_init(key_LOCK_rpl_semi_sync_master_enabled,
&LOCK_rpl_semi_sync_master_enabled, MY_MUTEX_INIT_FAST);
mysql_mutex_init(key_LOCK_binlog,
&LOCK_binlog, MY_MUTEX_INIT_FAST);
mysql_cond_init(key_COND_binlog_send,
&COND_binlog_send, NULL);
if (rpl_semi_sync_master_enabled)
{
result = enable_master(); if (!result)
result= ack_receiver.start(); /* Start the ACK thread. */
} else
disable_master();
return result;
}
int Repl_semi_sync_master::enable_master()
{ int result = 0;
/* Must have the lock when we do enable of disable. */
lock();
if (!get_master_enabled())
{
m_active_tranxs= new Active_tranx(&LOCK_binlog, &COND_binlog_send, m_trace_level); if (m_active_tranxs != NULL)
{
m_commit_file_name_inited = false;
m_reply_file_name_inited = false;
m_wait_file_name_inited = false;
set_master_enabled(true);
m_state = true;
sql_print_information("Semi-sync replication enabled on the master.");
} else
{
sql_print_error("Cannot allocate memory to enable semi-sync on the master.");
result = -1;
}
}
unlock();
return result;
}
void Repl_semi_sync_master::disable_master()
{ /* Must have the lock when we do enable of disable. */
lock();
if (get_master_enabled())
{ /* Switch off the semi-sync first so that waiting transaction will be *wakenup.
*/
switch_off();
/* This is the real check inside the mutex. */ if (!get_master_enabled()) goto l_end;
if (!is_on()) /* We check to see whether we can switch semi-sync ON. */
try_switch_on(server_id, log_file_name, log_file_pos);
/* The position should increase monotonically, if there is only one *threadsendingthebinlogtotheslave. *Inreality,toimprovethetransactionavailability,weallowmultiple *syncreplicationslaves.So,ifanyoneofthemgetthetransaction, *thetransactionsessioninthemastercanmoveforward.
*/ if (m_reply_file_name_inited)
{
cmp = Active_tranx::compare(log_file_name, log_file_pos,
m_reply_file_name, m_reply_file_pos);
/* If the requested position is behind the sending binlog position, *wouldnotadjustsendingbinlogposition. *Webasedontheassumptionthattherearemultiplesemi-syncslave, *andatleastoneofthemshouldbeuptodate. *Ifallsemi-syncslavesarebehind,atleastinitially,themaster *canfindthesituationafterthewaitingtimeout.Afterthat,some *slavesshouldcatchupquickly.
*/ if (cmp < 0)
{ /* If the position is behind, do not copy it. */
need_copy_send_pos = false;
}
}
/* Remove all active transaction nodes before this point. */
DBUG_ASSERT(m_active_tranxs != NULL);
m_active_tranxs->clear_active_tranx_nodes(log_file_name, log_file_pos,
signal_waiting_transaction); if (m_active_tranxs->is_empty())
m_wait_file_name_inited= false;
int Repl_semi_sync_master::dump_start(THD* thd, constchar *log_file,
my_off_t log_pos)
{ if (!thd->semi_sync_slave) return0;
if (ack_receiver.add_slave(thd))
{
sql_print_error("Failed to register slave to semi-sync ACK receiver " "thread. Turning off semisync");
thd->semi_sync_slave= 0; return1;
}
DEBUG_SYNC(thd, "rpl_semisync_master_commit_trx_before_lock"); /* Acquire the mutex. */
lock();
/* This must be called after acquired the lock */
THD_ENTER_COND(thd, &thd->COND_wakeup_ready, &LOCK_binlog,
&stage_waiting_for_semi_sync_ack_from_slave, &old_stage);
/* This is the real check inside the mutex. */ if (!get_master_enabled() || !is_on()) goto l_end;
while (is_on() && !(aborted= thd_killed(thd)))
{ /* We have to check these again as things may have changed */ if (!rpl_semi_sync_master_clients && !rpl_semi_sync_master_wait_no_slave)
{
aborted= 1; break;
}
if (m_reply_file_name_inited)
{ int cmp = Active_tranx::compare(m_reply_file_name, m_reply_file_pos,
trx_wait_binlog_name,
trx_wait_binlog_pos); if (cmp >= 0)
{ /* We have already sent the relevant binlog to the slave: no need to *waithere.
*/
DBUG_PRINT("semisync", ("%s: Binlog reply is ahead (%s, %lu),", "Repl_semi_sync_master::commit_trx",
m_reply_file_name,
(ulong)m_reply_file_pos));
success= 1; break;
}
}
Tranx_node *tranx_entry=
m_active_tranxs->is_thd_waiter(thd, trx_wait_binlog_name,
trx_wait_binlog_pos); /* In between the binlogging of this transaction and this wait, it is *possiblethatourentryinActive_tranxwasremoved(i.e.if *semi-syncwasswitchedoffandon).Itisalsopossiblethatthe *eventwasalreadysenttoaslave;however,wedon'tknowif *semi-syncwasonoroffatthattime,soanACKmaynevercome.So *skipthewait.Notethatrpl_semi_sync_master_request_ackswas *alreadyincrementedinreport_binlog_update(),sotokeep *rpl_semi_sync_master_yes/no_txconsistentwithit,wecheckfora *semi-syncrestart_after_checkingthereplystate.
*/ if (unlikely(!tranx_entry))
{
DBUG_EXECUTE_IF( "semisync_log_skip_trx_wait",
sql_print_information( "Skipping semi-sync wait for transaction at pos %s, %lu. This " "should be because semi-sync turned off and on during the " "lifetime of this transaction.", trx_wait_binlog_name, static_cast<unsignedlong>(trx_wait_binlog_pos)););
/* The only known reason for a missing entry at this point is if *semi-syncwasturnedoffthenon,soondebugbuilds,wetrack *thenumberoftimessemi-syncturnedoffatbinlogging,andcompare
* to the current value. */
DBUG_ASSERT(rpl_semi_sync_master_off_times >
thd->expected_semi_sync_offs);
/* Let us update the info about the minimum binlog position of waiting *threads.
*/ if (m_wait_file_name_inited)
{ int cmp = Active_tranx::compare(trx_wait_binlog_name,
trx_wait_binlog_pos,
m_wait_file_name, m_wait_file_pos); if (cmp <= 0)
{ /* This thd has a lower position, let's update the minimum info. */
strmake_buf(m_wait_file_name, trx_wait_binlog_name);
m_wait_file_pos = trx_wait_binlog_pos;
/* In semi-synchronous replication, we wait until the binlog-dump *threadhasreceivedthereplyontherelevantbinlogsegmentfromthe *replicationslave. * *Letussuspendthisthreadtowaitonthecondition; *whenreplicationhasprogressedfarenough,wewillrelease *thesewaitingthreads.
*/
rpl_semi_sync_master_wait_sessions++;
DBUG_PRINT("semisync", ("%s: wait %lu ms for binlog sent (%s, %lu)", "Repl_semi_sync_master::commit_trx",
m_wait_timeout,
m_wait_file_name, (ulong)m_wait_file_pos));
if (wait_result != 0)
{ /* This is a real wait timeout. */
sql_print_warning("Timeout waiting for reply of binlog (file: %s, pos:" " %lu), last semi-sync at file %s, position %lu.",
trx_wait_binlog_name, (ulong)trx_wait_binlog_pos,
(m_reply_file_name[0] == '\0') ? "(none)" :
m_reply_file_name, (ulong)m_reply_file_pos);
rpl_semi_sync_master_wait_timeouts++;
/* switch semi-sync off */
switch_off();
} else
{ int wait_time;
wait_time = get_wait_time(start_ts); if (wait_time < 0)
{
DBUG_PRINT("semisync", ("Replication semi-sync getWaitTime fail at " "wait position (%s, %lu)",
trx_wait_binlog_name,
(ulong)trx_wait_binlog_pos));
rpl_semi_sync_master_timefunc_fails++;
} else
{
rpl_semi_sync_master_trx_wait_num++;
rpl_semi_sync_master_trx_wait_time += wait_time;
/* If the current sending event's position is larger than or equal to the *'largest'committransactionbinlogposition,theslaveisalready *catchingupnowandwecanswitchsemi-synconhere. *Ifm_commit_file_name_initedindicatestherearenorecenttransactions, *wecanenablesemi-syncimmediately.
*/ if (m_commit_file_name_inited)
{ int cmp = Active_tranx::compare(log_file_name, log_file_pos,
m_commit_file_name, m_commit_file_pos);
semi_sync_on = (cmp >= 0);
} else
{
semi_sync_on = true;
}
if (semi_sync_on)
{ /* Switch semi-sync replication on. */
m_state = true;
sql_print_information("Semi-sync replication switched ON with slave (server_id: %d) " "at (%s, %lu)",
server_id, log_file_name,
(ulong)log_file_pos);
}
DBUG_RETURN(0);
}
int Repl_semi_sync_master::reserve_sync_header(String* packet)
{
DBUG_ENTER("Repl_semi_sync_master::reserve_sync_header");
/* If the semi-sync master is not enabled, or the slave is not a semi-sync *target,donotrequestrepliesfromtheslave.
*/ if (!get_master_enabled() || !thd->semi_sync_slave)
{
*need_sync = false;
DBUG_RETURN(0);
}
lock();
/* This is the real check inside the mutex. */ if (!get_master_enabled()) goto l_end;
if (is_on())
{ /* semi-sync is ON */ if (m_reply_file_name_inited)
{
cmp = Active_tranx::compare(log_file_name, log_file_pos,
m_reply_file_name, m_reply_file_pos); if (cmp <= 0)
{ /* If we have already got the reply for the event, then we do *notneedtosyncthetransactionagain.
*/ goto l_end;
}
}
/* This is the real check inside the mutex. */ if (!get_master_enabled()) goto l_end;
/* Update the 'largest' transaction commit position seen so far even *thoughsemi-syncisswitchedoff. *Itismuchbetterthatweupdatem_commit_file*here,insteadof *insidecommit_trx().Thisismostlybecauseupdate_sync_header() *willwatchform_commit_file*todecidewhethertoswitchsemi-sync *on.Thedetailedreasonisexplainedinfunctionupdate_sync_header().
*/ if (m_commit_file_name_inited)
{ int cmp = Active_tranx::compare(log_file_name, log_file_pos,
m_commit_file_name, m_commit_file_pos); if (cmp > 0)
{ /* This is a larger position, let's update the maximum info. */
strncpy(m_commit_file_name, log_file_name, FN_REFLEN-1);
m_commit_file_name[FN_REFLEN-1] = 0; /* make sure it ends properly */
m_commit_file_pos = log_file_pos;
}
} else
{
strncpy(m_commit_file_name, log_file_name, FN_REFLEN-1);
m_commit_file_name[FN_REFLEN-1] = 0; /* make sure it ends properly */
m_commit_file_pos = log_file_pos;
m_commit_file_name_inited = true;
}
int Repl_semi_sync_master::flush_net(THD *thd, constchar *event_buf)
{ int result = -1;
NET* net= &thd->net;
DBUG_ENTER("Repl_semi_sync_master::flush_net");
DBUG_ASSERT((unsignedchar)event_buf[1] == k_packet_magic_num); if ((unsignedchar)event_buf[2] != k_packet_flag_sync)
{ /* current event does not require reply */
result = 0; goto l_end;
}
/* We flush to make sure that the current event is sent to the network, *insteadofbeingbufferedintheTCP/IPstack.
*/ if (net_flush(net))
{
sql_print_error("Semi-sync master failed on net_flush() " "before waiting for slave reply"); goto l_end;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.