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

📄 btree.c

📁 sqlite-3.4.1,嵌入式数据库.是一个功能强大的开源数据库,给学习和研发以及小型公司的发展带来了全所未有的好处.
💻 C
📖 第 1 页 / 共 5 页
字号:
    pPage->pParent = pParent;    sqlite3PagerRef(pParent->pDbPage);  }  hdr = pPage->hdrOffset;  data = pPage->aData;  decodeFlags(pPage, data[hdr]);  pPage->nOverflow = 0;  pPage->idxShift = 0;  usableSize = pBt->usableSize;  pPage->cellOffset = cellOffset = hdr + 12 - 4*pPage->leaf;  top = get2byte(&data[hdr+5]);  pPage->nCell = get2byte(&data[hdr+3]);  if( pPage->nCell>MX_CELL(pBt) ){    /* To many cells for a single page.  The page must be corrupt */    return SQLITE_CORRUPT_BKPT;  }  if( pPage->nCell==0 && pParent!=0 && pParent->pgno!=1 ){    /* All pages must have at least one cell, except for root pages */    return SQLITE_CORRUPT_BKPT;  }  /* Compute the total free space on the page */  pc = get2byte(&data[hdr+1]);  nFree = data[hdr+7] + top - (cellOffset + 2*pPage->nCell);  while( pc>0 ){    int next, size;    if( pc>usableSize-4 ){      /* Free block is off the page */      return SQLITE_CORRUPT_BKPT;     }    next = get2byte(&data[pc]);    size = get2byte(&data[pc+2]);    if( next>0 && next<=pc+size+3 ){      /* Free blocks must be in accending order */      return SQLITE_CORRUPT_BKPT;     }    nFree += size;    pc = next;  }  pPage->nFree = nFree;  if( nFree>=usableSize ){    /* Free space cannot exceed total page size */    return SQLITE_CORRUPT_BKPT;   }  pPage->isInit = 1;  return SQLITE_OK;}/*** Set up a raw page so that it looks like a database page holding** no entries.*/static void zeroPage(MemPage *pPage, int flags){  unsigned char *data = pPage->aData;  BtShared *pBt = pPage->pBt;  int hdr = pPage->hdrOffset;  int first;  assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno );  assert( &data[pBt->pageSize] == (unsigned char*)pPage );  assert( sqlite3PagerIswriteable(pPage->pDbPage) );  memset(&data[hdr], 0, pBt->usableSize - hdr);  data[hdr] = flags;  first = hdr + 8 + 4*((flags&PTF_LEAF)==0);  memset(&data[hdr+1], 0, 4);  data[hdr+7] = 0;  put2byte(&data[hdr+5], pBt->usableSize);  pPage->nFree = pBt->usableSize - first;  decodeFlags(pPage, flags);  pPage->hdrOffset = hdr;  pPage->cellOffset = first;  pPage->nOverflow = 0;  pPage->idxShift = 0;  pPage->nCell = 0;  pPage->isInit = 1;}/*** Get a page from the pager.  Initialize the MemPage.pBt and** MemPage.aData elements if needed.**** If the noContent flag is set, it means that we do not care about** the content of the page at this time.  So do not go to the disk** to fetch the content.  Just fill in the content with zeros for now.** If in the future we call sqlite3PagerWrite() on this page, that** means we have started to be concerned about content and the disk** read should occur at that point.*/int sqlite3BtreeGetPage(  BtShared *pBt,       /* The btree */  Pgno pgno,           /* Number of the page to fetch */  MemPage **ppPage,    /* Return the page in this parameter */  int noContent        /* Do not load page content if true */){  int rc;  MemPage *pPage;  DbPage *pDbPage;  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent);  if( rc ) return rc;  pPage = (MemPage *)sqlite3PagerGetExtra(pDbPage);  pPage->aData = sqlite3PagerGetData(pDbPage);  pPage->pDbPage = pDbPage;  pPage->pBt = pBt;  pPage->pgno = pgno;  pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;  *ppPage = pPage;  return SQLITE_OK;}/*** Get a page from the pager and initialize it.  This routine** is just a convenience wrapper around separate calls to** sqlite3BtreeGetPage() and sqlite3BtreeInitPage().*/static int getAndInitPage(  BtShared *pBt,          /* The database file */  Pgno pgno,           /* Number of the page to get */  MemPage **ppPage,    /* Write the page pointer here */  MemPage *pParent     /* Parent of the page */){  int rc;  if( pgno==0 ){    return SQLITE_CORRUPT_BKPT;   }  rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0);  if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){    rc = sqlite3BtreeInitPage(*ppPage, pParent);  }  return rc;}/*** Release a MemPage.  This should be called once for each prior** call to sqlite3BtreeGetPage.*/static void releasePage(MemPage *pPage){  if( pPage ){    assert( pPage->aData );    assert( pPage->pBt );    assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage );    sqlite3PagerUnref(pPage->pDbPage);  }}/*** This routine is called when the reference count for a page** reaches zero.  We need to unref the pParent pointer when that** happens.*/static void pageDestructor(DbPage *pData, int pageSize){  MemPage *pPage;  assert( (pageSize & 7)==0 );  pPage = (MemPage *)sqlite3PagerGetExtra(pData);  if( pPage->pParent ){    MemPage *pParent = pPage->pParent;    pPage->pParent = 0;    releasePage(pParent);  }  pPage->isInit = 0;}/*** During a rollback, when the pager reloads information into the cache** so that the cache is restored to its original state at the start of** the transaction, for each page restored this routine is called.**** This routine needs to reset the extra data section at the end of the** page to agree with the restored data.*/static void pageReinit(DbPage *pData, int pageSize){  MemPage *pPage;  assert( (pageSize & 7)==0 );  pPage = (MemPage *)sqlite3PagerGetExtra(pData);  if( pPage->isInit ){    pPage->isInit = 0;    sqlite3BtreeInitPage(pPage, pPage->pParent);  }}/*** Open a database file.** ** zFilename is the name of the database file.  If zFilename is NULL** a new database with a random name is created.  This randomly named** database file will be deleted when sqlite3BtreeClose() is called.*/int sqlite3BtreeOpen(  const char *zFilename,  /* Name of the file containing the BTree database */  sqlite3 *pSqlite,       /* Associated database handle */  Btree **ppBtree,        /* Pointer to new Btree object written here */  int flags               /* Options */){  BtShared *pBt;          /* Shared part of btree structure */  Btree *p;               /* Handle to return */  int rc = SQLITE_OK;  int nReserve;  unsigned char zDbHeader[100];#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)  const ThreadData *pTsdro;#endif  /* Set the variable isMemdb to true for an in-memory database, or   ** false for a file-based database. This symbol is only required if  ** either of the shared-data or autovacuum features are compiled   ** into the library.  */#if !defined(SQLITE_OMIT_SHARED_CACHE) || !defined(SQLITE_OMIT_AUTOVACUUM)  #ifdef SQLITE_OMIT_MEMORYDB    const int isMemdb = 0;  #else    const int isMemdb = zFilename && !strcmp(zFilename, ":memory:");  #endif#endif  p = sqliteMalloc(sizeof(Btree));  if( !p ){    return SQLITE_NOMEM;  }  p->inTrans = TRANS_NONE;  p->pSqlite = pSqlite;  /* Try to find an existing Btree structure opened on zFilename. */#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)  pTsdro = sqlite3ThreadDataReadOnly();  if( pTsdro->useSharedData && zFilename && !isMemdb ){    char *zFullPathname = sqlite3OsFullPathname(zFilename);    if( !zFullPathname ){      sqliteFree(p);      return SQLITE_NOMEM;    }    for(pBt=pTsdro->pBtree; pBt; pBt=pBt->pNext){      assert( pBt->nRef>0 );      if( 0==strcmp(zFullPathname, sqlite3PagerFilename(pBt->pPager)) ){        p->pBt = pBt;        *ppBtree = p;        pBt->nRef++;        sqliteFree(zFullPathname);        return SQLITE_OK;      }    }    sqliteFree(zFullPathname);  }#endif  /*  ** The following asserts make sure that structures used by the btree are  ** the right size.  This is to guard against size changes that result  ** when compiling on a different architecture.  */  assert( sizeof(i64)==8 || sizeof(i64)==4 );  assert( sizeof(u64)==8 || sizeof(u64)==4 );  assert( sizeof(u32)==4 );  assert( sizeof(u16)==2 );  assert( sizeof(Pgno)==4 );  pBt = sqliteMalloc( sizeof(*pBt) );  if( pBt==0 ){    rc = SQLITE_NOMEM;    goto btree_open_out;  }  rc = sqlite3PagerOpen(&pBt->pPager, zFilename, EXTRA_SIZE, flags);  if( rc==SQLITE_OK ){    rc = sqlite3PagerReadFileheader(pBt->pPager,sizeof(zDbHeader),zDbHeader);  }  if( rc!=SQLITE_OK ){    goto btree_open_out;  }  p->pBt = pBt;  sqlite3PagerSetDestructor(pBt->pPager, pageDestructor);  sqlite3PagerSetReiniter(pBt->pPager, pageReinit);  pBt->pCursor = 0;  pBt->pPage1 = 0;  pBt->readOnly = sqlite3PagerIsreadonly(pBt->pPager);  pBt->pageSize = get2byte(&zDbHeader[16]);  if( pBt->pageSize<512 || pBt->pageSize>SQLITE_MAX_PAGE_SIZE       || ((pBt->pageSize-1)&pBt->pageSize)!=0 ){    pBt->pageSize = SQLITE_DEFAULT_PAGE_SIZE;    pBt->maxEmbedFrac = 64;   /* 25% */    pBt->minEmbedFrac = 32;   /* 12.5% */    pBt->minLeafFrac = 32;    /* 12.5% */#ifndef SQLITE_OMIT_AUTOVACUUM    /* If the magic name ":memory:" will create an in-memory database, then    ** leave the autoVacuum mode at 0 (do not auto-vacuum), even if    ** SQLITE_DEFAULT_AUTOVACUUM is true. On the other hand, if    ** SQLITE_OMIT_MEMORYDB has been defined, then ":memory:" is just a    ** regular file-name. In this case the auto-vacuum applies as per normal.    */    if( zFilename && !isMemdb ){      pBt->autoVacuum = (SQLITE_DEFAULT_AUTOVACUUM ? 1 : 0);      pBt->incrVacuum = (SQLITE_DEFAULT_AUTOVACUUM==2 ? 1 : 0);    }#endif    nReserve = 0;  }else{    nReserve = zDbHeader[20];    pBt->maxEmbedFrac = zDbHeader[21];    pBt->minEmbedFrac = zDbHeader[22];    pBt->minLeafFrac = zDbHeader[23];    pBt->pageSizeFixed = 1;#ifndef SQLITE_OMIT_AUTOVACUUM    pBt->autoVacuum = (get4byte(&zDbHeader[36 + 4*4])?1:0);    pBt->incrVacuum = (get4byte(&zDbHeader[36 + 7*4])?1:0);#endif  }  pBt->usableSize = pBt->pageSize - nReserve;  assert( (pBt->pageSize & 7)==0 );  /* 8-byte alignment of pageSize */  sqlite3PagerSetPagesize(pBt->pPager, pBt->pageSize);#if !defined(SQLITE_OMIT_SHARED_CACHE) && !defined(SQLITE_OMIT_DISKIO)  /* Add the new btree to the linked list starting at ThreadData.pBtree.  ** There is no chance that a malloc() may fail inside of the   ** sqlite3ThreadData() call, as the ThreadData structure must have already  ** been allocated for pTsdro->useSharedData to be non-zero.  */  if( pTsdro->useSharedData && zFilename && !isMemdb ){    pBt->pNext = pTsdro->pBtree;    sqlite3ThreadData()->pBtree = pBt;  }#endif  pBt->nRef = 1;  *ppBtree = p;btree_open_out:  if( rc!=SQLITE_OK ){    if( pBt && pBt->pPager ){      sqlite3PagerClose(pBt->pPager);    }    sqliteFree(pBt);    sqliteFree(p);    *ppBtree = 0;  }  return rc;}/*** Close an open database and invalidate all cursors.*/int sqlite3BtreeClose(Btree *p){  BtShared *pBt = p->pBt;  BtCursor *pCur;#ifndef SQLITE_OMIT_SHARED_CACHE  ThreadData *pTsd;#endif  /* Close all cursors opened via this handle.  */  pCur = pBt->pCursor;  while( pCur ){    BtCursor *pTmp = pCur;    pCur = pCur->pNext;    if( pTmp->pBtree==p ){      sqlite3BtreeCloseCursor(pTmp);    }  }  /* Rollback any active transaction and free the handle structure.  ** The call to sqlite3BtreeRollback() drops any table-locks held by  ** this handle.  */  sqlite3BtreeRollback(p);  sqliteFree(p);#ifndef SQLITE_OMIT_SHARED_CACHE  /* If there are still other outstanding references to the shared-btree  ** structure, return now. The remainder of this procedure cleans   ** up the shared-btree.  */  assert( pBt->nRef>0 );  pBt->nRef--;  if( pBt->nRef ){    return SQLITE_OK;  }  /* Remove the shared-btree from the thread wide list. Call   ** ThreadDataReadOnly() and then cast away the const property of the   ** pointer to avoid allocating thread data if it is not really required.  */  pTsd = (ThreadData *)sqlite3ThreadDataReadOnly();  if( pTsd->pBtree==pBt ){    assert( pTsd==sqlite3ThreadData() );    pTsd->pBtree = pBt->pNext;  }else{    BtShared *pPrev;    for(pPrev=pTsd->pBtree; pPrev && pPrev->pNext!=pBt; pPrev=pPrev->pNext){}    if( pPrev ){      assert( pTsd==sqlite3ThreadData() );      pPrev->pNext = pBt->pNext;    }  }#endif  /* Close the pager and free the shared-btree structure */  assert( !pBt->pCursor );  sqlite3PagerClose(pBt->pPager);  if( pBt->xFreeSchema && pBt->pSchema ){    pBt->xFreeSchema(pBt->pSchema);  }  sqliteFree(pBt->pSchema);  sqliteFree(pBt);  return SQLITE_OK;}/*** Change the busy handler callback function.*/int sqlite3BtreeSetBusyHandler(Btree *p, BusyHandler *pHandler){  BtShared *pBt = p->pBt;  pBt->pBusyHandler = pHandler;  sqlite3PagerSetBusyhandler(pBt->pPager, pHandler);  return SQLITE_OK;}/*** Change the limit on the number of pages allowed in the cache.**

⌨️ 快捷键说明

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