WL#7796: WAIT_FOR_EXECUTED_GTID_SET
Affects: Server-5.7
—
Status: Complete
The function WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS has several shortcomings: - The function is dependent on the slave to execute. If the slave thread is not running (or if is being stopped while the function is executed), then the function returns an error. It would be better if the function kept waiting, so that it could be used even when the slave is stopped. - The function returns an event count. This is meaningless and not very well-defined. It would be better to just return 0 for success, 1 for timeout, and 2 for other failure (i.e., query killed). - The function is ill-named. In this worklog we introduce a better replacement: WAIT_FOR_EXECUTED_GTID_SET(GTID_SET [, TIMEOUT]) This function shall not care about slaves running and shall return just 0 or 1.
Functional requirement ======================= FR1 - Wait for the gtid_executed set to be superset of the gtid_set value specified (both timed and untimed wait) FR2 - Should not be dependent on the slave threads. Non Functional requirement =========================== NFR1 - Should not cause any performance drop due to extra wait for the gtid set.
This worklog aims at adding a new sql function WAIT_FOR_EXECUTED_GTID_SET which make the current syncing option for the slave with master independent of the slave threads. The use of the new function will be : WAIT_FOR_EXECUTED_GTID_SET(GTID_SET [, TIMEOUT]) Wait until all the transactions whose global transaction identifiers are being specified, are contained in gtid_set. ie. After this function returns with success, it must hold that GTID_SUBSET(GTID_SET, @@global.gtid_executed) returns true. The TIMEOUT parameter is used for the maximum duration for which we have to wait for the GTIDS to be synced. If its not able to get to that GTID value in this duration we return timeout error. (current unit for timeout is second and it uses integer values for timeout) Use : mysql> SELECT WAIT_FOR_EXECUTED_GTID_SET('3E11FA47-71CA-11E1-9E33-C80AA9429562:1- 5'); -> 0 The return value is a bit different compared to WAIT_UNTIL_SQL_THREAD_AFTER_GTIDS return value which is the event count. The return values here are : 0 - success 1 - timeout For all other cases we will throw corresponding error messages eg :- ER_OUT_OF_RESOURCES ER_MALFORMED_GTID_SET_SPECIFICATION ER_QUERY_INTERRUPTED
Low level design ================= FILE - rpl_gtid.h ================== ## class Mutex_cond_array Add a new member inline int wait(int n, struct timespec* abstime) const which is a timed version of the already existing wait function. The caller holds the read or write lock on the sid_lock and it does a cond_timedwait (ie. waits for the timeout duration) to see whether the condition is met or timeout is reached. This method is called from the wait for gtid method of the Gtid_state class. ## class Gtid_state The following function will take a new parameter ie. Timeout and will call the corresponding function defined on the Mutex_cond_array class based on whether the timeout is set or not. Also it will return error values which will be based on the timeout duration exceeded or not. int Gtid_state::wait_for_gtid(THD *thd, const Gtid & gtid, longlong* timeout) We also add the following new method which does the actual wait for the gtid_set to be in subset of the executed gtid_set by calling itself repeatedly. Since the loop might be called multiple times we would like to use the same timeout value for the iterations and decrease it after each call, we are passing the timeout as pointer. /** @param thd - global thread pointer. @param Gtid - Pointer to the Gtid set which gets updated. @param timeout - Timeout value for which wait should be done in millisecond. @return 0 - success 1 - timeout For all other cases we will throw corresponding error messages using the my_error(ER_*, MYF(0)) call and return with value of -1. eg: my_error(ER_OUT_OF_RESOURCES, MYF(0)); ER_OUT_OF_RESOURCES ER_QUERY_INTERRUPTED. **/ int wait_for_gtid_set(THD* thd, String* gtid, longlong timeout); This method is called from the Item_executed_gtid_set::val_int() ## class Owned_gtids We are adding a new member to the Owned_gtids class which will remove the owned gtids set from the already executed gtid_set. @param other - The gtid set from which the owned gtids have to be removed. enum_return_status remove_from_gtid_set(Gtid_set* other); This method is called from the wait_for_gtid_set defined in the Gtid_state class inside a loop. The reason why the owned_gtids set is removed from the executed gtid_set is gtids are added to executed_gtids when they are flushed to the binary log, not when they are committed to the storage engine. But they are kept in owned_gtids until the storage engine commit. Since we consider transactions that are between flush and commit to not be committed, we have to remove them from executed_gtid_set before we remove executed_gtid_set from wait_gtid_set. /** Supporting class and functions for the new SQL function WAIT_FOR_EXECUTED_GTID_SET. */ FILE - sql/item_create.cc ========================== /* We are implementing the standard framework required by any native function. */ class Create_func_executed_gtid_set_wait : public Create_native_func Item* Create_func_executed_gtid_set_wait::create_native(THD *thd, LEX_STRING name, PT_item_list *item_list) { { C_STRING_WITH_LEN("WAIT_FOR_EXECUTED_GTID_SET") }, BUILDER(Create_func_executed_gtid_set_wait)} FILE - sql/item_func.cc ======================== bool Item_executed_gtid_set_wait::itemize(Parse_context *pc, Item **res) longlong Item_executed_gtid_set_wait::val_int() { ... int ret_val= gtid_state->wait_for_gtid_set(thd, gtid, timeout); // call to the wait_for_gtid_set function. ... } FILE - sql/item_func.h ======================= class Item_executed_gtid_set_wait :public Item_int_func
Copyright (c) 2000, 2024, Oracle Corporation and/or its affiliates. All rights reserved.