?? pager.c
字號:
static int pager_ckpt_playback(Pager *pPager){ off_t szJ; /* Size of the full journal */ int nRec; /* Number of Records */ int i; /* Loop counter */ int rc; /* Truncate the database back to its original size. */ rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)pPager->ckptSize); pPager->dbSize = pPager->ckptSize; /* Figure out how many records are in the checkpoint journal. */ assert( pPager->ckptInUse && pPager->journalOpen ); sqliteOsSeek(&pPager->cpfd, 0); nRec = pPager->ckptNRec; /* Copy original pages out of the checkpoint journal and back into the ** database file. Note that the checkpoint journal always uses format ** 2 instead of format 3 since it does not need to be concerned with ** power failures corrupting the journal and can thus omit the checksums. */ for(i=nRec-1; i>=0; i--){ rc = pager_playback_one_page(pPager, &pPager->cpfd, 2); assert( rc!=SQLITE_DONE ); if( rc!=SQLITE_OK ) goto end_ckpt_playback; } /* Figure out how many pages need to be copied out of the transaction ** journal. */ rc = sqliteOsSeek(&pPager->jfd, pPager->ckptJSize); if( rc!=SQLITE_OK ){ goto end_ckpt_playback; } rc = sqliteOsFileSize(&pPager->jfd, &szJ); if( rc!=SQLITE_OK ){ goto end_ckpt_playback; } nRec = (szJ - pPager->ckptJSize)/JOURNAL_PG_SZ(journal_format); for(i=nRec-1; i>=0; i--){ rc = pager_playback_one_page(pPager, &pPager->jfd, journal_format); if( rc!=SQLITE_OK ){ assert( rc!=SQLITE_DONE ); goto end_ckpt_playback; } } end_ckpt_playback: if( rc!=SQLITE_OK ){ pPager->errMask |= PAGER_ERR_CORRUPT; rc = SQLITE_CORRUPT; } return rc;}/*** Change the maximum number of in-memory pages that are allowed.**** The maximum number is the absolute value of the mxPage parameter.** If mxPage is negative, the noSync flag is also set. noSync bypasses** calls to sqliteOsSync(). The pager runs much faster with noSync on,** but if the operating system crashes or there is an abrupt power ** failure, the database file might be left in an inconsistent and** unrepairable state. */void sqlitepager_set_cachesize(Pager *pPager, int mxPage){ if( mxPage>=0 ){ pPager->noSync = pPager->tempFile; if( pPager->noSync==0 ) pPager->needSync = 0; }else{ pPager->noSync = 1; mxPage = -mxPage; } if( mxPage>10 ){ pPager->mxPage = 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 sqliteOsSync() 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.*/void sqlitepager_set_safety_level(Pager *pPager, int level){ pPager->noSync = level==1 || pPager->tempFile; pPager->fullSync = level==3 && !pPager->tempFile; if( pPager->noSync==0 ) pPager->needSync = 0;}/*** Open a temporary file. Write the name of the file into zName** (zName must be at least SQLITE_TEMPNAME_SIZE bytes long.) 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 sqlitepager_opentemp(char *zFile, OsFile *fd){ int cnt = 8; int rc; do{ cnt--; sqliteOsTempFileName(zFile); rc = sqliteOsOpenExclusive(zFile, fd, 1); }while( cnt>0 && rc!=SQLITE_OK ); 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 sqlitepager_get() and is only held open until the** last page is released using sqlitepager_unref().**** 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.*/int sqlitepager_open( Pager **ppPager, /* Return the Pager structure here */ const char *zFilename, /* Name of the database file to open */ int mxPage, /* Max number of in-memory cache pages */ int nExtra, /* Extra bytes append to each in-memory page */ int useJournal /* TRUE to use a rollback journal on this file */){ Pager *pPager; char *zFullPathname; int nameLen; OsFile fd; int rc, i; int tempFile; int readOnly = 0; char zTemp[SQLITE_TEMPNAME_SIZE]; *ppPager = 0; if( sqlite_malloc_failed ){ return SQLITE_NOMEM; } if( zFilename && zFilename[0] ){ zFullPathname = sqliteOsFullPathname(zFilename); rc = sqliteOsOpenReadWrite(zFullPathname, &fd, &readOnly); tempFile = 0; }else{ rc = sqlitepager_opentemp(zTemp, &fd); zFilename = zTemp; zFullPathname = sqliteOsFullPathname(zFilename); tempFile = 1; } if( sqlite_malloc_failed ){ return SQLITE_NOMEM; } if( rc!=SQLITE_OK ){ sqliteFree(zFullPathname); return SQLITE_CANTOPEN; } nameLen = strlen(zFullPathname); pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); if( pPager==0 ){ sqliteOsClose(&fd); sqliteFree(zFullPathname); return SQLITE_NOMEM; } SET_PAGER(pPager); 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; pPager->ckptOpen = 0; pPager->ckptInUse = 0; pPager->nRef = 0; pPager->dbSize = -1; pPager->ckptSize = 0; pPager->ckptJSize = 0; pPager->nPage = 0; pPager->mxPage = mxPage>5 ? mxPage : 10; pPager->state = SQLITE_UNLOCK; pPager->errMask = 0; pPager->tempFile = tempFile; pPager->readOnly = readOnly; pPager->needSync = 0; pPager->noSync = pPager->tempFile || !useJournal; pPager->pFirst = 0; pPager->pFirstSynced = 0; pPager->pLast = 0; pPager->nExtra = nExtra; memset(pPager->aHash, 0, sizeof(pPager->aHash)); *ppPager = pPager; return SQLITE_OK;}/*** 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 sqlitepager_close(). ** Destructors are only called by sqlitepager_unref().*/void sqlitepager_set_destructor(Pager *pPager, void (*xDesc)(void*)){ pPager->xDestructor = xDesc;}/*** Return the total number of pages in the disk file associated with** pPager.*/int sqlitepager_pagecount(Pager *pPager){ off_t n; assert( pPager!=0 ); if( pPager->dbSize>=0 ){ return pPager->dbSize; } if( sqliteOsFileSize(&pPager->fd, &n)!=SQLITE_OK ){ pPager->errMask |= PAGER_ERR_DISK; return 0; } n /= SQLITE_PAGE_SIZE; if( pPager->state!=SQLITE_UNLOCK ){ pPager->dbSize = n; } return n;}/*** Forward declaration*/static int syncJournal(Pager*);/*** Truncate the file to the number of pages specified.*/int sqlitepager_truncate(Pager *pPager, Pgno nPage){ int rc; if( pPager->dbSize<0 ){ sqlitepager_pagecount(pPager); } if( pPager->errMask!=0 ){ rc = pager_errcode(pPager); return rc; } if( nPage>=(unsigned)pPager->dbSize ){ return SQLITE_OK; } syncJournal(pPager); rc = sqliteOsTruncate(&pPager->fd, SQLITE_PAGE_SIZE*(off_t)nPage); if( rc==SQLITE_OK ){ pPager->dbSize = nPage; } return rc;}/*** Shutdown the page cache. Free all memory and close all files.**** If a transaction was in progress when this routine is called, that** transaction is rolled back. All outstanding pages are invalidated** and their memory is freed. Any attempt to use a page associated** with this page cache after this function returns will likely** result in a coredump.*/int sqlitepager_close(Pager *pPager){ PgHdr *pPg, *pNext; switch( pPager->state ){ case SQLITE_WRITELOCK: { sqlitepager_rollback(pPager); sqliteOsUnlock(&pPager->fd); assert( pPager->journalOpen==0 ); break; } case SQLITE_READLOCK: { sqliteOsUnlock(&pPager->fd); break; } default: { /* Do nothing */ break; } } for(pPg=pPager->pAll; pPg; pPg=pNext){ pNext = pPg->pNextAll; sqliteFree(pPg); } sqliteOsClose(&pPager->fd); assert( pPager->journalOpen==0 ); /* Temp files are automatically deleted by the OS ** if( pPager->tempFile ){ ** sqliteOsDelete(pPager->zFilename); ** } */ CLR_PAGER(pPager); if( pPager->zFilename!=(char*)&pPager[1] ){ assert( 0 ); /* Cannot happen */ sqliteFree(pPager->zFilename); sqliteFree(pPager->zJournal); sqliteFree(pPager->zDirectory); } sqliteFree(pPager); return SQLITE_OK;}/*** Return the page number for the given page data.*/Pgno sqlitepager_pagenumber(void *pData){ PgHdr *p = DATA_TO_PGHDR(pData); return p->pgno;}/*** Increment the reference count for a page. If the page is** currently on the freelist (the reference count is zero) then** remove it from the freelist.*/#define page_ref(P) ((P)->nRef==0?_page_ref(P):(void)(P)->nRef++)static void _page_ref(PgHdr *pPg){ if( pPg->nRef==0 ){ /* The page is currently on the freelist. Remove it. */ if( pPg==pPg->pPager->pFirstSynced ){ PgHdr *p = pPg->pNextFree; while( p && p->needSync ){ p = p->pNextFree; } pPg->pPager->pFirstSynced = p; } if( pPg->pPrevFree ){ pPg->pPrevFree->pNextFree = pPg->pNextFree; }else{ pPg->pPager->pFirst = pPg->pNextFree; } if( pPg->pNextFree ){ pPg->pNextFree->pPrevFree = pPg->pPrevFree; }else{ pPg->pPager->pLast = pPg->pPrevFree; } pPg->pPager->nRef++; } pPg->nRef++; REFINFO(pPg);}/*** Increment the reference count for a page. The input pointer is** a reference to the page data.*/int sqlitepager_ref(void *pData){ PgHdr *pPg = DATA_TO_PGHDR(pData); page_ref(pPg); return SQLITE_OK;}/*** Sync the journal. In other words, make sure all the pages that have** been written to the journal have actually reached the surface of the** disk. It is not safe to modify the original database file until after** the journal has been synced. If the original database is modified before** the journal is synced and a power failure occurs, the unsynced journal** data would be lost and we would be unable to completely rollback the
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -