1From d6f2f7b1d7d288bc0cb0ff998052bb8efac40f7f Mon Sep 17 00:00:00 2001 2From: MartinChoo <214582617@qq.com> 3Date: Wed, 23 Jul 2025 17:41:00 +0800 4Subject: [PATCH 04/12] Support meta recovery 5 6--- 7 src/sqlite3.c | 1156 ++++++++++++++++++++++++++++++++++++++++++++++++- 8 1 file changed, 1151 insertions(+), 5 deletions(-) 9 10diff --git a/src/sqlite3.c b/src/sqlite3.c 11index 6f423a9..dc09c3c 100644 12--- a/src/sqlite3.c 13+++ b/src/sqlite3.c 14@@ -786,6 +786,7 @@ SQLITE_API int sqlite3_exec( 15 #define SQLITE_WARNING 28 /* Warnings from sqlite3_log() */ 16 #define SQLITE_ROW 100 /* sqlite3_step() has another row ready */ 17 #define SQLITE_DONE 101 /* sqlite3_step() has finished executing */ 18+#define SQLITE_META_RECOVERED 66 /* meta page recovered*/ 19 /* end-of-error-codes */ 20 21 /* 22@@ -57472,6 +57473,26 @@ struct PagerSavepoint { 23 #endif 24 }; 25 26+#if !defined(SQLITE_OS_UNIX) && defined(SQLITE_META_DWR) 27+#undef SQLITE_META_DWR 28+#endif 29+ 30+#ifdef SQLITE_META_DWR 31+static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight); 32+typedef struct MetaDwrHdr MetaDwrHdr; 33+static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr); 34+static int MetaDwrUpdateMetaPages(Btree *pBt); 35+static void MetaDwrPagerRelease(Pager *pPager); 36+static int MetaDwrOpenFile(Pager *pPager, u8 openCreate); 37+static void MetaDwrCheckVacuum(BtShared *pBt); 38+static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion); 39+static int MetaDwrOpenAndCheck(Btree *pBt); 40+static void MetaDwrDisable(Btree *pBt); 41+#define META_HEADER_CHANGED 1 42+#define META_SCHEMA_CHANGED 2 43+#define META_IN_RECOVERY 1 44+#define META_RECOVER_SUCCESS 2 45+#endif 46 /* 47 ** Bits of the Pager.doNotSpill flag. See further description below. 48 */ 49@@ -57737,6 +57758,13 @@ struct Pager { 50 Wal *pWal; /* Write-ahead log used by "journal_mode=wal" */ 51 char *zWal; /* File name for write-ahead log */ 52 #endif 53+#ifdef SQLITE_META_DWR 54+ u8 metaChanged; 55+ sqlite3_file *metaFd; 56+ MetaDwrHdr *metaHdr; 57+ void *metaMapPage; 58+ int (*xGetMethod)(Pager*,Pgno,DbPage**,int); /* Routine to fetch a patch */ 59+#endif 60 }; 61 62 /* 63@@ -58096,7 +58124,11 @@ static void setGetterMethod(Pager *pPager){ 64 pPager->xGet = getPageMMap; 65 #endif /* SQLITE_MAX_MMAP_SIZE>0 */ 66 }else{ 67+#ifdef SQLITE_META_DWR 68+ pPager->xGet = pPager->xGetMethod ? pPager->xGetMethod : getPageNormal; 69+#else 70 pPager->xGet = getPageNormal; 71+#endif 72 } 73 } 74 75@@ -59170,7 +59202,14 @@ static int pager_end_transaction(Pager *pPager, int hasSuper, int bCommit){ 76 } 77 sqlite3PcacheTruncate(pPager->pPCache, pPager->dbSize); 78 } 79- 80+#ifdef SQLITE_META_DWR 81+ if (bCommit && pPager->metaChanged != 0) { 82+ sqlite3BeginBenignMalloc(); 83+ (void)MetaDwrWriteHeader(pPager, pPager->metaHdr); 84+ sqlite3EndBenignMalloc(); 85+ pPager->metaChanged = 0; 86+ } 87+#endif 88 if( pagerUseWal(pPager) ){ 89 /* Drop the WAL write-lock, if any. Also, if the connection was in 90 ** locking_mode=exclusive mode but is no longer, drop the EXCLUSIVE 91@@ -61269,6 +61308,9 @@ SQLITE_PRIVATE int sqlite3PagerClose(Pager *pPager, sqlite3 *db){ 92 sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a); 93 pPager->pWal = 0; 94 } 95+#endif 96+#ifdef SQLITE_META_DWR 97+ MetaDwrPagerRelease(pPager); 98 #endif 99 pager_reset(pPager); 100 if( MEMDB ){ 101@@ -62112,7 +62154,11 @@ act_like_temp_file: 102 rc = sqlite3PcacheOpen(szPageDflt, nExtra, !memDb, 103 !memDb?pagerStress:0, (void *)pPager, pPager->pPCache); 104 } 105- 106+#ifdef SQLITE_META_DWR 107+ if( rc==SQLITE_OK && !memDb && !readOnly){ 108+ (void)MetaDwrOpenFile(pPager, 0); 109+ } 110+#endif 111 /* If an error occurred above, free the Pager structure and close the file. 112 */ 113 if( rc!=SQLITE_OK ){ 114@@ -70005,6 +70051,10 @@ struct BtShared { 115 #endif 116 u8 *pTmpSpace; /* Temp space sufficient to hold a single cell */ 117 int nPreformatSize; /* Size of last cell written by TransferRow() */ 118+#ifdef SQLITE_META_DWR 119+ u32 maxMetaPage; 120+ u32 metaRecoverStatus; 121+#endif 122 }; 123 124 /* 125@@ -74298,7 +74348,12 @@ trans_begun: 126 rc = sqlite3PagerOpenSavepoint(pPager, p->db->nSavepoint); 127 } 128 } 129- 130+#ifdef SQLITE_META_DWR 131+ if (rc == SQLITE_NOTADB || rc == SQLITE_CORRUPT) { 132+ int rc1 = MetaDwrRecoverAndBeginTran(p, wrflag, pSchemaVersion); 133+ rc = (rc1 == SQLITE_OK) ? SQLITE_OK : rc; 134+ } 135+#endif 136 btreeIntegrity(p); 137 sqlite3BtreeLeave(p); 138 return rc; 139@@ -74687,6 +74742,9 @@ SQLITE_PRIVATE int sqlite3BtreeIncrVacuum(Btree *p){ 140 if( rc==SQLITE_OK ){ 141 rc = sqlite3PagerWrite(pBt->pPage1->pDbPage); 142 put4byte(&pBt->pPage1->aData[28], pBt->nPage); 143+#ifdef SQLITE_META_DWR 144+ MetaDwrCheckVacuum(pBt); 145+#endif 146 } 147 }else{ 148 rc = SQLITE_DONE; 149@@ -74771,6 +74829,9 @@ static int autoVacuumCommit(Btree *p){ 150 put4byte(&pBt->pPage1->aData[28], nFin); 151 pBt->bDoTruncate = 1; 152 pBt->nPage = nFin; 153+#ifdef SQLITE_META_DWR 154+ MetaDwrCheckVacuum(pBt); 155+#endif 156 } 157 if( rc!=SQLITE_OK ){ 158 sqlite3PagerRollback(pPager); 159@@ -74827,6 +74888,9 @@ SQLITE_PRIVATE int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zSuperJrnl){ 160 if( pBt->bDoTruncate ){ 161 sqlite3PagerTruncateImage(pBt->pPager, pBt->nPage); 162 } 163+#endif 164+#ifdef SQLITE_META_DWR 165+ (void)MetaDwrUpdateMetaPages(p); 166 #endif 167 rc = sqlite3PagerCommitPhaseOne(pBt->pPager, zSuperJrnl, 0); 168 sqlite3BtreeLeave(p); 169@@ -80898,6 +80962,11 @@ SQLITE_PRIVATE int sqlite3BtreeUpdateMeta(Btree *p, int idx, u32 iMeta){ 170 assert( iMeta==0 || iMeta==1 ); 171 pBt->incrVacuum = (u8)iMeta; 172 } 173+#endif 174+#ifdef SQLITE_META_DWR 175+ if (idx == 1 && pBt->pPager->metaFd) { 176+ pBt->pPager->metaChanged = META_SCHEMA_CHANGED; 177+ } 178 #endif 179 } 180 sqlite3BtreeLeave(p); 181@@ -82544,7 +82613,12 @@ SQLITE_API int sqlite3_backup_step(sqlite3_backup *p, int nPage){ 182 sqlite3PagerTruncateImage(pDestPager, nDestTruncate); 183 rc = sqlite3PagerCommitPhaseOne(pDestPager, 0, 0); 184 } 185- 186+ #ifdef SQLITE_META_DWR 187+ if (rc == SQLITE_OK && p->pDest->pBt->pPager->metaFd) { 188+ p->pDest->pBt->pPager->metaChanged = META_SCHEMA_CHANGED; 189+ (void)MetaDwrUpdateMetaPages(p->pDest); 190+ } 191+ #endif 192 /* Finish committing the transaction to the destination database. */ 193 if( SQLITE_OK==rc 194 && SQLITE_OK==(rc = sqlite3BtreeCommitPhaseTwo(p->pDest, 0)) 195@@ -138957,7 +139031,12 @@ SQLITE_PRIVATE void sqlite3Pragma( 196 } 197 #endif 198 /* END CODEC */ 199- 200+#ifdef SQLITE_META_DWR 201+ if(PragmaMetaDoubleWrie(db, iDb, pParse, zLeft, zRight)) { 202+ /* PragmaMetaDoubleWrie executes internal */ 203+ goto pragma_out; 204+ } 205+#endif 206 /* Locate the pragma in the lookup table */ 207 pPragma = pragmaLocate(zLeft); 208 if( pPragma==0 ){ 209@@ -180709,6 +180788,10 @@ SQLITE_PRIVATE const char *sqlite3ErrStr(int rc){ 210 zErr = "no more rows available"; 211 break; 212 } 213+ case SQLITE_META_RECOVERED: { 214+ zErr = "warning meta recover message"; 215+ break; 216+ } 217 default: { 218 rc &= 0xff; 219 if( ALWAYS(rc>=0) && rc<ArraySize(aMsg) && aMsg[rc]!=0 ){ 220@@ -254918,7 +255001,1070 @@ export_finish: 221 } 222 /************** End file hw_codec.c *****************************************/ 223 #endif 224+#ifdef SQLITE_META_DWR 225+#define META_DWR_MAX_PAGES 500 226+#define META_DWR_MAGIC 0x234A86D9 227+#define META_DWR_VERSION 0x00000001 228+#define META_DWR_INVALID_ZONE 0x55 229+#define META_DWR_HEADER_PAGE_SIZE 4096 230+#define META_DWR_HEADER_DEFAULT_PAGE_CNT 8 231+typedef struct ScanPages { 232+ u32 pageCnt; 233+ u32 pageBufSize; 234+ u32 maxPageNo; 235+ Pgno *pages; 236+} ScanPages; 237+ 238+typedef struct MetaDwrHdr { 239+ u32 magic; 240+ u32 version; 241+ u32 dbSize; 242+ u32 mxFrameInWal; 243+ u32 freeListPageNo; 244+ u32 freeListPageCnt; 245+ u32 schemaCookie; 246+ u32 pageSz; 247+ u32 pageCnt; 248+ u64 dbFileInode; 249+ u32 reserved[12]; 250+ u32 checkSum; 251+ u8 *zones; 252+ Pgno *pages; 253+ u32 pageBufSize; 254+ u8 hdrValid; 255+ u8 checkFileId; 256+ u16 needSync; 257+ i64 lastSyncTime; 258+} MetaDwrHdr; 259+ 260+#define META_VERIFIED_HDR_LEN (offsetof(MetaDwrHdr, zones)) 261+#define META_ZONES_LENGTH (META_DWR_MAX_PAGES * sizeof(u8)) 262+#define META_PAGE_NO_OFFSET (META_VERIFIED_HDR_LEN + META_ZONES_LENGTH) 263+#define META_FILE_UPDATE_TIMES_PER_SYNC 100 // sync once for every 100 update 264+#define META_FILE_SYNC_TIMEOUT_MS 30000 // 30 seconds 265+ 266+static int MetaDwrHeaderSimpleCheck(Pager *pPager, MetaDwrHdr *hdr) { 267+#if SQLITE_OS_UNIX 268+ if (hdr->checkFileId) { 269+ unixFile *fd = (unixFile *)pPager->fd; 270+ if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL) { 271+ return SQLITE_INTERNAL; 272+ } 273+ if (fd->pInode->fileId.ino != hdr->dbFileInode) { 274+ sqlite3_log(SQLITE_IOERR_DATA, "Ino mismatch file %llu dwr file %llu", 275+ fd->pInode->fileId.ino, hdr->dbFileInode); 276+ return SQLITE_IOERR_DATA; 277+ } 278+ } 279+#endif 280+ if (hdr->pageCnt > META_DWR_MAX_PAGES || hdr->version != META_DWR_VERSION || 281+ hdr->magic != META_DWR_MAGIC || hdr->checkSum != META_DWR_MAGIC) { 282+ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageCnt %u, version %u, magic %u, checkSum %u", 283+ hdr->pageCnt, hdr->version, hdr->magic, hdr->checkSum); 284+ return SQLITE_IOERR_DATA; 285+ } 286+ if (hdr->pageSz != pPager->pageSize) { 287+ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file check wrong pageSz %u-%u", hdr->pageSz, pPager->pageSize); 288+ return SQLITE_IOERR_DATA; 289+ } 290+ return SQLITE_OK; 291+} 292+ 293+static int PragmaMetaDoubleWrie(sqlite3 *db, int iDb, Parse *parse, const char *zLeft, const char *zRight) { 294+ Btree *pBt = db->aDb[iDb].pBt; 295+ if (pBt == NULL || zLeft == NULL || sqlite3StrICmp(zLeft, "meta_double_write") != 0) { 296+ return 0; 297+ } 298+ Pager *pPager = pBt->pBt->pPager; 299+ if (pPager == NULL) { 300+ sqlite3_log(SQLITE_WARNING_DUMP, "Invalid pager handle"); 301+ return 1; 302+ } 303+ if (zRight == NULL) { 304+ Vdbe *v = sqlite3GetVdbe(parse); 305+ sqlite3VdbeSetNumCols(v, 1); 306+ sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "meta_double_write", SQLITE_STATIC); 307+ sqlite3VdbeAddOp4(v, OP_String8, 0, 1, 0, pPager->metaFd ? "enabled" : "disabled", 0); 308+ sqlite3VdbeAddOp2(v, OP_ResultRow, 1, 1); 309+ } else if (strncmp(zRight, "enabled", 7) == 0) { 310+ sqlite3_mutex_enter(db->mutex); 311+ // only support enabled meta double write 312+ int rc = MetaDwrOpenAndCheck(pBt); 313+ if (rc != SQLITE_OK && rc != SQLITE_PERM) { 314+ parse->nErr++; 315+ parse->rc = rc; 316+ } 317+ sqlite3_mutex_leave(db->mutex); 318+ } else if (strncmp(zRight, "disabled", 8) == 0) { 319+ sqlite3_mutex_enter(db->mutex); 320+ MetaDwrDisable(pBt); 321+ sqlite3_mutex_leave(db->mutex); 322+ } 323+ return 1; 324+} 325+ 326+static int GetBtreePageNo(MemPage *pPage, void *args) { 327+ ScanPages *pInfo = (ScanPages *)args; 328+ // realloc buffer to store pages 329+ u32 pageCnt = pInfo->pageCnt; 330+ if (pageCnt == pInfo->pageBufSize) { 331+ u32 memSz = sizeof(Pgno) * ROUND8(pageCnt + 1); 332+ Pgno *pages = sqlite3Malloc(memSz); 333+ if (pages == NULL) { 334+ sqlite3_log(SQLITE_NOMEM, "GetPages alloc buffer go wrong %u", memSz); 335+ return SQLITE_NOMEM; 336+ } 337+ if (pageCnt != 0) { 338+ memcpy(pages, pInfo->pages, pageCnt * sizeof(Pgno)); 339+ } 340+ sqlite3_free(pInfo->pages); 341+ pInfo->pageBufSize = ROUND8(pageCnt + 1); 342+ pInfo->pages = pages; 343+ } 344+ pInfo->pages[pageCnt] = pPage->pgno; 345+ pInfo->pageCnt++; 346+ if (pInfo->maxPageNo < pPage->pgno) { 347+ pInfo->maxPageNo = pPage->pgno; 348+ } 349+ return 0; 350+} 351+ 352+typedef int (*ScanFn)(MemPage *pPage, void *args); 353+static SQLITE_NOINLINE int ScanOverflowPages( 354+ MemPage *pPage, /* The page that contains the Cell */ 355+ unsigned char *pCell, /* First byte of the Cell */ 356+ CellInfo *pInfo, /* Size information about the cell */ 357+ ScanFn fn, /* Scan pages function */ 358+ void *args) { 359+ BtShared *pBt; 360+ Pgno ovflPgno; 361+ int rc; 362+ int nOvfl; 363+ u32 ovflPageSize; 364+ 365+ if (pCell + pInfo->nSize > pPage->aDataEnd) { 366+ /* Cell extends past end of page */ 367+ return SQLITE_CORRUPT_BKPT; 368+ } 369+ ovflPgno = get4byte(pCell + pInfo->nSize - 4); 370+ pBt = pPage->pBt; 371+ assert(pBt->usableSize > 4); 372+ ovflPageSize = pBt->usableSize - 4; 373+ nOvfl = (pInfo->nPayload - pInfo->nLocal + ovflPageSize - 1) / ovflPageSize; 374+ assert(nOvfl > 0 || 375+ (CORRUPT_DB && (pInfo->nPayload + ovflPageSize) < ovflPageSize)); 376+ while (nOvfl > 0) { 377+ nOvfl--; 378+ Pgno iNext = 0; 379+ MemPage *pOvfl = 0; 380+ if (ovflPgno < 2 || ovflPgno > btreePagecount(pBt)) { 381+ sqlite3_log(SQLITE_WARNING_DUMP, "Ignore for ovfl page not as expect, pgno %u ovflPgno %u novfl %d payload %u local %u", 382+ pPage->pgno, ovflPgno, nOvfl, pInfo->nPayload, pInfo->nLocal); 383+ return SQLITE_MISUSE; 384+ } 385+ rc = getOverflowPage(pBt, ovflPgno, &pOvfl, &iNext); 386+ if (rc) 387+ return rc; 388+ if (pOvfl) { 389+ rc = fn(pOvfl, args); 390+ if (rc) { 391+ return rc; 392+ } 393+ sqlite3PagerUnref(pOvfl->pDbPage); 394+ } 395+ ovflPgno = iNext; 396+ } 397+ return SQLITE_OK; 398+} 399+ 400+static int ScanBtreePage( 401+ BtShared *pBt, /* The BTree that contains the table */ 402+ Pgno pgno, /* Page number to clear */ 403+ ScanFn fn, /* Scan pages function */ 404+ void *args) { /* Scan pages args */ 405+ MemPage *pPage; 406+ int rc; 407+ unsigned char *pCell; 408+ int i; 409+ int hdr; 410+ CellInfo info; 411+ 412+ assert(sqlite3_mutex_held(pBt->mutex)); 413+ if (pgno > btreePagecount(pBt)) { 414+ return SQLITE_OK; 415+ } 416+ rc = getAndInitPage(pBt, pgno, &pPage, 0); 417+ if (rc) { 418+ return rc; 419+ } 420+ rc = fn(pPage, args); 421+ if (rc) { 422+ goto SCAN_PAGE_OUT; 423+ } 424+ hdr = pPage->hdrOffset; 425+ for (i = pPage->nCell - 1; i >= 0; i--) { 426+ pCell = findCell(pPage, i); 427+ if (!pPage->leaf) { 428+ rc = ScanBtreePage(pBt, get4byte(pCell), fn, args); 429+ if (rc) { 430+ goto SCAN_PAGE_OUT; 431+ } 432+ } 433+ pPage->xParseCell(pPage, pCell, &info); 434+ if (info.nLocal < info.nPayload) { 435+ rc = ScanOverflowPages(pPage, pCell, &info, fn, args); 436+ if (rc) { 437+ goto SCAN_PAGE_OUT; 438+ } 439+ } 440+ } 441+ if (!pPage->leaf) { 442+ rc = ScanBtreePage(pBt, get4byte(&pPage->aData[hdr + 8]), fn, args); 443+ if (rc) { 444+ goto SCAN_PAGE_OUT; 445+ } 446+ } 447+SCAN_PAGE_OUT: 448+ releasePage(pPage); 449+ return rc; 450+} 451+ 452+static inline int ScanMetaPages(Btree *pBt, ScanPages *pages) { 453+ return ScanBtreePage(pBt->pBt, 1, GetBtreePageNo, pages); 454+} 455+ 456+static int ReleaseMetaPages(ScanPages *pages) { 457+ sqlite3_free(pages->pages); 458+ pages->pages = NULL; 459+ return SQLITE_OK; 460+} 461+ 462+static void InitMetaHeader(MetaDwrHdr *hdr) { 463+ (void)memset(hdr, 0, META_VERIFIED_HDR_LEN); 464+ hdr->magic = META_DWR_MAGIC; 465+ hdr->version = META_DWR_VERSION; 466+ hdr->checkSum = META_DWR_MAGIC; 467+} 468+ 469+static void MetaDwrReleaseHdr(MetaDwrHdr *hdr) { 470+ if (!hdr) { 471+ return; 472+ } 473+ sqlite3_free(hdr->zones); 474+ sqlite3_free(hdr); 475+} 476+ 477+static int ExpandMetaPageBuf(MetaDwrHdr *hdr, u32 minimalPageCnt, u32 bufHasData) { 478+ if (minimalPageCnt < hdr->pageBufSize && hdr->zones != NULL) { 479+ return SQLITE_OK; 480+ } 481+ int pageBufSz = ROUND8(MAX(hdr->pageCnt, minimalPageCnt)); 482+ u8 *zones = (u8 *)sqlite3Malloc(pageBufSz * (sizeof(u8) + sizeof(Pgno))); 483+ if (zones == NULL) { 484+ return SQLITE_NOMEM_BKPT; 485+ } 486+ Pgno *pgnos = (Pgno *)(zones + pageBufSz); 487+ if (hdr->zones != NULL) { 488+ if (bufHasData && hdr->pageCnt > 0) { 489+ (void)memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); 490+ (void)memcpy(pgnos, hdr->pages, hdr->pageCnt * sizeof(Pgno)); 491+ } 492+ sqlite3_free(hdr->zones); 493+ } 494+ hdr->pageBufSize = pageBufSz; 495+ hdr->zones = zones; 496+ hdr->pages = pgnos; 497+ return SQLITE_OK; 498+} 499+ 500+static MetaDwrHdr *AllocInitMetaHeaderDwr(Pager *pPager) { 501+ MetaDwrHdr *hdr = sqlite3MallocZero(sizeof(MetaDwrHdr)); 502+ if (hdr == NULL) { 503+ return NULL; 504+ } 505+ InitMetaHeader(hdr); 506+ int rc = ExpandMetaPageBuf(hdr, META_DWR_HEADER_DEFAULT_PAGE_CNT, 0); 507+ if (rc != SQLITE_OK) { 508+ MetaDwrReleaseHdr(hdr); 509+ return NULL; 510+ } 511+ hdr->checkFileId = (pPager->pVfs != NULL && sqlite3_stricmp(pPager->pVfs->zName, "unix") == 0); 512+ return hdr; 513+} 514+ 515+static void MetaDwrCloseFile(Pager *pPager) { 516+ if (!pPager->metaFd) { 517+ return; 518+ } 519+#if SQLITE_OS_UNIX 520+ if (pPager->metaMapPage) { 521+ osMunmap(pPager->metaMapPage, META_DWR_HEADER_PAGE_SIZE); 522+ pPager->metaMapPage = NULL; 523+ } 524+#endif 525+ if (pPager->metaHdr && pPager->metaHdr->needSync > 0) { 526+ (void)sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); 527+ } 528+ sqlite3OsClose(pPager->metaFd); 529+} 530+ 531+static void MetaDwrPagerRelease(Pager *pPager) { 532+ MetaDwrCloseFile(pPager); 533+ MetaDwrReleaseHdr(pPager->metaHdr); 534+ pPager->metaHdr = NULL; 535+ if (pPager->metaFd) { 536+ sqlite3_free(pPager->metaFd); 537+ pPager->metaFd = NULL; 538+ } 539+} 540+ 541+static inline int ReadFromHdrPage(Pager *pPager, void *data, int amt, i64 offset) { 542+ if (pPager->metaMapPage) { 543+ (void)memcpy(data, (u8 *)pPager->metaMapPage + offset, amt); 544+ return SQLITE_OK; 545+ } 546+ return sqlite3OsRead(pPager->metaFd, data, amt, offset); 547+} 548+ 549+static int MetaDwrReadHeader(Pager *pPager, MetaDwrHdr *hdr) { 550+ i64 sz = 0; 551+ int rc = sqlite3OsFileSize(pPager->metaFd, &sz); 552+ if (rc != SQLITE_OK) { 553+ sqlite3_log(rc, "Meta dwr file size go wrong"); 554+ return rc; 555+ } 556+ if (sz <= META_DWR_HEADER_PAGE_SIZE) { 557+ rc = SQLITE_IOERR_DATA; 558+ goto READ_META_OUT; 559+ } 560+ rc = ReadFromHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); 561+ if (rc != SQLITE_OK) { 562+ sqlite3_log(rc, "Meta dwr file header read wrong"); 563+ goto READ_META_OUT; 564+ } 565+ rc = MetaDwrHeaderSimpleCheck(pPager, hdr); 566+ if (rc != SQLITE_OK) { 567+ goto READ_META_OUT; 568+ } 569+ // avoid realloc buffer if buf can't hold all pages 570+ rc = ExpandMetaPageBuf(hdr, hdr->pageCnt, 0); 571+ if (rc != SQLITE_OK) { 572+ goto READ_META_OUT; 573+ } 574+ int zoneSize = hdr->pageCnt * sizeof(u8); 575+ rc = ReadFromHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); 576+ if (rc != SQLITE_OK) { 577+ goto READ_META_OUT; 578+ } 579+ rc = ReadFromHdrPage(pPager, hdr->pages, hdr->pageCnt * sizeof(Pgno), META_PAGE_NO_OFFSET); 580+ if (rc != SQLITE_OK) { 581+ goto READ_META_OUT; 582+ } 583+ for (u32 i = 0; i < hdr->pageCnt; i++) { 584+ u8 zoneIdx = hdr->zones[i]; 585+ if (zoneIdx != 0 && zoneIdx != 1 && zoneIdx != META_DWR_INVALID_ZONE) { 586+ sqlite3_log(SQLITE_IOERR_DATA, "Invalid zoneIdx %d", zoneIdx); 587+ rc = SQLITE_IOERR_DATA; 588+ break; 589+ } 590+ } 591+READ_META_OUT: 592+ if (rc == SQLITE_IOERR_DATA) { 593+ InitMetaHeader(hdr); 594+ rc = SQLITE_OK; 595+ } 596+ return rc; 597+} 598+ 599+static inline u64 CaculateMetaDwrWriteOffset(int pageSz, u32 idx, u8 zone) { 600+ // 1 header page, idx correspond 2 zone pages 601+ return META_DWR_HEADER_PAGE_SIZE + pageSz * (idx * 2 + zone); 602+} 603+ 604+static void MetaDwrUpdateHeaderDbInfo(BtShared *pBt) { 605+ MetaDwrHdr *hdr = pBt->pPager->metaHdr; 606+ // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie 607+ const u8 *dbHdrInfo = &pBt->pPage1->aData[28]; 608+ hdr->dbSize = sqlite3Get4byte(dbHdrInfo); 609+#ifndef SQLITE_OMIT_WAL 610+ if (pagerUseWal(pBt->pPager)) { 611+ WalIndexHdr *pWalHdr = &pBt->pPager->pWal->hdr; 612+ if (pWalHdr->isInit) { 613+ hdr->mxFrameInWal = pWalHdr->mxFrame; 614+ hdr->dbSize = pWalHdr->nPage; 615+ } 616+ } else { 617+ hdr->mxFrameInWal = 0; 618+ } 619+#endif 620+#if SQLITE_OS_UNIX 621+ if (hdr->checkFileId) { 622+ unixFile *fd = (unixFile *)pBt->pPager->fd; 623+ if (fd == NULL || fd->pInode == NULL) { 624+ sqlite3_log(SQLITE_WARNING_DUMP, "update meta header invalid fd"); 625+ hdr->hdrValid = 0; 626+ return; 627+ } 628+ hdr->dbFileInode = fd->pInode->fileId.ino; 629+ } 630+#endif 631+ hdr->freeListPageNo = sqlite3Get4byte(dbHdrInfo + 4); 632+ hdr->freeListPageCnt = sqlite3Get4byte(dbHdrInfo + 8); 633+ hdr->schemaCookie = sqlite3Get4byte(dbHdrInfo + 12); 634+ hdr->hdrValid = 1; 635+} 636+ 637+static inline int WriteToHdrPage(Pager *pPager, const void *data, int amt, i64 offset) { 638+ if (pPager->metaMapPage) { 639+ (void)memcpy((u8 *)pPager->metaMapPage + offset, data, amt); 640+ return SQLITE_OK; 641+ } 642+ return sqlite3OsWrite(pPager->metaFd, data, amt, offset); 643+} 644+ 645+static int MetaDwrWriteHeader(Pager *pPager, MetaDwrHdr *hdr) { 646+ if (pPager->metaChanged == 0 || hdr == NULL || hdr->pageCnt == 0 || hdr->hdrValid == 0) { 647+ return SQLITE_OK; 648+ } 649+ hdr->hdrValid = 0; 650+ hdr->pageSz = pPager->pageSize; 651+ hdr->dbSize = pPager->dbSize; 652+ int rc = WriteToHdrPage(pPager, hdr, META_VERIFIED_HDR_LEN, 0); 653+ if (rc != SQLITE_OK) { 654+ sqlite3_log(rc, "update meta header write hdr %u wrong", META_VERIFIED_HDR_LEN); 655+ return rc; 656+ } 657+ if (hdr->zones) { 658+ int zoneSize = hdr->pageCnt * sizeof(u8); 659+ rc = WriteToHdrPage(pPager, hdr->zones, zoneSize, META_VERIFIED_HDR_LEN); 660+ if (rc != SQLITE_OK) { 661+ sqlite3_log(rc, "update meta header write zonebuf %u wrong", zoneSize); 662+ return rc; 663+ } 664+ } 665+ if (hdr->pages) { 666+ int pageBufSz = hdr->pageCnt * sizeof(Pgno); 667+ rc = WriteToHdrPage(pPager, hdr->pages, pageBufSz, META_PAGE_NO_OFFSET); 668+ if (rc != SQLITE_OK) { 669+ sqlite3_log(rc, "update meta header write pagebuf %u wrong", pageBufSz); 670+ } 671+ } 672+ if (rc == SQLITE_OK) { 673+ u64 size = CaculateMetaDwrWriteOffset((int)pPager->pageSize, hdr->pageCnt, 0); 674+ rc = sqlite3OsTruncate(pPager->metaFd, size); 675+ if (rc != SQLITE_OK) { 676+ sqlite3_log(rc, "update meta header truncate filesz %lu wrong", size); 677+ } 678+ i64 timeMs = 0; 679+ sqlite3OsCurrentTimeInt64(pPager->pVfs, &timeMs); 680+ if ((timeMs - hdr->lastSyncTime) > META_FILE_SYNC_TIMEOUT_MS || 681+ hdr->needSync >= META_FILE_UPDATE_TIMES_PER_SYNC) { 682+ rc = sqlite3OsSync(pPager->metaFd, SQLITE_SYNC_NORMAL); 683+ if (rc != SQLITE_OK) { 684+ sqlite3_log(rc, "update meta header sync filesz %lu wrong", size); 685+ } 686+ hdr->lastSyncTime = timeMs; 687+ hdr->needSync = 0; 688+ } else { 689+ hdr->needSync++; 690+ } 691+ } 692+ return rc; 693+} 694+ 695+static int MetaDwrFindPageIdx(MetaDwrHdr *hdr, u32 pgno, u32 *idx) { 696+ for (u32 i = 0; i < hdr->pageCnt && i < META_DWR_MAX_PAGES; i++) { 697+ if (pgno == hdr->pages[i]) { 698+ *idx = i; 699+ return 1; 700+ } 701+ } 702+ return 0; 703+} 704+ 705+static int MetaDwrWriteOnePage(Btree *pBt, PgHdr *pPage, MetaDwrHdr *hdr, u8 curZones, u32 idx) { 706+ int rc = SQLITE_OK; 707+ u8 pageExpand = 0; 708+ if (hdr->pageCnt <= idx) { 709+ rc = ExpandMetaPageBuf(hdr, idx + 1, 1); 710+ if (rc != SQLITE_OK) { 711+ return rc; 712+ } 713+ pageExpand = 1; 714+ } 715+ Pager *pPager = pBt->pBt->pPager; 716+ // asume zone 0 or 1 717+ u8 zone = 1 - curZones; 718+ int pageSz = sqlite3BtreeGetPageSize(pBt); 719+ u64 ofs = CaculateMetaDwrWriteOffset(pageSz, idx, zone); 720+ void *pData; 721+#if defined(SQLITE_HAS_CODEC) 722+ if ((pData = sqlite3PagerCodec(pPage)) == 0) 723+ return SQLITE_NOMEM; 724+#else 725+ pData = pPage->pData; 726+#endif 727+ rc = sqlite3OsWrite(pPager->metaFd, pData, pageSz, ofs); 728+ if (rc != SQLITE_OK) { 729+ return rc; 730+ } 731+ hdr->zones[idx] = zone; 732+ hdr->pages[idx] = pPage->pgno; 733+ if (pageExpand) { 734+ hdr->pageCnt++; 735+ } 736+ return SQLITE_OK; 737+} 738+ 739+static int MetaDwrRestoreAllPages(Btree *pBt, const ScanPages *metaPages, MetaDwrHdr *hdr) { 740+ u32 i = 0; 741+ PgHdr *p = NULL; 742+ int rc = SQLITE_OK; 743+ for (i = 0; i < metaPages->pageCnt && i < META_DWR_MAX_PAGES; i++) { 744+ Pgno pgno = metaPages->pages[i]; 745+ if (pgno > btreePagecount(pBt->pBt)) { 746+ sqlite3_log(SQLITE_WARNING_DUMP, "pageno %d overlimit", pgno); 747+ return SQLITE_CORRUPT_BKPT; 748+ } 749+ rc = sqlite3PagerGet(pBt->pBt->pPager, pgno, &p, 0); 750+ if (rc) { 751+ return rc; 752+ } 753+ rc = MetaDwrWriteOnePage(pBt, p, hdr, 1, i); 754+ sqlite3PagerUnref(p); 755+ if (rc) { 756+ return rc; 757+ } 758+ } 759+ hdr->pageCnt = metaPages->pageCnt; 760+ MetaDwrUpdateHeaderDbInfo(pBt->pBt); 761+ return rc; 762+} 763+ 764+static inline const char *GetMetaFilePath(Pager *pPager) 765+{ 766+ return pPager->metaFd == NULL ? NULL : ((const char *)pPager->metaFd + ROUND8(pPager->pVfs->szOsFile)); 767+} 768+ 769+static int MetaDwrCheckPerm(sqlite3_vfs *pVfs, u8 openCreate, char *metaPath) { 770+ int exists = 0; 771+ int rc = sqlite3OsAccess(pVfs, metaPath, SQLITE_ACCESS_EXISTS, &exists); 772+ if (rc != SQLITE_OK) { 773+ return rc; 774+ } 775+ if (!exists && !openCreate) { 776+ return SQLITE_PERM; 777+ } 778+#ifdef OS_FEATURE 779+ // check if the path have enough permission 780+ rc = osAccess(metaPath, W_OK|R_OK); 781+ if (rc == 0 || errno == ENOENT) { 782+ return SQLITE_OK; 783+ } 784+ rc = SQLITE_PERM; 785+ if (openCreate) { 786+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta double write disabled, sysno %d", errno); 787+ } 788+#endif 789+ return rc; 790+} 791+ 792+static int MetaDwrOpenFile(Pager *pPager, u8 openCreate) { 793+ if (pPager->metaFd || pPager->zFilename == NULL) { 794+ return SQLITE_OK; 795+ } 796+ sqlite3BeginBenignMalloc(); 797+ sqlite3_vfs *pVfs = pPager->pVfs; 798+ int size = strlen(pPager->zFilename) + sizeof("-dwr"); 799+ int szOsFile = ROUND8(pVfs->szOsFile); 800+ sqlite3_file *metaFd = (sqlite3_file *)sqlite3MallocZero(szOsFile + size); 801+ char *metaPath = (char *)metaFd + szOsFile; 802+ if (metaFd == NULL) { 803+ sqlite3EndBenignMalloc(); 804+ sqlite3_log(SQLITE_NOMEM_BKPT, "sqlite alloc memsize %d go wrong", szOsFile + size); 805+ return SQLITE_NOMEM_BKPT; 806+ } 807+ sqlite3_snprintf(size, metaPath, "%s-dwr", pPager->zFilename); 808+ int rc = MetaDwrCheckPerm(pVfs, openCreate, metaPath); 809+ if (rc != SQLITE_OK) { 810+ goto INIT_META_OUT; 811+ } 812+ u32 flags = (SQLITE_OPEN_READWRITE | SQLITE_OPEN_SUPER_JOURNAL); 813+ if (openCreate) { 814+ flags |= SQLITE_OPEN_CREATE; 815+ } 816+ rc = sqlite3OsOpen(pVfs, metaPath, metaFd, (int)flags, 0); 817+ if (rc != SQLITE_OK) { 818+ goto INIT_META_OUT; 819+ } 820+#if SQLITE_OS_UNIX 821+ if (pPager->metaMapPage == NULL) { 822+ sqlite3_int64 sz = META_DWR_HEADER_PAGE_SIZE; 823+ sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_CHUNK_SIZE, &sz); 824+ sqlite3OsFileControlHint(metaFd, SQLITE_FCNTL_SIZE_HINT, &sz); 825+ void *page = osMmap(0, META_DWR_HEADER_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, 826+ ((unixFile *)metaFd)->h, 0); 827+ if (page != MAP_FAILED) { 828+ pPager->metaMapPage = page; 829+ } 830+ } 831+#endif 832+ pPager->metaFd = metaFd; 833+INIT_META_OUT: 834+ sqlite3EndBenignMalloc(); 835+ if (rc != SQLITE_OK && metaFd != NULL) { 836+ sqlite3_free(metaFd); 837+ } 838+ return rc; 839+} 840+ 841+void MetaDwrCheckVacuum(BtShared *pBt) { 842+ if (!pBt || !pBt->pPager->metaFd) { 843+ return; 844+ } 845+ if (pBt->nPage < pBt->maxMetaPage) { 846+ pBt->pPager->metaChanged = META_SCHEMA_CHANGED; 847+ } 848+} 849+ 850+static inline u8 LocalMetaHdrValid(Pager *pPager) { 851+ return pPager->metaMapPage != NULL && memcmp(pPager->metaMapPage, pPager->metaHdr, 852+ META_VERIFIED_HDR_LEN) == 0; 853+} 854+ 855+static int MetaDwrLoadHdr(Pager *pPager) { 856+ if (!pPager->metaHdr) { 857+ pPager->metaHdr = AllocInitMetaHeaderDwr(pPager); 858+ if (pPager->metaHdr == NULL) { 859+ return SQLITE_NOMEM_BKPT; 860+ } 861+ } 862+ if (LocalMetaHdrValid(pPager)) { 863+ return SQLITE_OK; 864+ } 865+ return MetaDwrReadHeader(pPager, pPager->metaHdr); 866+} 867+ 868+static int MetaDwrLoadAndCheckMetaFile(BtShared *pBt, u8 reportErr) { 869+ int rc = MetaDwrLoadHdr(pBt->pPager); 870+ if (rc != SQLITE_OK) { 871+ return rc; 872+ } 873+ MetaDwrHdr *hdr = pBt->pPager->metaHdr; 874+ if (hdr->pageCnt == 0) { 875+ return reportErr ? SQLITE_IOERR_DATA : SQLITE_OK; 876+ } 877+ // 28 offset: dbSize, freelist pageNo, freelist pages count, schema cookie 878+ u8 *dbHdrInfo = &pBt->pPage1->aData[28]; 879+ if (hdr->dbSize != pBt->pPager->dbSize || hdr->dbSize != sqlite3Get4byte(dbHdrInfo) || 880+ hdr->freeListPageNo != sqlite3Get4byte(dbHdrInfo + 4) || 881+ hdr->freeListPageCnt != sqlite3Get4byte(dbHdrInfo + 8) || 882+ hdr->schemaCookie != sqlite3Get4byte(dbHdrInfo + 12)) { 883+ sqlite3_log(SQLITE_IOERR_DATA, "Meta dwr file expect %u-%u-%u-%u-%u but gotton %u-%u-%u-%u-%u", 884+ pBt->pPager->dbSize, hdr->dbSize, sqlite3Get4byte(dbHdrInfo), sqlite3Get4byte(dbHdrInfo + 4), 885+ sqlite3Get4byte(dbHdrInfo + 8), sqlite3Get4byte(dbHdrInfo + 12), hdr->dbSize, hdr->freeListPageNo, 886+ hdr->freeListPageCnt, hdr->schemaCookie); 887+ // reinit 888+ InitMetaHeader(hdr); 889+ if (reportErr) { 890+ return SQLITE_IOERR_DATA; 891+ } 892+ } 893+ return SQLITE_OK; 894+} 895+ 896+static int MetaDwrReadOnePage(Pager *pPager, MetaDwrHdr *hdr, int idx, u8 *pData) { 897+ u64 ofs = CaculateMetaDwrWriteOffset(pPager->pageSize, idx, hdr->zones[idx]); 898+ int rc = sqlite3OsRead(pPager->metaFd, pData, pPager->pageSize, ofs); 899+ CODEC1(pPager, pData, hdr->pages[idx], 3, rc = SQLITE_NOMEM_BKPT); 900+ return rc; 901+} 902+ 903+static int MetaDwrRecoverHeadPage( 904+ Pager *pPager, /* The pager open on the database file */ 905+ Pgno pgno, /* Page number to fetch */ 906+ DbPage **pDbPage, 907+ int flag) { 908+ if (pPager->metaFd == NULL) { 909+ return pgno == 1 ? SQLITE_NOTADB : SQLITE_CORRUPT; 910+ } 911+ sqlite3_pcache_page *pCachePage = sqlite3PcacheFetch(pPager->pPCache, pgno, 3); 912+ if (pCachePage == NULL) { 913+ sqlite3_log(SQLITE_NOMEM_BKPT, "Get meta page wrong %d", pgno); 914+ return SQLITE_NOMEM_BKPT; 915+ } 916+ DbPage *pPage = sqlite3PcacheFetchFinish(pPager->pPCache, pgno, pCachePage); 917+ pPage->pPager = pPager; 918+ assert(pCachePage != 0); 919+ int rc = MetaDwrLoadHdr(pPager); 920+ if (rc != SQLITE_OK) { 921+ goto RELEASE_OUT; 922+ } 923+ MetaDwrHdr *hdr = pPager->metaHdr; 924+ u8 walChecked = 0; 925+#ifndef SQLITE_OMIT_WAL 926+ if (pagerUseWal(pPager)) { 927+ WalIndexHdr *pWalHdr = &pPager->pWal->hdr; 928+ if (pWalHdr->isInit && pWalHdr->mxFrame != 0) { 929+ if (hdr->mxFrameInWal != pWalHdr->mxFrame || hdr->dbSize != pWalHdr->nPage) { 930+ rc = SQLITE_NOTADB; 931+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr wal hdr expect %u-%u but gotten %u-%u", 932+ hdr->mxFrameInWal, hdr->dbSize, pWalHdr->mxFrame, pWalHdr->nPage); 933+ goto RELEASE_OUT; 934+ } else { 935+ walChecked = 1; 936+ } 937+ } 938+ } 939+ if (walChecked == 0) { 940+ i64 size = 0; 941+ rc = sqlite3OsFileSize(pPager->fd, &size); 942+ if (rc != SQLITE_OK) { 943+ rc = SQLITE_NOTADB; 944+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr get db file size go wrong"); 945+ goto RELEASE_OUT; 946+ } 947+ i64 expectSz = (i64)hdr->dbSize * (i64)hdr->pageSz; 948+ if (size != expectSz) { 949+ rc = SQLITE_NOTADB; 950+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta dwr expect file size %lu but gotten size %llu", 951+ expectSz, size); 952+ goto RELEASE_OUT; 953+ } 954+ } 955+#endif 956+ rc = SQLITE_NOTADB; 957+ for (u32 i = 0; i < hdr->pageCnt; i++) { 958+ if (hdr->pages[i] != pgno) { 959+ continue; 960+ } 961+ rc = MetaDwrReadOnePage(pPager, hdr, i, sqlite3PagerGetData(pPage)); 962+ if (rc == SQLITE_OK) { 963+ *pDbPage = pPage; 964+ if (pPage->pgno == 1) { 965+ memcpy(&pPager->dbFileVers, &((u8 *)pPage->pData)[24], sizeof(pPager->dbFileVers)); 966+ } 967+ pager_set_pagehash(pPage); 968+ } 969+ break; 970+ } 971+RELEASE_OUT: 972+ if (rc != SQLITE_OK && pPage != NULL) { 973+ sqlite3PcacheDrop(pPage); 974+ } 975+ return rc; 976+} 977+ 978+static int MetaDwrRestoreChangedPages(Btree *pBt) { 979+ Pager *pPager = pBt->pBt->pPager; 980+ MetaDwrHdr *hdr = pPager->metaHdr; 981+ u8 *zones = sqlite3MallocZero(hdr->pageBufSize * sizeof(u8)); 982+ if (zones == NULL) { 983+ sqlite3_log(SQLITE_NOMEM_BKPT, "Alloc zones buffer size %u go wrong", hdr->pageBufSize * sizeof(u8)); 984+ return SQLITE_NOMEM_BKPT; 985+ } 986+ if (hdr->pageCnt > 0) { 987+ memcpy(zones, hdr->zones, hdr->pageCnt * sizeof(u8)); 988+ } 989+ u32 idx = 0; 990+ PgHdr *p = 0; 991+ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); 992+ int rc = SQLITE_OK; 993+ for (p = pList; p; p = p->pDirty) { 994+ if (MetaDwrFindPageIdx(hdr, p->pgno, &idx) == 0) { 995+ continue; 996+ } 997+ rc = MetaDwrWriteOnePage(pBt, p, hdr, zones[idx], idx); 998+ if (rc != SQLITE_OK) { 999+ break; 1000+ } 1001+ } 1002+ if (rc == SQLITE_OK) { 1003+ MetaDwrUpdateHeaderDbInfo(pBt->pBt); 1004+ } 1005+ sqlite3_free(zones); 1006+ return rc; 1007+} 1008+ 1009+static int MetaDwrUpdateMetaPages(Btree *pBt) { 1010+ Pager *pPager = pBt->pBt->pPager; 1011+ if (!pPager || !pPager->metaFd || pPager->memDb || pPager->readOnly || pBt->pBt->pPage1 == NULL) { 1012+ return SQLITE_OK; 1013+ } 1014+ if (pPager->metaChanged == 0) { 1015+ if ((pBt->pBt->pPage1->pDbPage->flags & PGHDR_DIRTY) == 0) { 1016+ return SQLITE_OK; 1017+ } 1018+ pPager->metaChanged = META_HEADER_CHANGED; 1019+ } 1020+ sqlite3BeginBenignMalloc(); 1021+ int rc = MetaDwrLoadHdr(pPager); 1022+ if (rc != SQLITE_OK) { 1023+ goto UPDATE_OUT; 1024+ } 1025+ // only update header page 1026+ if (pPager->metaChanged == META_HEADER_CHANGED) { 1027+ rc = MetaDwrRestoreChangedPages(pBt); 1028+ goto UPDATE_OUT; 1029+ } 1030+ // update schema pages 1031+ ScanPages metaPages = {0}; 1032+ rc = ScanMetaPages(pBt, &metaPages); 1033+ if (rc != SQLITE_OK) { 1034+ goto UPDATE_OUT; 1035+ } 1036+ MetaDwrHdr *hdr = pPager->metaHdr; 1037+ // rewrite 1038+ if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || pBt->pBt->nPage > pBt->pBt->maxMetaPage || 1039+ memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { 1040+ // if page numbers unorderred, restore all pages 1041+ rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); 1042+ } else { 1043+ rc = MetaDwrRestoreChangedPages(pBt); 1044+ } 1045+ if (rc == SQLITE_OK) { 1046+ pBt->pBt->maxMetaPage = metaPages.maxPageNo; 1047+ } 1048+ ReleaseMetaPages(&metaPages); 1049+UPDATE_OUT: 1050+ sqlite3EndBenignMalloc(); 1051+ return rc; 1052+} 1053+ 1054+static int MetaDwrRecoverSinglePage(Btree *pBt, int pgno, u8 *pData) { 1055+ if (pgno < 1 || pBt == NULL) { 1056+ return SQLITE_CORRUPT_BKPT; 1057+ } 1058+ Pager *pPager = sqlite3BtreePager(pBt); 1059+ DbPage *pDbPage = NULL; 1060+ int rc = sqlite3PagerGet(pPager, pgno, &pDbPage, 0); 1061+ if (rc) { 1062+ return rc; 1063+ } 1064+ if ((rc = sqlite3PagerWrite(pDbPage)) == SQLITE_OK) { 1065+ memcpy(sqlite3PagerGetData(pDbPage), pData, pPager->pageSize); 1066+ } else { 1067+ sqlite3_log(rc, "Dwr recoverwrite meta page %d failed", pgno); 1068+ } 1069+ sqlite3PagerUnref(pDbPage); 1070+ return rc; 1071+} 1072+ 1073+static int MetaDwrCheckMeta(Btree *pBt) { 1074+ int nErr = 0; 1075+ Pgno aRoot[2] = {0, 1}; // quick check and only check root btree 1076+ char *errStr = NULL; 1077+ int rc = sqlite3BtreeIntegrityCheck(pBt->db, pBt, &aRoot[0], 2, SQLITE_INTEGRITY_CHECK_ERROR_MAX, 1078+ &nErr, &errStr); 1079+ if (nErr == 0) { 1080+ assert(errStr == 0); 1081+ return SQLITE_OK; 1082+ } 1083+ if (rc != SQLITE_OK) { 1084+ sqlite3_log(rc, "Meta integrity check go wrong"); 1085+ return rc; 1086+ } 1087+ sqlite3_log(SQLITE_WARNING_DUMP, "Meta integrity check %s", errStr); 1088+ sqlite3DbFree(pBt->db, errStr); 1089+ return SQLITE_CORRUPT; 1090+} 1091+ 1092+static int MetaDwrBeginTrans(Btree *pBt, int wrflag) { 1093+ pBt->pBt->btsFlags &= ~BTS_READ_ONLY; 1094+ Pager *pPager = pBt->pBt->pPager; 1095+ void *xGetMethod = pPager->xGet; 1096+ pPager->xGetMethod = MetaDwrRecoverHeadPage; 1097+ pPager->xGet = MetaDwrRecoverHeadPage; 1098+ int rc = sqlite3BtreeBeginTrans(pBt, wrflag, 0); 1099+ pPager->xGet = xGetMethod; 1100+ pPager->xGetMethod = 0; 1101+ if (rc == SQLITE_OK) { 1102+ sqlite3PagerWrite(pBt->pBt->pPage1->pDbPage); 1103+ sqlite3_log(rc, "sqlite fix meta header"); 1104+ } 1105+ return rc; 1106+} 1107+ 1108+static int MetaDwrRecoverAndBeginTran(Btree *pBt, int wrflag, int *pSchemaVersion) 1109+{ 1110+ Pager *pPager = pBt->pBt->pPager; 1111+ assert(sqlite3_mutex_held(pBt->pBt->mutex)); 1112+ if (!pPager->metaFd || pBt->pBt->metaRecoverStatus || pPager->readOnly || pPager->memDb) { 1113+ return SQLITE_NOTADB; 1114+ } 1115+ int rc = MetaDwrLoadHdr(pPager); 1116+ if (rc != SQLITE_OK) { 1117+ sqlite3_log(rc, "MetaDwr load header failed"); 1118+ return rc; 1119+ } 1120+ pBt->pBt->metaRecoverStatus = META_IN_RECOVERY; 1121+ rc = MetaDwrBeginTrans(pBt, 2); 1122+ if (rc != SQLITE_OK) { 1123+ return rc; 1124+ } 1125+ void *pData = NULL; 1126+ pPager->metaChanged = META_HEADER_CHANGED; 1127+ MetaDwrHdr *hdr = pPager->metaHdr; 1128+ sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta recover %u frames", hdr->pageCnt); 1129+ int szPage = sqlite3BtreeGetPageSize(pBt); 1130+ pData = sqlite3Malloc(szPage); 1131+ if (pData == NULL) { 1132+ rc = SQLITE_NOMEM; 1133+ sqlite3_log(rc, "Dwr malloc mem size %d failed", szPage); 1134+ goto DWR_RECOVER_OUT; 1135+ } 1136+ for (u32 i = 0; i < hdr->pageCnt; i++) { 1137+ rc = MetaDwrReadOnePage(pPager, hdr, i, pData); 1138+ if (rc != SQLITE_OK) { 1139+ sqlite3_log(rc, "Dwr read %d meta page failed ", i); 1140+ break; 1141+ } 1142+ rc = MetaDwrRecoverSinglePage(pBt, hdr->pages[i], pData); 1143+ if (rc != SQLITE_OK) { 1144+ sqlite3_log(rc, "Dwr recover %d meta page failed ", i); 1145+ break; 1146+ } 1147+ } 1148+DWR_RECOVER_OUT: 1149+ /* Close the transaction, if one was opened. */ 1150+ if (rc == SQLITE_OK) { 1151+ sqlite3BtreeCommit(pBt); 1152+ } else { 1153+ (void)sqlite3BtreeRollback(pBt, SQLITE_ABORT_ROLLBACK, 0); 1154+ } 1155+ if (rc == SQLITE_OK) { 1156+ rc = sqlite3BtreeBeginTrans(pBt, wrflag, pSchemaVersion); 1157+ } 1158+ if (rc == SQLITE_OK) { 1159+ pBt->pBt->metaRecoverStatus = META_RECOVER_SUCCESS; 1160+ } 1161+ if (pData) { 1162+ sqlite3_free(pData); 1163+ } 1164+ return rc; 1165+} 1166+ 1167+static int Sqlite3MetaDwrCheckRestore(Btree *pBt) { 1168+ Pager *pPager = pBt->pBt->pPager; 1169+ int rc = MetaDwrOpenFile(pPager, 1); 1170+ if (rc != SQLITE_OK) { 1171+ return rc; 1172+ } 1173+ ScanPages metaPages = {0}; 1174+ rc = ScanMetaPages(pBt, &metaPages); 1175+ if (rc != SQLITE_OK || metaPages.pageCnt == 0) { 1176+ goto CHK_RESTORE_OUT; 1177+ } 1178+ rc = MetaDwrLoadAndCheckMetaFile(pBt->pBt, 0); 1179+ if (rc != SQLITE_OK) { 1180+ goto CHK_RESTORE_OUT; 1181+ } 1182+ MetaDwrHdr *hdr = pPager->metaHdr; 1183+ if (hdr->pageCnt == 0 || hdr->pageCnt != metaPages.pageCnt || 1184+ memcmp(hdr->pages, metaPages.pages, hdr->pageCnt * sizeof(Pgno))) { 1185+ sqlite3_log(SQLITE_WARNING_DUMP, "sqlite meta restore all"); 1186+ rc = MetaDwrRestoreAllPages(pBt, &metaPages, hdr); 1187+ if (rc == SQLITE_OK) { 1188+ pPager->metaChanged = META_SCHEMA_CHANGED; 1189+ rc = MetaDwrWriteHeader(pPager, hdr); 1190+ pPager->metaChanged = 0; 1191+ } 1192+ } 1193+ if (rc == SQLITE_OK) { 1194+ pBt->pBt->maxMetaPage = metaPages.maxPageNo; 1195+ } 1196+CHK_RESTORE_OUT: 1197+ ReleaseMetaPages(&metaPages); 1198+ return rc; 1199+} 1200+ 1201+static inline u8 IsConnectionValidForCheck(Pager *pPager) 1202+{ 1203+#if SQLITE_OS_UNIX 1204+ unixFile *fd = (unixFile *)pPager->fd; 1205+ // unix and only one connection exist 1206+ if (fd == NULL || fd->pInode == NULL || pPager->pVfs == NULL || 1207+ sqlite3_stricmp(pPager->pVfs->zName, "unix") != 0 || fd->pInode->nRef != 1) { 1208+ return 0; 1209+ } 1210+ return 1; 1211+#else 1212+ return 0; 1213+#endif 1214+} 1215+ 1216+static int MetaDwrOpenAndCheck(Btree *pBt) 1217+{ 1218+ Pager *pPager = pBt->pBt->pPager; 1219+ if (pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { 1220+ return SQLITE_OK; 1221+ } 1222+#ifdef SQLITE_HAS_CODEC 1223+ // not support codec right now 1224+ if (pPager->xCodec) { 1225+ return SQLITE_OK; 1226+ } 1227+#endif 1228+ sqlite3BtreeEnter(pBt); 1229+ int rc = SQLITE_OK; 1230+ int openedTransaction = 0; 1231+ int tnxState = sqlite3BtreeTxnState(pBt); 1232+ if (tnxState == SQLITE_TXN_NONE) { 1233+ rc = sqlite3BtreeBeginTrans(pBt, 0, 0); 1234+ if (rc != SQLITE_OK) { 1235+ goto DWR_OPEN_OUT; 1236+ } 1237+ openedTransaction = 1; 1238+ } 1239+ rc = MetaDwrCheckMeta(pBt); 1240+ if (rc == SQLITE_CORRUPT || rc == SQLITE_NOTADB) { 1241+ // keep txn status after recover 1242+ rc = MetaDwrRecoverAndBeginTran(pBt, tnxState == SQLITE_TXN_WRITE ? 1 : 0, 0); 1243+ goto DWR_OPEN_OUT; 1244+ } 1245+ rc = Sqlite3MetaDwrCheckRestore(pBt); 1246+DWR_OPEN_OUT: 1247+ if (rc == SQLITE_OK && pBt->pBt->metaRecoverStatus == META_RECOVER_SUCCESS) { 1248+ rc = MetaDwrCheckMeta(pBt); 1249+ if (rc == SQLITE_OK) { 1250+ rc = SQLITE_META_RECOVERED; 1251+ } 1252+ } 1253+ /* Close the transaction, if one was opened. */ 1254+ if (openedTransaction) { 1255+ sqlite3BtreeCommit(pBt); 1256+ } 1257+ sqlite3BtreeLeave(pBt); 1258+ return rc; 1259+} 1260 1261+static void MetaDwrDisable(Btree *pBt) 1262+{ 1263+ Pager *pPager = pBt->pBt->pPager; 1264+ if (pPager->metaFd == NULL || pPager->memDb || pPager->readOnly || !IsConnectionValidForCheck(pPager)) { 1265+ return; 1266+ } 1267+#ifdef SQLITE_HAS_CODEC 1268+ // not support codec right now 1269+ if (pPager->xCodec) { 1270+ return; 1271+ } 1272+#endif 1273+ sqlite3BtreeEnter(pBt); 1274+ MetaDwrCloseFile(pPager); 1275+ MetaDwrReleaseHdr(pPager->metaHdr); 1276+ pPager->metaHdr = NULL; 1277+ const char *metaPath = GetMetaFilePath(pPager); 1278+ if (metaPath != NULL) { 1279+ (void)osUnlink(metaPath); 1280+ } 1281+ if (pPager->metaFd) { 1282+ sqlite3_free(pPager->metaFd); 1283+ pPager->metaFd = NULL; 1284+ } 1285+ sqlite3BtreeLeave(pBt); 1286+} 1287+#endif 1288 #if SQLITE_OS_UNIX 1289 #include <unistd.h> 1290 #include <sys/syscall.h> 1291-- 12922.47.0.windows.2 1293 1294