📄 pager.c
字号:
/* 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 ); sqlite3OsSeek(pPager->stfd, 0); 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=nRec-1; i>=0; i--){ rc = pager_playback_one_page(pPager, pPager->stfd, 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. */ rc = sqlite3OsSeek(pPager->jfd, pPager->stmtJSize); if( rc!=SQLITE_OK ){ goto end_stmt_playback; } pPager->journalOff = pPager->stmtJSize; pPager->cksumInit = pPager->stmtCksum; while( pPager->journalOff < hdrOff ){ rc = pager_playback_one_page(pPager, pPager->jfd, 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, 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){ if( mxPage>10 ){ pPager->mxPage = mxPage; }else{ pPager->mxPage = 10; }}/*** 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 full_fsync){ pPager->noSync = level==1 || pPager->tempFile; pPager->fullSync = level==3 && !pPager->tempFile; pPager->full_fsync = full_fsync; 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(OsFile **pFd){ int cnt = 8; int rc; char zFile[SQLITE_TEMPNAME_SIZE];#ifdef SQLITE_TEST sqlite3_opentemp_count++; /* Used for testing and analysis only */#endif do{ cnt--; sqlite3OsTempFileName(zFile); rc = sqlite3OsOpenExclusive(zFile, pFd, 1); assert( rc!=SQLITE_OK || *pFd ); }while( cnt>0 && rc!=SQLITE_OK && rc!=SQLITE_NOMEM ); return rc;}/*** 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( Pager **ppPager, /* Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ int nExtra, /* Extra bytes append to each in-memory page */ int flags /* flags controlling this file */){ Pager *pPager = 0; char *zFullPathname = 0; int nameLen; /* Compiler is wrong. This is always initialized before use */ OsFile *fd = 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; char zTemp[SQLITE_TEMPNAME_SIZE];#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT /* A malloc() cannot fail in sqlite3ThreadData() as one or more calls to ** malloc() must have already been made by this thread before it gets ** to this point. This means the ThreadData must have been allocated already ** so that ThreadData.nAlloc can be set. It would be nice to assert ** that ThreadData.nAlloc is non-zero, but alas this breaks test cases ** written to invoke the pager directly. */ ThreadData *pTsd = sqlite3ThreadData(); assert( pTsd );#endif /* We used to test if malloc() had already failed before proceeding. ** But the way this function is used in SQLite means that can never ** happen. Furthermore, if the malloc-failed flag is already set, ** either the call to sqliteStrDup() or sqliteMalloc() below will ** fail shortly and SQLITE_NOMEM returned anyway. */ *ppPager = 0; /* Open the pager file and set zFullPathname to point at malloc()ed ** memory containing the complete filename (i.e. including the directory). */ if( zFilename && zFilename[0] ){#ifndef SQLITE_OMIT_MEMORYDB if( strcmp(zFilename,":memory:")==0 ){ memDb = 1; zFullPathname = sqliteStrDup(""); }else#endif { zFullPathname = sqlite3OsFullPathname(zFilename); if( zFullPathname ){ rc = sqlite3OsOpenReadWrite(zFullPathname, &fd, &readOnly); assert( rc!=SQLITE_OK || fd ); } } }else{ rc = sqlite3PagerOpentemp(&fd); sqlite3OsTempFileName(zTemp); zFilename = zTemp; zFullPathname = sqlite3OsFullPathname(zFilename); if( rc==SQLITE_OK ){ tempFile = 1; } } /* Allocate the Pager structure. As part of the same allocation, allocate ** space for the full paths of the file, directory and journal ** (Pager.zFilename, Pager.zDirectory and Pager.zJournal). */ if( zFullPathname ){ nameLen = strlen(zFullPathname); pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); if( pPager && rc==SQLITE_OK ){ pPager->pTmpSpace = (char *)sqliteMallocRaw(SQLITE_DEFAULT_PAGE_SIZE); } } /* If an error occured in either of the blocks above, free the memory ** pointed to by zFullPathname, free the Pager structure and close the ** file. Since the pager is not allocated there is no need to set ** any Pager.errMask variables. */ if( !pPager || !zFullPathname || !pPager->pTmpSpace || rc!=SQLITE_OK ){ sqlite3OsClose(&fd); sqliteFree(zFullPathname); sqliteFree(pPager); return ((rc==SQLITE_OK)?SQLITE_NOMEM:rc); } PAGERTRACE3("OPEN %d %s\n", FILEHANDLEID(fd), zFullPathname); IOTRACE(("OPEN %p %s\n", pPager, zFullPathname)) pPager->zFilename = (char*)&pPager[1]; pPager->zDirectory = &pPager->zFilename[nameLen+1]; pPager->zJournal = &pPager->zDirectory[nameLen+1]; strcpy(pPager->zFilename, zFullPathname); strcpy(pPager->zDirectory, zFullPathname); for(i=nameLen; i>0 && pPager->zDirectory[i-1]!='/'; i--){} if( i>0 ) pPager->zDirectory[i-1] = 0; strcpy(pPager->zJournal, zFullPathname); sqliteFree(zFullPathname); strcpy(&pPager->zJournal[nameLen], "-journal"); pPager->fd = fd; /* pPager->journalOpen = 0; */ pPager->useJournal = useJournal && !memDb; pPager->noReadlock = noReadlock && readOnly; /* pPager->stmtOpen = 0; */ /* pPager->stmtInUse = 0; */ /* pPager->nRef = 0; */ pPager->dbSize = memDb-1; pPager->pageSize = SQLITE_DEFAULT_PAGE_SIZE; /* pPager->stmtSize = 0; */ /* pPager->stmtJSize = 0; */ /* pPager->nPage = 0; */ /* pPager->nMaxPage = 0; */ pPager->mxPage = 100; assert( PAGER_UNLOCK==0 ); /* pPager->state = PAGER_UNLOCK; */ /* pPager->errMask = 0; */ pPager->tempFile = tempFile; assert( tempFile==PAGER_LOCKINGMODE_NORMAL || tempFile==PAGER_LOCKINGMODE_EXCLUSIVE ); assert( PAGER_LOCKINGMODE_EXCLUSIVE==1 ); pPager->exclusiveMode = tempFile; pPager->memDb = memDb; pPager->readOnly = readOnly; /* pPager->needSync = 0; */ pPager->noSync = pPager->tempFile || !useJournal; pPager->fullSync = (pPager->noSync?0:1); /* pPager->pFirst = 0; */ /* pPager->pFirstSynced = 0; */ /* pPager->pLast = 0; */ pPager->nExtra = FORCE_ALIGNMENT(nExtra); assert(fd||memDb); if( !memDb ){ pPager->sectorSize = sqlite3OsSectorSize(fd); } /* pPager->pBusyHandler = 0; */ /* memset(pPager->aHash, 0, sizeof(pPager->aHash)); */ *ppPager = pPager;#ifdef SQLITE_ENABLE_MEMORY_MANAGEMENT pPager->pNext = pTsd->pPager; pTsd->pPager = pPager;#endif return SQLITE_OK;}/*** Set the busy handler function.*/void sqlite3PagerSetBusyhandler(Pager *pPager, BusyHandler *pBusyHandler){ pPager->pBusyHandler = pBusyHandler;}/*** Set the destructor for this pager. If not NULL, the destructor is called** when the reference count on each page reaches zero. The destructor can** be used to clean up information in the extra segment appended to each page.**** The destructor is not called as a result sqlite3PagerClose(). ** Destructors are only called by sqlite3PagerUnref().*/void sqlite3PagerSetDestructor(Pager *pPager, void (*xDesc)(DbPage*,int)){ pPager->xDestructor = xDesc;}/*** Set the reinitializer for this pager. If not NULL, the reinitializer** is called when the content of a page in cache is restored to its original** value as a result of a rollback. The callback gives higher-level code** an opportunity to restore the EXTRA section to agree with the restored** page data.*/void sqlite3PagerSetReiniter(Pager *pPager, void (*xReinit)(DbPage*,int)){ pPager->xReiniter = xReinit;}/*** Set the page size. Return the new size. If the suggest new page** size is inappropriate, then an alternative page size is selected** and returned.*/int sqlite3PagerSetPagesize(Pager *pPager, int pageSize){ assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE ); if( !pPager->memDb && pPager->nRef==0 ){ pager_reset(pPager); pPager->pageSize = pageSize; pPager->pTmpSpace = sqlite3ReallocOrFree(pPager->pTmpSpace, pageSize); } return pPager->pageSize;}/*** The following set of routines are used to disable the simulated** I/O error mechanism. These routines are used to avoid simulated** errors in places where we do not care abou
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -