📄 pager.c
字号:
pPager->journalOff = 0; /* This loop terminates either when the readJournalHdr() call returns ** SQLITE_DONE or an IO error occurs. */ while( 1 ){ /* Read the next journal header from the journal file. If there are ** not enough bytes left in the journal file for a complete header, or ** it is corrupted, then a process must of failed while writing it. ** This indicates nothing more needs to be rolled back. */ rc = readJournalHdr(pPager, szJ, &nRec, &mxPg); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; } goto end_playback; } /* If nRec is 0xffffffff, then this journal was created by a process ** working in no-sync mode. This means that the rest of the journal ** file consists of pages, there are no more journal headers. Compute ** the value of nRec based on this assumption. */ if( nRec==0xffffffff ){ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ); nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager); } /* If nRec is 0 and this rollback is of a transaction created by this ** process and if this is the final header in the journal, then it means ** that this part of the journal was being filled but has not yet been ** synced to disk. Compute the number of pages based on the remaining ** size of the file. ** ** The third term of the test was added to fix ticket #2565. */ if( nRec==0 && !isHot && pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ nRec = (szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager); } /* If this is the first header read from the journal, truncate the ** database file back to its original size. */ if( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ){ rc = pager_truncate(pPager, mxPg); if( rc!=SQLITE_OK ){ goto end_playback; } } /* Copy original pages out of the journal and back into the database file. */ for(u=0; u<nRec; u++){ rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); if( rc!=SQLITE_OK ){ if( rc==SQLITE_DONE ){ rc = SQLITE_OK; pPager->journalOff = szJ; break; }else{ goto end_playback; } } } } /*NOTREACHED*/ assert( 0 );end_playback: if( rc==SQLITE_OK ){ zMaster = pPager->pTmpSpace; rc = readMasterJournal(pPager->jfd, zMaster, pPager->pVfs->mxPathname+1); } if( rc==SQLITE_OK ){ rc = pager_end_transaction(pPager, zMaster[0]!='\0'); } if( rc==SQLITE_OK && zMaster[0] ){ /* If there was a master journal and this routine will return success, ** see if it is possible to delete the master journal. */ rc = pager_delmaster(pPager, zMaster); } /* The Pager.sectorSize variable may have been updated while rolling ** back a journal created by a process with a different sector size ** value. Reset it to the correct value for this process. */ setSectorSize(pPager); return rc;}/*** Playback the statement journal.**** This is similar to playing back the transaction journal but with** a few extra twists.**** (1) The number of pages in the database file at the start of** the statement is stored in pPager->stmtSize, not in the** journal file itself.**** (2) In addition to playing back the statement journal, also** playback all pages of the transaction journal beginning** at offset pPager->stmtJSize.*/static int pager_stmt_playback(Pager *pPager){ i64 szJ; /* Size of the full journal */ i64 hdrOff; int nRec; /* Number of Records */ int i; /* Loop counter */ int rc; szJ = pPager->journalOff; /* Set hdrOff to be the offset just after the end of the last journal ** page written before the first journal-header for this statement ** transaction was written, or the end of the file if no journal ** header was written. */ hdrOff = pPager->stmtHdrOff; assert( pPager->fullSync || !hdrOff ); if( !hdrOff ){ hdrOff = szJ; } /* Truncate the database back to its original size. */ rc = pager_truncate(pPager, pPager->stmtSize); assert( pPager->state>=PAGER_SHARED ); /* Figure out how many records are in the statement journal. */ assert( pPager->stmtInUse && pPager->journalOpen ); nRec = pPager->stmtNRec; /* Copy original pages out of the statement journal and back into the ** database file. Note that the statement journal omits checksums from ** each record since power-failure recovery is not important to statement ** journals. */ for(i=0; i<nRec; i++){ i64 offset = i*(4+pPager->pageSize); rc = pager_playback_one_page(pPager, pPager->stfd, offset, 0); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } /* Now roll some pages back from the transaction journal. Pager.stmtJSize ** was the size of the journal file when this statement was started, so ** everything after that needs to be rolled back, either into the ** database, the memory cache, or both. ** ** If it is not zero, then Pager.stmtHdrOff is the offset to the start ** of the first journal header written during this statement transaction. */ pPager->journalOff = pPager->stmtJSize; pPager->cksumInit = pPager->stmtCksum; while( pPager->journalOff < hdrOff ){ rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } while( pPager->journalOff < szJ ){ u32 nJRec; /* Number of Journal Records */ u32 dummy; rc = readJournalHdr(pPager, szJ, &nJRec, &dummy); if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_DONE ); goto end_stmt_playback; } if( nJRec==0 ){ nJRec = (szJ - pPager->journalOff) / (pPager->pageSize+8); } for(i=nJRec-1; i>=0 && pPager->journalOff < szJ; i--){ rc = pager_playback_one_page(pPager, pPager->jfd, pPager->journalOff, 1); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_stmt_playback; } } pPager->journalOff = szJ; end_stmt_playback: if( rc==SQLITE_OK) { pPager->journalOff = szJ; /* pager_reload_cache(pPager); */ } return rc;}/*** Change the maximum number of in-memory pages that are allowed.*/void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ sqlite3PcacheSetCachesize(pPager->pPCache, mxPage);}/*** Adjust the robustness of the database to damage due to OS crashes** or power failures by changing the number of syncs()s when writing** the rollback journal. There are three levels:**** OFF sqlite3OsSync() is never called. This is the default** for temporary and transient files.**** NORMAL The journal is synced once before writes begin on the** database. This is normally adequate protection, but** it is theoretically possible, though very unlikely,** that an inopertune power failure could leave the journal** in a state which would cause damage to the database** when it is rolled back.**** FULL The journal is synced twice before writes begin on the** database (with some additional information - the nRec field** of the journal header - being written in between the two** syncs). If we assume that writing a** single disk sector is atomic, then this mode provides** assurance that the journal will not be corrupted to the** point of causing damage to the database during rollback.**** Numeric values associated with these states are OFF==1, NORMAL=2,** and FULL=3.*/#ifndef SQLITE_OMIT_PAGER_PRAGMASvoid sqlite3PagerSetSafetyLevel(Pager *pPager, int level, int bFullFsync){ pPager->noSync = level==1 || pPager->tempFile; pPager->fullSync = level==3 && !pPager->tempFile; pPager->sync_flags = (bFullFsync?SQLITE_SYNC_FULL:SQLITE_SYNC_NORMAL); if( pPager->noSync ) pPager->needSync = 0;}#endif/*** The following global variable is incremented whenever the library** attempts to open a temporary file. This information is used for** testing and analysis only. */#ifdef SQLITE_TESTint sqlite3_opentemp_count = 0;#endif/*** Open a temporary file. **** Write the file descriptor into *fd. Return SQLITE_OK on success or some** other error code if we fail. The OS will automatically delete the temporary** file when it is closed.*/static int sqlite3PagerOpentemp( Pager *pPager, /* The pager object */ sqlite3_file *pFile, /* Write the file descriptor here */ int vfsFlags /* Flags passed through to the VFS */){ int rc;#ifdef SQLITE_TEST sqlite3_opentemp_count++; /* Used for testing and analysis only */#endif vfsFlags |= SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_EXCLUSIVE | SQLITE_OPEN_DELETEONCLOSE; rc = sqlite3OsOpen(pPager->pVfs, 0, pFile, vfsFlags, 0); assert( rc!=SQLITE_OK || pFile->pMethods ); return rc;}static int pagerStress(void *,PgHdr *);/*** Create a new page cache and put a pointer to the page cache in *ppPager.** The file to be cached need not exist. The file is not locked until** the first call to sqlite3PagerGet() and is only held open until the** last page is released using sqlite3PagerUnref().**** If zFilename is NULL then a randomly-named temporary file is created** and used as the file to be cached. The file will be deleted** automatically when it is closed.**** If zFilename is ":memory:" then all information is held in cache.** It is never written to disk. This can be used to implement an** in-memory database.*/int sqlite3PagerOpen( sqlite3_vfs *pVfs, /* The virtual file system to use */ Pager **ppPager, /* Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ void (*xDesc)(DbPage*), /* Page destructor function */ int nExtra, /* Extra bytes append to each in-memory page */ int flags, /* flags controlling this file */ int vfsFlags /* flags passed through to sqlite3_vfs.xOpen() */){ u8 *pPtr; Pager *pPager = 0; int rc = SQLITE_OK; int i; int tempFile = 0; int memDb = 0; int readOnly = 0; int useJournal = (flags & PAGER_OMIT_JOURNAL)==0; int noReadlock = (flags & PAGER_NO_READLOCK)!=0; int journalFileSize = sqlite3JournalSize(pVfs); int pcacheSize = sqlite3PcacheSize(); int szPageDflt = SQLITE_DEFAULT_PAGE_SIZE; char *zPathname = 0; int nPathname = 0; /* The default return is a NULL pointer */ *ppPager = 0; /* Compute and store the full pathname in an allocated buffer pointed ** to by zPathname, length nPathname. Or, if this is a temporary file, ** leave both nPathname and zPathname set to 0. */ if( zFilename && zFilename[0] ){ nPathname = pVfs->mxPathname+1; zPathname = sqlite3Malloc(nPathname*2); if( zPathname==0 ){ return SQLITE_NOMEM; }#ifndef SQLITE_OMIT_MEMORYDB if( strcmp(zFilename,":memory:")==0 ){ memDb = 1; zPathname[0] = 0; }else#endif { rc = sqlite3OsFullPathname(pVfs, zFilename, nPathname, zPathname); } if( rc!=SQLITE_OK ){ sqlite3_free(zPathname); return rc; } nPathname = strlen(zPathname); } /* Allocate memory for the pager structure */ pPager = sqlite3MallocZero( sizeof(*pPager) + /* Pager structure */ pcacheSize + /* PCache object */ journalFileSize + /* The journal file structure */ pVfs->szOsFile * 3 + /* The main db and two journal files */ 3*nPathname + 40 /* zFilename, zDirectory, zJournal */ ); if( !pPager ){ sqlite3_free(zPathname); return SQLITE_NOMEM; } pPager->pPCache = (PCache *)&pPager[1]; pPtr = ((u8 *)&pPager[1]) + pcacheSize; pPager->vfsFlags = vfsFlags; pPager->fd = (sqlite3_file*)&pPtr[pVfs->szOsFile*0]; pPager->stfd = (sqlite3_file*)&pPtr[pVfs->szOsFile*1]; pPager->jfd =
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -