From 440cd3ebc8eb3591a86e46e2466e537463a8daa5 Mon Sep 17 00:00:00 2001 From: ryne3366 Date: Thu, 6 Feb 2025 18:28:58 +0800 Subject: [PATCH] meta recovery fix open race Signed-off-by: ryne3366 --- src/sqlite3.c | 114 ++++++++++++++++++++++---------------------------- 1 file changed, 51 insertions(+), 63 deletions(-) diff --git a/src/sqlite3.c b/src/sqlite3.c index c7dd21e..7b95184 100644 --- a/src/sqlite3.c +++ b/src/sqlite3.c @@ -781,9 +781,9 @@ SQLITE_API int sqlite3_exec( #define SQLITE_NOTADB 26 /* File opened that is not a database file */ #define SQLITE_NOTICE 27 /* Notifications from sqlite3_log() */ #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ -#define SQLITE_META_RECOVERED 66 /* meta page recovered*/ #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ +#define SQLITE_META_RECOVERED 66 /* meta page recovered*/ /* end-of-error-codes */ /* @@ -43290,6 +43290,7 @@ static int unixOpen( flags |= SQLITE_OPEN_READONLY; openFlags |= O_RDONLY; isReadonly = 1; + sqlite3_log(SQLITE_WARNING, "Try open file readonly"); fd = robust_open(zName, openFlags, openMode); } } @@ -56102,7 +56103,7 @@ static int MetaDwrUpdateMetaPages(Btree *pBt); static void MetaDwrPagerRelease(Pager *pPager); static int MetaDwrOpenFile(Pager *pPager, u8 openCreate); static void MetaDwrCheckVacuum(BtShared *pBt); -static int MetaDwrDoRecover(Btree *pBt, u8 headCorrput); +static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion); static int MetaDwrOpenAndCheck(Btree *pBt); #define META_HEADER_CHANGED 1 #define META_SCHEMA_CHANGED 2 @@ -68288,9 +68289,9 @@ struct BtShared { u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ int nPreformatSize; /* Size of last cell written by TransferRow() */ #ifdef SQLITE_META_DWR - int metaFileChecked; - int maxMetaPage; - int metaRecoverStatus; + u32 metaFileChecked; + u32 maxMetaPage; + u32 metaRecoverStatus; #endif }; @@ -72803,11 +72804,9 @@ trans_begun: } } #ifdef SQLITE_META_DWR - if (rc == SQLITE_NOTADB) { - rc = MetaDwrDoRecover(p, 1); - if (rc == SQLITE_OK) { - rc = sqlite3BtreeBeginTrans(p, wrflag, pSchemaVersion); - } + if (rc == SQLITE_NOTADB || rc == SQLITE_CORRUPT) { + int rc1 = MetaDwrRecoverAndBeginTran(p, wrflag, pSchemaVersion); + rc = (rc1 == SQLITE_OK) ? SQLITE_OK : rc; } #endif btreeIntegrity(p); @@ -245444,8 +245443,8 @@ CODEC_STATIC int sqlite3CodecDecryptData(CodecContext *ctx, OperateContext which inputBuffer.buffer = input; inputBuffer.bufferSize = bufferSize - keyCtx->codecConst.reserveSize; if(sqlite3CodecCheckHmac(keyCtx, pgno, inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize, input, input + inputBuffer.bufferSize + keyCtx->codecConst.initVectorSize)){ - sqlite3_log(SQLITE_ERROR, "codec: check hmac error at page %d, hmac %d, kdf %d, pageSize %d.", - pgno, keyCtx->codecConst.hmacAlgo, keyCtx->codecConst.kdfAlgo, keyCtx->codecConst.cipherPageSize); + sqlite3_log(SQLITE_ERROR, "codec: check hmac error at page %d, hmac %d, kdf %d, pageSize %d, iter %d.", + pgno, keyCtx->codecConst.hmacAlgo, keyCtx->codecConst.kdfAlgo, keyCtx->codecConst.cipherPageSize, keyCtx->iter); return SQLITE_ERROR; } unsigned char *initVector = input + inputBuffer.bufferSize; @@ -246237,7 +246236,7 @@ static int ScanBtreePage( } rc = fn(pPage, args); if (rc) { - goto ScanBtreePage_out; + goto SCAN_PAGE_OUT; } hdr = pPage->hdrOffset; for (i = pPage->nCell - 1; i >= 0; i--) { @@ -246245,24 +246244,24 @@ static int ScanBtreePage( if (!pPage->leaf) { rc = ScanBtreePage(pBt, get4byte(pCell), fn, args); if (rc) { - goto ScanBtreePage_out; + goto SCAN_PAGE_OUT; } } pPage->xParseCell(pPage, pCell, &info); if (info.nLocal != info.nPayload) { rc = ScanOverflowPages(pPage, pCell, &info, fn, args); if (rc) { - goto ScanBtreePage_out; + goto SCAN_PAGE_OUT; } } } if (!pPage->leaf) { rc = ScanBtreePage(pBt, get4byte(&pPage->aData[hdr + 8]), fn, args); if (rc) { - goto ScanBtreePage_out; + goto SCAN_PAGE_OUT; } } -ScanBtreePage_out: +SCAN_PAGE_OUT: releasePage(pPage); return rc; } @@ -246292,7 +246291,7 @@ static void MetaDwrReleaseHdr(MetaDwrHdr *hdr) { sqlite3_free(hdr); } -static int ExpandMetaPageBuf(MetaDwrHdr *hdr, int minimalPageCnt) { +static int ExpandMetaPageBuf(MetaDwrHdr *hdr, u32 minimalPageCnt) { if (minimalPageCnt < hdr->pageBufSize && hdr->zones != NULL) { return SQLITE_OK; } @@ -246507,7 +246506,7 @@ static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr) { return rc; } -static int MetaDwrFindPageIdx(MetaDwrHdr *hdr, int pgno, int *idx) { +static int MetaDwrFindPageIdx(MetaDwrHdr *hdr, u32 pgno, u32 *idx) { for (u32 i = 0; i < hdr->pageCnt && i < META_DWR_MAX_PAGES; i++) { if (pgno == hdr->pages[i]) { *idx = i; @@ -246517,7 +246516,7 @@ static int MetaDwrFindPageIdx(MetaDwrHdr *hdr, int pgno, int *idx) { return 0; } -static int MetaDwrWriteOnePage(Btree *pBt, PgHdr *pPage, MetaDwrHdr *hdr, u8 curZones, int idx) { +static int MetaDwrWriteOnePage(Btree *pBt, PgHdr *pPage, MetaDwrHdr *hdr, u8 curZones, u32 idx) { int rc = SQLITE_OK; u8 pageExpand = 0; if (hdr->pageCnt <= idx) { @@ -246776,7 +246775,7 @@ static int MetaDwrRestoreChangedPages(Btree *pBt) { if (hdr->pageCnt > 0) { memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); } - int idx = 0; + u32 idx = 0; PgHdr *p = 0; PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); int rc = SQLITE_OK; @@ -246894,45 +246893,35 @@ static int MetaDwrBeginTrans(Btree *pBt, int wrflag) { return rc; } -static int MetaDwrDoRecover(Btree *pBt, u8 headCorrput) { +static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion) +{ Pager *pPager = pBt->pBt->pPager; assert(sqlite3_mutex_held(pBt->pBt->mutex)); if (!pPager->metaFd || pBt->pBt->metaRecoverStatus || pPager->readOnly || pPager->memDb) { - return headCorrput ? SQLITE_NOTADB : SQLITE_OK; + return SQLITE_NOTADB; + } + int rc = MetaDwrLoadHdr(pPager); + if (rc != SQLITE_OK) { + sqlite3_log(rc, "MetaDwr load header failed"); + return rc; } pBt->pBt->metaRecoverStatus = META_IN_RECOVERY; - int rc = SQLITE_OK; - void *pData = NULL; - int openedTransaction = 0; - int txnState = sqlite3BtreeTxnState(pBt); - if (txnState <= SQLITE_TXN_READ) { - rc = MetaDwrBeginTrans(pBt, 2); - if (rc != SQLITE_OK) { - goto CLEAN_OUT; - } - openedTransaction = 1; - } else { - rc = MetaDwrLoadAndCheckMetaFile(pBt->pBt, 1); - if (rc != SQLITE_OK) { - sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta recover check failed"); - goto CLEAN_OUT; - } + rc = MetaDwrBeginTrans(pBt, 2); + if (rc != SQLITE_OK) { + return rc; } + void *pData = NULL; pPager->metaChanged = META_HEADER_CHANGED; MetaDwrHdr *hdr = pPager->metaHdr; sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta recover %u frames", hdr->pageCnt); - // page 1 recovered in MetaDwrBeginTrans - if (hdr->pageCnt == 1) { - goto CLEAN_OUT; - } int szPage = sqlite3BtreeGetPageSize(pBt); pData = sqlite3Malloc(szPage); if (pData == NULL) { rc = SQLITE_NOMEM; sqlite3_log(rc, "Dwr malloc mem size %d failed", szPage); - goto CLEAN_OUT; + goto DWR_RECOVER_OUT; } - for (u32 i = 1; i < hdr->pageCnt; i++) { + for (u32 i = 0; i < hdr->pageCnt; i++) { rc = MetaDwrReadOnePage(pPager, hdr, i, pData); if (rc != SQLITE_OK) { sqlite3_log(rc, "Dwr read %d meta page failed ", i); @@ -246944,14 +246933,15 @@ static int MetaDwrDoRecover(Btree *pBt, u8 headCorrput) { break; } } -CLEAN_OUT: +DWR_RECOVER_OUT: /* Close the transaction, if one was opened. */ - if (openedTransaction) { - if (rc == SQLITE_OK) { - sqlite3BtreeCommit(pBt); - } else { - (void)sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); - } + if (rc == SQLITE_OK) { + sqlite3BtreeCommit(pBt); + } else { + (void)sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); + } + if (rc == SQLITE_OK) { + rc = sqlite3BtreeBeginTrans(pBt, wrflag, pSchemaVersion); } if (rc == SQLITE_OK) { pBt->pBt->metaRecoverStatus = META_RECOVER_SUCCESS; @@ -247013,20 +247003,22 @@ static int MetaDwrOpenAndCheck(Btree *pBt) { sqlite3BtreeEnter(pBt); int rc = SQLITE_OK; int openedTransaction = 0; - if (sqlite3BtreeTxnState(pBt) <= SQLITE_TXN_READ) { - rc = sqlite3BtreeBeginTrans(pBt, 2, 0); + int tnxState = sqlite3BtreeTxnState(pBt); + if (tnxState == SQLITE_TXN_NONE) { + rc = sqlite3BtreeBeginTrans(pBt, 0, 0); if (rc != SQLITE_OK) { - goto CLEAN_OUT; + goto DWR_OPEN_OUT; } openedTransaction = 1; } rc = MetaDwrCheckMeta(pBt); if (rc == SQLITE_CORRUPT || rc == SQLITE_NOTADB) { - rc = MetaDwrDoRecover(pBt, 0); - goto CLEAN_OUT; + // keep txn status after recover + rc = MetaDwrRecoverAndBeginTran(pBt, tnxState == SQLITE_TXN_WRITE ? 1 : 0, 0); + goto DWR_OPEN_OUT; } rc = Sqlite3MetaDwrCheckRestore(pBt); -CLEAN_OUT: +DWR_OPEN_OUT: if (rc == SQLITE_OK && pBt->pBt->metaRecoverStatus == META_RECOVER_SUCCESS) { rc = MetaDwrCheckMeta(pBt); if (rc == SQLITE_OK) { @@ -247035,11 +247027,7 @@ CLEAN_OUT: } /* Close the transaction, if one was opened. */ if (openedTransaction) { - if (rc == SQLITE_OK) { - sqlite3BtreeCommit(pBt); - } else { - (void)sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); - } + sqlite3BtreeCommit(pBt); } sqlite3BtreeLeave(pBt); pBt->pBt->metaFileChecked = 1; -- Gitee