mirror of
https://github.com/MariaDB/server.git
synced 2025-08-08 11:22:35 +03:00
MDEV-15505 Fix wsrep XID seqno byte order
The problem is that the seqno part of wsrep XID is always stored in host byte order. This may cause issues when a physical backup is restored on a host with different architecture, the seqno part with XID may have incorrect value. In order to fix this, wsrep XID seqno is always written into XID data buffer in little endian byte order using int8store() and read from data buffer using sint8korr(). For backwards compatibility the seqno is read from TRX_SYS page in host byte order during upgrade. This patch implements byte ordering in wsrep_xid_init(), wsrep_xid_seqno(), and exposes functions to read wsrep XID uuid and seqno in wsrep_service_st. Backwards compatibility for upgrade is provided in trx_rseg_init_wsrep_xid().
This commit is contained in:
@@ -119,11 +119,7 @@ wsrep_seqno_t wsrep_xid_seqno(
|
|||||||
const XID* xid)
|
const XID* xid)
|
||||||
{
|
{
|
||||||
if (wsrep_is_wsrep_xid(xid)) {
|
if (wsrep_is_wsrep_xid(xid)) {
|
||||||
wsrep_seqno_t seqno;
|
return sint8korr(xid->data + WSREP_XID_SEQNO_OFFSET);
|
||||||
memcpy(&seqno, xid->data + WSREP_XID_SEQNO_OFFSET,
|
|
||||||
sizeof(wsrep_seqno_t));
|
|
||||||
|
|
||||||
return(seqno);
|
|
||||||
} else {
|
} else {
|
||||||
return(WSREP_SEQNO_UNDEFINED);
|
return(WSREP_SEQNO_UNDEFINED);
|
||||||
}
|
}
|
||||||
|
@@ -70,6 +70,8 @@ struct xid_t;
|
|||||||
struct wsrep;
|
struct wsrep;
|
||||||
struct wsrep_ws_handle;
|
struct wsrep_ws_handle;
|
||||||
struct wsrep_buf;
|
struct wsrep_buf;
|
||||||
|
/* must match to typedef in wsrep/wsrep_api.h */
|
||||||
|
typedef int64_t wsrep_seqno_t;
|
||||||
|
|
||||||
extern struct wsrep_service_st {
|
extern struct wsrep_service_st {
|
||||||
struct wsrep * (*get_wsrep_func)();
|
struct wsrep * (*get_wsrep_func)();
|
||||||
@@ -84,6 +86,8 @@ extern struct wsrep_service_st {
|
|||||||
void (*wsrep_aborting_thd_enqueue_func)(THD *thd);
|
void (*wsrep_aborting_thd_enqueue_func)(THD *thd);
|
||||||
bool (*wsrep_consistency_check_func)(THD *thd);
|
bool (*wsrep_consistency_check_func)(THD *thd);
|
||||||
int (*wsrep_is_wsrep_xid_func)(const struct xid_t *xid);
|
int (*wsrep_is_wsrep_xid_func)(const struct xid_t *xid);
|
||||||
|
wsrep_seqno_t (*wsrep_xid_seqno_func)(const struct xid_t *xid);
|
||||||
|
const unsigned char* (*wsrep_xid_uuid_func)(const struct xid_t *xid);
|
||||||
void (*wsrep_lock_rollback_func)();
|
void (*wsrep_lock_rollback_func)();
|
||||||
int (*wsrep_on_func)(MYSQL_THD);
|
int (*wsrep_on_func)(MYSQL_THD);
|
||||||
void (*wsrep_post_commit_func)(THD* thd, bool all);
|
void (*wsrep_post_commit_func)(THD* thd, bool all);
|
||||||
@@ -125,6 +129,8 @@ extern struct wsrep_service_st {
|
|||||||
#define wsrep_aborting_thd_enqueue(T) wsrep_service->wsrep_aborting_thd_enqueue_func(T)
|
#define wsrep_aborting_thd_enqueue(T) wsrep_service->wsrep_aborting_thd_enqueue_func(T)
|
||||||
#define wsrep_consistency_check(T) wsrep_service->wsrep_consistency_check_func(T)
|
#define wsrep_consistency_check(T) wsrep_service->wsrep_consistency_check_func(T)
|
||||||
#define wsrep_is_wsrep_xid(X) wsrep_service->wsrep_is_wsrep_xid_func(X)
|
#define wsrep_is_wsrep_xid(X) wsrep_service->wsrep_is_wsrep_xid_func(X)
|
||||||
|
#define wsrep_xid_seqno(X) wsrep_service->wsrep_xid_seqno_func(X)
|
||||||
|
#define wsrep_xid_uuid(X) wsrep_service->wsrep_xid_uuid_func(X)
|
||||||
#define wsrep_lock_rollback() wsrep_service->wsrep_lock_rollback_func()
|
#define wsrep_lock_rollback() wsrep_service->wsrep_lock_rollback_func()
|
||||||
#define wsrep_on(X) wsrep_service->wsrep_on_func(X)
|
#define wsrep_on(X) wsrep_service->wsrep_on_func(X)
|
||||||
#define wsrep_post_commit(T,A) wsrep_service->wsrep_post_commit_func(T,A)
|
#define wsrep_post_commit(T,A) wsrep_service->wsrep_post_commit_func(T,A)
|
||||||
@@ -182,6 +188,8 @@ enum wsrep_exec_mode wsrep_thd_exec_mode(THD *thd);
|
|||||||
enum wsrep_query_state wsrep_thd_query_state(THD *thd);
|
enum wsrep_query_state wsrep_thd_query_state(THD *thd);
|
||||||
enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, bool all);
|
enum wsrep_trx_status wsrep_run_wsrep_commit(THD *thd, bool all);
|
||||||
int wsrep_is_wsrep_xid(const struct xid_t* xid);
|
int wsrep_is_wsrep_xid(const struct xid_t* xid);
|
||||||
|
wsrep_seqno_t wsrep_xid_seqno(const struct xid_t* xid);
|
||||||
|
const unsigned char* wsrep_xid_uuid(const struct xid_t* xid);
|
||||||
int wsrep_on(MYSQL_THD thd);
|
int wsrep_on(MYSQL_THD thd);
|
||||||
int wsrep_thd_retry_counter(THD *thd);
|
int wsrep_thd_retry_counter(THD *thd);
|
||||||
int wsrep_trx_is_aborting(MYSQL_THD thd);
|
int wsrep_trx_is_aborting(MYSQL_THD thd);
|
||||||
|
@@ -154,6 +154,8 @@ static struct wsrep_service_st wsrep_handler = {
|
|||||||
wsrep_aborting_thd_enqueue,
|
wsrep_aborting_thd_enqueue,
|
||||||
wsrep_consistency_check,
|
wsrep_consistency_check,
|
||||||
wsrep_is_wsrep_xid,
|
wsrep_is_wsrep_xid,
|
||||||
|
wsrep_xid_seqno,
|
||||||
|
wsrep_xid_uuid,
|
||||||
wsrep_lock_rollback,
|
wsrep_lock_rollback,
|
||||||
wsrep_on,
|
wsrep_on,
|
||||||
wsrep_post_commit,
|
wsrep_post_commit,
|
||||||
|
@@ -39,7 +39,7 @@ void wsrep_xid_init(XID* xid, const wsrep_uuid_t& uuid, wsrep_seqno_t seqno)
|
|||||||
memset(xid->data, 0, sizeof(xid->data));
|
memset(xid->data, 0, sizeof(xid->data));
|
||||||
memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN);
|
memcpy(xid->data, WSREP_XID_PREFIX, WSREP_XID_PREFIX_LEN);
|
||||||
memcpy(xid->data + WSREP_XID_UUID_OFFSET, &uuid, sizeof(wsrep_uuid_t));
|
memcpy(xid->data + WSREP_XID_UUID_OFFSET, &uuid, sizeof(wsrep_uuid_t));
|
||||||
memcpy(xid->data + WSREP_XID_SEQNO_OFFSET, &seqno, sizeof(wsrep_seqno_t));
|
int8store(xid->data + WSREP_XID_SEQNO_OFFSET,seqno);
|
||||||
}
|
}
|
||||||
|
|
||||||
int wsrep_is_wsrep_xid(const XID* xid)
|
int wsrep_is_wsrep_xid(const XID* xid)
|
||||||
@@ -59,13 +59,17 @@ const wsrep_uuid_t* wsrep_xid_uuid(const XID& xid)
|
|||||||
return &WSREP_UUID_UNDEFINED;
|
return &WSREP_UUID_UNDEFINED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const unsigned char* wsrep_xid_uuid(const xid_t* xid)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(xid);
|
||||||
|
return wsrep_xid_uuid(*xid)->data;
|
||||||
|
}
|
||||||
|
|
||||||
wsrep_seqno_t wsrep_xid_seqno(const XID& xid)
|
wsrep_seqno_t wsrep_xid_seqno(const XID& xid)
|
||||||
{
|
{
|
||||||
if (wsrep_is_wsrep_xid(&xid))
|
if (wsrep_is_wsrep_xid(&xid))
|
||||||
{
|
{
|
||||||
wsrep_seqno_t seqno;
|
return sint8korr(xid.data + WSREP_XID_SEQNO_OFFSET);
|
||||||
memcpy(&seqno, xid.data + WSREP_XID_SEQNO_OFFSET, sizeof(wsrep_seqno_t));
|
|
||||||
return seqno;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -73,6 +77,12 @@ wsrep_seqno_t wsrep_xid_seqno(const XID& xid)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wsrep_seqno_t wsrep_xid_seqno(const xid_t* xid)
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(xid);
|
||||||
|
return wsrep_xid_seqno(*xid);
|
||||||
|
}
|
||||||
|
|
||||||
static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
|
static my_bool set_SE_checkpoint(THD* unused, plugin_ref plugin, void* arg)
|
||||||
{
|
{
|
||||||
XID* xid= static_cast<XID*>(arg);
|
XID* xid= static_cast<XID*>(arg);
|
||||||
|
@@ -35,32 +35,15 @@ Created 3/26/1996 Heikki Tuuri
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#ifdef WITH_WSREP
|
#ifdef WITH_WSREP
|
||||||
|
#include <mysql/service_wsrep.h>
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
/** The latest known WSREP XID sequence number */
|
/** The latest known WSREP XID sequence number */
|
||||||
static long long wsrep_seqno = -1;
|
static wsrep_seqno_t wsrep_seqno = -1;
|
||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
/** The latest known WSREP XID UUID */
|
/** The latest known WSREP XID UUID */
|
||||||
static unsigned char wsrep_uuid[16];
|
static unsigned char wsrep_uuid[16];
|
||||||
|
|
||||||
/** Read WSREP XID UUID.
|
|
||||||
@param[in] xid WSREP XID
|
|
||||||
@return Pointer to the first byte of the UUID.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static inline const byte* read_wsrep_xid_uuid(const XID* xid)
|
|
||||||
{
|
|
||||||
return reinterpret_cast<const byte*>(xid->data + 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Read WSREP XID seqno */
|
|
||||||
static inline long long read_wsrep_xid_seqno(const XID* xid)
|
|
||||||
{
|
|
||||||
long long seqno;
|
|
||||||
memcpy(&seqno, xid->data + 24, sizeof(long long));
|
|
||||||
return seqno;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Update the WSREP XID information in rollback segment header.
|
/** Update the WSREP XID information in rollback segment header.
|
||||||
@param[in,out] rseg_header rollback segment header
|
@param[in,out] rseg_header rollback segment header
|
||||||
@param[in] xid WSREP XID
|
@param[in] xid WSREP XID
|
||||||
@@ -71,12 +54,12 @@ trx_rseg_update_wsrep_checkpoint(
|
|||||||
const XID* xid,
|
const XID* xid,
|
||||||
mtr_t* mtr)
|
mtr_t* mtr)
|
||||||
{
|
{
|
||||||
ut_ad(xid->formatID == 1);
|
ut_ad(wsrep_is_wsrep_xid(xid));
|
||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
/* Check that seqno is monotonically increasing */
|
/* Check that seqno is monotonically increasing */
|
||||||
long long xid_seqno = read_wsrep_xid_seqno(xid);
|
wsrep_seqno_t xid_seqno = wsrep_xid_seqno(xid);
|
||||||
const byte* xid_uuid = read_wsrep_xid_uuid(xid);
|
const byte* xid_uuid = wsrep_xid_uuid(xid);
|
||||||
|
|
||||||
if (!memcmp(xid_uuid, wsrep_uuid, sizeof wsrep_uuid)) {
|
if (!memcmp(xid_uuid, wsrep_uuid, sizeof wsrep_uuid)) {
|
||||||
ut_ad(xid_seqno > wsrep_seqno);
|
ut_ad(xid_seqno > wsrep_seqno);
|
||||||
@@ -125,7 +108,7 @@ void trx_rseg_update_wsrep_checkpoint(const XID* xid)
|
|||||||
|
|
||||||
trx_rseg_update_wsrep_checkpoint(rseg_header, xid, &mtr);
|
trx_rseg_update_wsrep_checkpoint(rseg_header, xid, &mtr);
|
||||||
|
|
||||||
const byte* xid_uuid = read_wsrep_xid_uuid(xid);
|
const byte* xid_uuid = wsrep_xid_uuid(xid);
|
||||||
if (memcmp(wsrep_uuid, xid_uuid, sizeof wsrep_uuid)) {
|
if (memcmp(wsrep_uuid, xid_uuid, sizeof wsrep_uuid)) {
|
||||||
memcpy(wsrep_uuid, xid_uuid, sizeof wsrep_uuid);
|
memcpy(wsrep_uuid, xid_uuid, sizeof wsrep_uuid);
|
||||||
|
|
||||||
@@ -203,6 +186,17 @@ static bool trx_rseg_init_wsrep_xid(const page_t* page, XID& xid)
|
|||||||
memcpy(xid.data,
|
memcpy(xid.data,
|
||||||
TRX_SYS + TRX_SYS_WSREP_XID_INFO
|
TRX_SYS + TRX_SYS_WSREP_XID_INFO
|
||||||
+ TRX_SYS_WSREP_XID_DATA + page, XIDDATASIZE);
|
+ TRX_SYS_WSREP_XID_DATA + page, XIDDATASIZE);
|
||||||
|
|
||||||
|
/* Wsrep XID seqno part in TRX_SYS page was written in host byte
|
||||||
|
order. However, in the XID which gets written to the rollback
|
||||||
|
segment header the byte order is little endian. On big endian
|
||||||
|
machines swap the seqno part byte order. */
|
||||||
|
#ifdef WORDS_BIGENDIAN
|
||||||
|
wsrep_seqno_t seqno;
|
||||||
|
memcpy(&seqno, xid.data + 24, sizeof seqno);
|
||||||
|
mach_swap_byte_order(xid.data + 24, &seqno, sizeof seqno);
|
||||||
|
#endif /* WORDS_BIGENDIAN */
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,14 +233,14 @@ bool trx_rseg_read_wsrep_checkpoint(XID& xid)
|
|||||||
}
|
}
|
||||||
|
|
||||||
XID tmp_xid;
|
XID tmp_xid;
|
||||||
long long tmp_seqno = 0;
|
wsrep_seqno_t tmp_seqno = 0;
|
||||||
if (trx_rseg_read_wsrep_checkpoint(rseg_header, tmp_xid)
|
if (trx_rseg_read_wsrep_checkpoint(rseg_header, tmp_xid)
|
||||||
&& (tmp_seqno = read_wsrep_xid_seqno(&tmp_xid))
|
&& (tmp_seqno = wsrep_xid_seqno(&tmp_xid))
|
||||||
> max_xid_seqno) {
|
> max_xid_seqno) {
|
||||||
found = true;
|
found = true;
|
||||||
max_xid_seqno = tmp_seqno;
|
max_xid_seqno = tmp_seqno;
|
||||||
xid = tmp_xid;
|
xid = tmp_xid;
|
||||||
memcpy(wsrep_uuid, read_wsrep_xid_uuid(&tmp_xid),
|
memcpy(wsrep_uuid, wsrep_xid_uuid(&tmp_xid),
|
||||||
sizeof wsrep_uuid);
|
sizeof wsrep_uuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user