⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 pager.c

📁 一个小型的嵌入式数据库
💻 C
📖 第 1 页 / 共 5 页
字号:
  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->psAligned = FORCE_ALIGNMENT(pPager->pageSize);  pPager->stmtSize = 0;  pPager->stmtJSize = 0;  pPager->nPage = 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.**** The page size must only be changed when the cache is empty.*/void sqlite3pager_set_pagesize(Pager *pPager, int pageSize){  assert( pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE );  pPager->pageSize = pageSize;  pPager->psAligned = FORCE_ALIGNMENT(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;    do {      rc = sqlite3OsLock(&pPager->fd, locktype);    }while( rc==SQLITE_BUSY &&         pPager->pBusyHandler &&         pPager->pBusyHandler->xFunc &&         pPager->pBusyHandler->xFunc(pPager->pBusyHandler->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 ){    return rc;  }  /* Get an exclusive lock on the database before truncating. */  rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK);  if( rc!=SQLITE_OK ){    return rc;  }  rc = pager_truncate(pPager, 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 sqlite3pager_close(Pager *pPager){  PgHdr *pPg, *pNext;  switch( pPager->state ){    case PAGER_RESERVED:    case PAGER_SYNCED:     case PAGER_EXCLUSIVE: {      /* We ignore any IO errors that occur during the rollback      ** operation. So disable IO error simulation so that testing      ** works more easily.      */#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN))      extern int sqlite3_io_error_pending;      int ioerr_cnt = sqlite3_io_error_pending;      sqlite3_io_error_pending = -1;#endif      sqlite3pager_rollback(pPager);#if defined(SQLITE_TEST) && (defined(OS_UNIX) || defined(OS_WIN))      sqlite3_io_error_pending = ioerr_cnt;#endif      if( !MEMDB ){        sqlite3OsUnlock(&pPager->fd, NO_LOCK);      }      assert( pPager->journalOpen==0 );      break;    }    case PAGER_SHARED: {      if( !MEMDB ){        sqlite3OsUnlock(&pPager->fd, NO_LOCK);      }      break;    }    default: {      /* Do nothing */      break;    }  }  for(pPg=pPager->pAll; pPg; pPg=pNext){#ifndef NDEBUG    if( MEMDB ){      PgHistory *pHist = PGHDR_TO_HIST(pPg, pPager);      assert( !pPg->alwaysRollback );      assert( !pHist->pOrig );      assert( !pHist->pStmt );    }#endi

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -