From b3a66b9a2f7bab82c0a4020c53633dbf7e6fb8f7 Mon Sep 17 00:00:00 2001 From: liuchangfeng Date: Fri, 20 Sep 2024 11:48:02 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=87=E6=9C=BA=E5=85=A8=E9=87=8Fbuild?= =?UTF-8?q?=E5=AF=B9undometa=E6=96=87=E4=BB=B6=E5=81=9A=E6=A0=A1=E9=AA=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../access/ustore/undo/knl_uundoapi.cpp | 106 ++++++++++++++++++ .../storage/replication/basebackup.cpp | 92 +++++++++++++++ src/include/access/ustore/undo/knl_uundoapi.h | 1 + .../access/ustore/undo/knl_uundospace.h | 7 ++ 4 files changed, 206 insertions(+) diff --git a/src/gausskernel/storage/access/ustore/undo/knl_uundoapi.cpp b/src/gausskernel/storage/access/ustore/undo/knl_uundoapi.cpp index a6a85602d..3de02ae2c 100644 --- a/src/gausskernel/storage/access/ustore/undo/knl_uundoapi.cpp +++ b/src/gausskernel/storage/access/ustore/undo/knl_uundoapi.cpp @@ -832,3 +832,109 @@ void ResetUndoZoneLock() } } // namespace undo + +bool CheckUndoZone(char *undoMeta) +{ + Assert(undoMeta != NULL); + uint32 zoneId = 0; + char *persistblock = undoMeta; + char *uspMetaBuffer = NULL; + pg_crc32 pageCrcVal = 0; /* CRC store in undo meta page */ + pg_crc32 comCrcVal = 0; /* calculating CRC current */ + for (zoneId = 0; zoneId < PERSIST_ZONE_COUNT; zoneId++) { + if (zoneId % (UNDOZONE_COUNT_PER_PAGE * PAGES_READ_NUM) == 0) { + if (zoneId / (UNDOZONE_COUNT_PER_PAGE * PAGES_READ_NUM) > 0) { + persistblock = persistblock + UNDO_META_PAGE_SIZE * PAGES_READ_NUM; + } + } + if (zoneId % UNDOZONE_COUNT_PER_PAGE == 0) { + uspMetaBuffer = + persistblock + + ((zoneId % (UNDOZONE_COUNT_PER_PAGE * PAGES_READ_NUM)) / UNDOZONE_COUNT_PER_PAGE) * UNDO_META_PAGE_SIZE; + uint32 count = UNDOZONE_COUNT_PER_PAGE; + if ((uint32)(PERSIST_ZONE_COUNT - zoneId) < UNDOZONE_COUNT_PER_PAGE) { + count = PERSIST_ZONE_COUNT - zoneId; + } + /* Get page CRC from uspMetaBuffer. */ + pageCrcVal = *(pg_crc32 *)(uspMetaBuffer + sizeof(undo::UndoZoneMetaInfo) * count); + /* + * Calculate the CRC value based on all undospace meta information stored on the page. + * Then compare with pageCrcVal. + */ + INIT_CRC32C(comCrcVal); + COMP_CRC32C(comCrcVal, (void *)uspMetaBuffer, sizeof(undo::UndoZoneMetaInfo) * count); + FIN_CRC32C(comCrcVal); + if (!EQ_CRC32C(pageCrcVal, comCrcVal)) { + ereport( + ERROR, + (errmsg(UNDOFORMAT( + "Undo meta zoneid(%d) CRC calculated(%u) is different from CRC recorded(%u) in page."), + zoneId, comCrcVal, pageCrcVal))); + return false; + } + } + } + return true; +} + +bool CheckUndoSpace(char *undoMeta, UndoSpaceType type) +{ + Assert(undoMeta != NULL); + uint32 zoneId = 0; + uint32 totalPageCnt = 0; + char *persistblock = NULL; + uint32 seek = 0; + char *uspMetaBuffer = NULL; + pg_crc32 pageCrcVal = 0; /* CRC store in undo meta page */ + pg_crc32 comCrcVal = 0; /* calculating CRC current */ + if (type == UNDO_LOG_SPACE) { + UNDOSPACE_META_PAGE_COUNT(PERSIST_ZONE_COUNT, UNDOZONE_COUNT_PER_PAGE, totalPageCnt); + seek = totalPageCnt * UNDO_META_PAGE_SIZE; + } else { + UNDOSPACE_META_PAGE_COUNT(PERSIST_ZONE_COUNT, UNDOZONE_COUNT_PER_PAGE, totalPageCnt); + seek = totalPageCnt * UNDO_META_PAGE_SIZE; + UNDOSPACE_META_PAGE_COUNT(PERSIST_ZONE_COUNT, UNDOSPACE_COUNT_PER_PAGE, totalPageCnt); + seek += totalPageCnt * UNDO_META_PAGE_SIZE; + } + persistblock = undoMeta + seek; + + for (zoneId = 0; zoneId < PERSIST_ZONE_COUNT; zoneId++) { + if (zoneId % (UNDOSPACE_COUNT_PER_PAGE * PAGES_READ_NUM) == 0) { + if (zoneId / (UNDOZONE_COUNT_PER_PAGE * PAGES_READ_NUM) > 0) { + persistblock = persistblock + UNDO_META_PAGE_SIZE * PAGES_READ_NUM; + } + } + if (zoneId % UNDOSPACE_COUNT_PER_PAGE == 0) { + uspMetaBuffer = + persistblock + ((zoneId % (UNDOSPACE_COUNT_PER_PAGE * PAGES_READ_NUM)) / UNDOSPACE_COUNT_PER_PAGE) * + UNDO_META_PAGE_SIZE; + uint32 count = UNDOSPACE_COUNT_PER_PAGE; + if ((uint32)(PERSIST_ZONE_COUNT - zoneId) < UNDOSPACE_COUNT_PER_PAGE) { + count = PERSIST_ZONE_COUNT - zoneId; + } + /* Get page CRC from uspMetaBuffer. */ + pageCrcVal = *(pg_crc32 *)(uspMetaBuffer + sizeof(undo::UndoSpaceMetaInfo) * count); + /* + * Calculate the CRC value based on all undospace meta information stored on the page. + * Then compare with pageCrcVal. + */ + INIT_CRC32C(comCrcVal); + COMP_CRC32C(comCrcVal, (void *)uspMetaBuffer, sizeof(undo::UndoSpaceMetaInfo) * count); + FIN_CRC32C(comCrcVal); + if (!EQ_CRC32C(pageCrcVal, comCrcVal)) { + ereport(ERROR, + (errmsg(UNDOFORMAT("Undo meta space type(%d) zonid(%d) CRC calculated(%u) is different from CRC recorded(%u) in page."), + type, zoneId, comCrcVal, pageCrcVal))); + return false; + } + } + } + return true; +} + +bool CheckUndoMetaBuf(char *undoMeta) +{ + Assert(undoMeta != NULL); + return CheckUndoZone(undoMeta) && CheckUndoSpace(undoMeta, UNDO_LOG_SPACE) && + CheckUndoSpace(undoMeta, UNDO_SLOT_SPACE); +} \ No newline at end of file diff --git a/src/gausskernel/storage/replication/basebackup.cpp b/src/gausskernel/storage/replication/basebackup.cpp index 2532c6a2a..7b838e59c 100755 --- a/src/gausskernel/storage/replication/basebackup.cpp +++ b/src/gausskernel/storage/replication/basebackup.cpp @@ -127,6 +127,9 @@ static XLogRecPtr UpdateStartPtr(XLogRecPtr minLsn, XLogRecPtr curStartPtr); /* compressed Function */ static void SendCompressedFile(char* readFileName, int basePathLen, struct stat& statbuf, bool missingOk, int64* size); +static bool SendUndoMeta(FILE *fp, struct stat *statbuf); +const int undometaSize = UNDOSPACE_META_PAGE_SIZE + 2 * UNDOSPACE_SPACE_PAGE_SIZE; +const int undometaRetryMax = 3; /* * save xlog location @@ -2240,6 +2243,10 @@ static bool sendFile(char *readfilename, char *tarfilename, struct stat *statbuf /* send the pkg header containing msg like file size */ _tarWriteHeader(tarfilename, NULL, statbuf); + char *fname = NULL; + if ((fname = strstr(readfilename, UNDO_META_FILE)) != NULL) { + return SendUndoMeta(fp, statbuf); + } /* Because pg_control file is shared in all instance when dss is enabled. Here pg_control of primary id * need to send to main standby in standby cluster, so we must seek a postion accoring to primary id. @@ -2462,3 +2469,88 @@ void ut_save_xlogloc(const char *xloglocation) { save_xlogloc(xloglocation); } + +static bool SendUndoMeta(FILE *fp, struct stat *statbuf) +{ + Assert(fp != NULL); + Assert(statbuf != NULL); + if (statbuf->st_size != undometaSize) { + (void)FreeFile(fp); + ereport(ERROR, (errmsg("Undometa size[%d] error", statbuf->st_size))); + } + pgoff_t len = 0; + MemoryContext oldcxt = MemoryContextSwitchTo(THREAD_GET_MEM_CXT_GROUP(MEMORY_CONTEXT_STORAGE)); + char *undoMeta = (char *)palloc0(statbuf->st_size); + MemoryContextSwitchTo(oldcxt); + int retry = 0; + size_t cnt = 0; + errno_t rc = 0; + size_t pad; + + fseek(fp, 0, SEEK_SET); + while ((cnt = fread(undoMeta, 1, statbuf->st_size, fp)) > 0) { + if (t_thrd.walsender_cxt.walsender_ready_to_stop) { + pfree(undoMeta); + ereport(ERROR, (errcode_for_file_access(), errmsg("base backup receive stop message, aborting backup"))); + } + if (cnt != (size_t)statbuf->st_size) { + if (ferror(fp)) { + pfree(undoMeta); + ereport(ERROR, (errcode_for_file_access(), errmsg("could not read file undometa file"))); + } + } + if (CheckUndoMetaBuf(undoMeta)) { + ereport(LOG, (errmsg("checkUndoMeta Success"))); + break; + } + retry++; + fseek(fp, 0, SEEK_SET); + if (retry > undometaRetryMax) { + pfree(undoMeta); + (void)FreeFile(fp); + ereport(ERROR, (errmsg("Read undo meta error"))); + } + } + while (len < statbuf->st_size) { + if (t_thrd.walsender_cxt.walsender_ready_to_stop) { + ereport(ERROR, (errcode_for_file_access(), errmsg("base backup receive stop message, aborting backup"))); + } + cnt = Min(TAR_SEND_SIZE, statbuf->st_size - len); + + /* Send the chunk as a CopyData Message */ + if (pq_putmessage_noblock('d', undoMeta + len, cnt)) { + ereport(ERROR, (errcode_for_file_access(), errmsg("base backup could not send data, aborting backup"))); + } + len += cnt; + if (len >= statbuf->st_size) { + /* + * Reached end of file. The file could be longer, if it was + * extended while we were sending it, but for a base backup we can + * ignore such extended data. It will be restored from WAL. + */ + break; + } + } + + /* If the file was truncated while we were sending it, pad it with zeros */ + if (len < statbuf->st_size) { + rc = memset_s(t_thrd.basebackup_cxt.buf_block, TAR_SEND_SIZE, 0, TAR_SEND_SIZE); + securec_check(rc, "", ""); + while (len < statbuf->st_size) { + cnt = Min(TAR_SEND_SIZE, statbuf->st_size - len); + (void)pq_putmessage_noblock('d', t_thrd.basebackup_cxt.buf_block, cnt); + len += cnt; + } + } + + /* Pad to 512 byte boundary, per tar format requirements */ + pad = ((len + 511) & ~511) - len; + if (pad > 0) { + rc = memset_s(t_thrd.basebackup_cxt.buf_block, pad, 0, pad); + securec_check(rc, "", ""); + (void)pq_putmessage_noblock('d', t_thrd.basebackup_cxt.buf_block, pad); + } + pfree(undoMeta); + (void)FreeFile(fp); + return true; +} diff --git a/src/include/access/ustore/undo/knl_uundoapi.h b/src/include/access/ustore/undo/knl_uundoapi.h index 66a2d0697..b6c813c25 100644 --- a/src/include/access/ustore/undo/knl_uundoapi.h +++ b/src/include/access/ustore/undo/knl_uundoapi.h @@ -70,4 +70,5 @@ void ResetUndoZoneLock(); } // namespace undo extern void GetUndoFileDirectory(char *path, int len, UndoPersistence upersistence); +bool CheckUndoMetaBuf(char *undoMeta); #endif // __KNL_UUNDOAPI_H__ diff --git a/src/include/access/ustore/undo/knl_uundospace.h b/src/include/access/ustore/undo/knl_uundospace.h index b738fd322..7b0c43077 100644 --- a/src/include/access/ustore/undo/knl_uundospace.h +++ b/src/include/access/ustore/undo/knl_uundospace.h @@ -41,6 +41,13 @@ typedef struct UndoSpaceMetaInfo { count = (total % unit == 0) ? (total / unit) : (total / unit) + 1; \ } while (0) +#define UNDOSPACE_META_PAGE_SIZE UNDO_META_PAGE_SIZE * \ +((PERSIST_ZONE_COUNT % UNDOZONE_COUNT_PER_PAGE == 0) ? (PERSIST_ZONE_COUNT / UNDOZONE_COUNT_PER_PAGE) : (PERSIST_ZONE_COUNT / UNDOZONE_COUNT_PER_PAGE) + 1) + +#define UNDOSPACE_SPACE_PAGE_SIZE UNDO_META_PAGE_SIZE * \ +((PERSIST_ZONE_COUNT % UNDOSPACE_COUNT_PER_PAGE == 0) ? (PERSIST_ZONE_COUNT / UNDOSPACE_COUNT_PER_PAGE) : (PERSIST_ZONE_COUNT / UNDOSPACE_COUNT_PER_PAGE) + 1) + + /* * UndoSpace class is used as a proxy to manipulate undo zone(segment) file. */