📄 pager.c
字号:
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. */int sqlite3_opentemp_count = 0;/*** Open a temporary file. Write the name of the file into zFile** (zFile 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 sqlite3pager_opentemp(char *zFile, OsFile *fd){ int cnt = 8; int rc; sqlite3_opentemp_count++; /* Used for testing and analysis only */ do{ cnt--; sqlite3OsTempFileName(zFile); rc = sqlite3OsOpenExclusive(zFile, fd, 1); }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 sqlite3pager_get() and is only held open until the** last page is released using sqlite3pager_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.**** 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 sqlite3pager_open( 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; char *zFullPathname = 0; int nameLen; OsFile fd; 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]; *ppPager = 0; memset(&fd, 0, sizeof(fd)); if( sqlite3_malloc_failed ){ return SQLITE_NOMEM; } if( zFilename && zFilename[0] ){#ifndef SQLITE_OMIT_MEMORYDB if( strcmp(zFilename,":memory:")==0 ){ memDb = 1; zFullPathname = sqliteStrDup(""); rc = SQLITE_OK; }else#endif { zFullPathname = sqlite3OsFullPathname(zFilename); if( zFullPathname ){ rc = sqlite3OsOpenReadWrite(zFullPathname, &fd, &readOnly); } } }else{ rc = sqlite3pager_opentemp(zTemp, &fd); zFilename = zTemp; zFullPathname = sqlite3OsFullPathname(zFilename); if( rc==SQLITE_OK ){ tempFile = 1; } } if( !zFullPathname ){ sqlite3OsClose(&fd); return SQLITE_NOMEM; } if( rc!=SQLITE_OK ){ sqlite3OsClose(&fd); sqliteFree(zFullPathname); return rc; } nameLen = strlen(zFullPathname); pPager = sqliteMalloc( sizeof(*pPager) + nameLen*3 + 30 ); if( pPager==0 ){ sqlite3OsClose(&fd); sqliteFree(zFullPathname); return SQLITE_NOMEM; } TRACE3("OPEN %d %s\n", FILEHANDLEID(fd), 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;#if OS_UNIX pPager->fd.pPager = pPager;#endif 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; pPager->state = PAGER_UNLOCK; pPager->errMask = 0; pPager->tempFile = 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); pPager->sectorSize = PAGER_SECTOR_SIZE; pPager->pBusyHandler = 0; memset(pPager->aHash, 0, sizeof(pPager->aHash)); *ppPager = pPager; return SQLITE_OK;}/*** Set the busy handler function.*/void sqlite3pager_set_busyhandler(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 sqlite3pager_close(). ** Destructors are only called by sqlite3pager_unref().*/void sqlite3pager_set_destructor(Pager *pPager, void (*xDesc)(void*,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 sqlite3pager_set_reiniter(Pager *pPager, void (*xReinit)(void*,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 sqlite3pager_set_pagesize(Pager *pPager, int pageSize){ assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE ); if( !pPager->memDb ){ pPager->pageSize = pageSize; } return pPager->pageSize;}/*** Read the first N bytes from the beginning of the file into memory** that pDest points to. No error checking is done.*/void sqlite3pager_read_fileheader(Pager *pPager, int N, unsigned char *pDest){ memset(pDest, 0, N); if( MEMDB==0 ){ sqlite3OsSeek(&pPager->fd, 0); sqlite3OsRead(&pPager->fd, pDest, N); }}/*** Return the total number of pages in the disk file associated with** pPager.*/int sqlite3pager_pagecount(Pager *pPager){ i64 n; assert( pPager!=0 ); if( pPager->dbSize>=0 ){ return pPager->dbSize; } if( sqlite3OsFileSize(&pPager->fd, &n)!=SQLITE_OK ){ pPager->errMask |= PAGER_ERR_DISK; return 0; } n /= pPager->pageSize; if( !MEMDB && n==PENDING_BYTE/pPager->pageSize ){ n++; } if( pPager->state!=PAGER_UNLOCK ){ pPager->dbSize = n; } return n;}/*** Forward declaration*/static int syncJournal(Pager*);/*** Unlink pPg from it's hash chain. Also set the page number to 0 to indicate** that the page is not part of any hash chain. This is required because the** sqlite3pager_movepage() routine can leave a page in the ** pNextFree/pPrevFree list that is not a part of any hash-chain.*/static void unlinkHashChain(Pager *pPager, PgHdr *pPg){ if( pPg->pgno==0 ){ /* If the page number is zero, then this page is not in any hash chain. */ return; } if( pPg->pNextHash ){ pPg->pNextHash->pPrevHash = pPg->pPrevHash; } if( pPg->pPrevHash ){ assert( pPager->aHash[pager_hash(pPg->pgno)]!=pPg ); pPg->pPrevHash->pNextHash = pPg->pNextHash; }else{ int h = pager_hash(pPg->pgno); assert( pPager->aHash[h]==pPg ); pPager->aHash[h] = pPg->pNextHash; } pPg->pgno = 0; pPg->pNextHash = pPg->pPrevHash = 0;}/*** Unlink a page from the free list (the list of all pages where nRef==0)** and from its hash collision chain.*/static void unlinkPage(PgHdr *pPg){ Pager *pPager = pPg->pPager; /* Keep the pFirstSynced pointer pointing at the first synchronized page */ if( pPg==pPager->pFirstSynced ){ PgHdr *p = pPg->pNextFree; while( p && p->needSync ){ p = p->pNextFree; } pPager->pFirstSynced = p; } /* Unlink from the freelist */ if( pPg->pPrevFree ){ pPg->pPrevFree->pNextFree = pPg->pNextFree; }else{ assert( pPager->pFirst==pPg ); pPager->pFirst = pPg->pNextFree; } if( pPg->pNextFree ){ pPg->pNextFree->pPrevFree = pPg->pPrevFree; }else{ assert( pPager->pLast==pPg ); pPager->pLast = pPg->pPrevFree; } pPg->pNextFree = pPg->pPrevFree = 0; /* Unlink from the pgno hash table */ unlinkHashChain(pPager, pPg);}#ifndef SQLITE_OMIT_MEMORYDB/*** This routine is used to truncate an in-memory database. Delete** all pages whose pgno is larger than pPager->dbSize and is unreferenced.** Referenced pages larger than pPager->dbSize are zeroed.*/static void memoryTruncate(Pager *pPager){ PgHdr *pPg; PgHdr **ppPg; int dbSize = pPager->dbSize; ppPg = &pPager->pAll; while( (pPg = *ppPg)!=0 ){ if( pPg->pgno<=dbSize ){ ppPg = &pPg->pNextAll; }else if( pPg->nRef>0 ){ memset(PGHDR_TO_DATA(pPg), 0, pPager->pageSize); ppPg = &pPg->pNextAll; }else{ *ppPg = pPg->pNextAll; unlinkPage(pPg); sqliteFree(pPg); pPager->nPage--; } }}#else#define memoryTruncate(p)#endif/*** Try to obtain a lock on a file. Invoke the busy callback if the lock** is currently not available. Repeate until the busy callback returns** false or until the lock succeeds.**** Return SQLITE_OK on success and an error code if we cannot obtain** the lock.*/static int pager_wait_on_lock(Pager *pPager, int locktype){ int rc; assert( PAGER_SHARED==SHARED_LOCK ); assert( PAGER_RESERVED==RESERVED_LOCK ); assert( PAGER_EXCLUSIVE==EXCLUSIVE_LOCK ); if( pPager->state>=locktype ){ rc = SQLITE_OK; }else{ int busy = 1; BusyHandler *pH; do { rc = sqlite3OsLock(&pPager->fd, locktype); }while( rc==SQLITE_BUSY && (pH = pPager->pBusyHandler)!=0 && pH->xFunc && pH->xFunc(pH->pArg, busy++) ); if( rc==SQLITE_OK ){ pPager->state = locktype; } } return rc;}/*** Truncate the file to the number of pages specified.*/int sqlite3pager_truncate(Pager *pPager, Pgno nPage){ int rc; sqlite3pager_pagecount(pPager); if( pPager->errMask!=0 ){ rc = pager_errcode(pPager); return rc; } if( nPage>=(unsigned)pPager->dbSize ){ return SQLITE_OK; } if( MEMDB ){ pPager->dbSize = nPage; memoryTruncate(pPager); return SQLITE_OK; } rc = syncJournal(pPager); if( rc!=SQLITE_OK ){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -