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

📄 btree.c

📁 sqlite最新源码
💻 C
📖 第 1 页 / 共 5 页
字号:
  int nCell;  int cellOffset;  unsigned char *data;    data = pPage->aData;  assert( sqlite3PagerIswriteable(pPage->pDbPage) );  assert( pPage->pBt );  assert( sqlite3_mutex_held(pPage->pBt->mutex) );  assert( nByte>=0 );  /* Minimum cell size is 4 */  assert( pPage->nFree>=nByte );  assert( pPage->nOverflow==0 );  pPage->nFree -= (u16)nByte;  hdr = pPage->hdrOffset;  nFrag = data[hdr+7];  if( nFrag<60 ){    /* Search the freelist looking for a slot big enough to satisfy the    ** space request. */    addr = hdr+1;    while( (pc = get2byte(&data[addr]))>0 ){      size = get2byte(&data[pc+2]);      if( size>=nByte ){        int x = size - nByte;        if( size<nByte+4 ){          memcpy(&data[addr], &data[pc], 2);          data[hdr+7] = (u8)(nFrag + x);          return pc;        }else{          put2byte(&data[pc+2], x);          return pc + x;        }      }      addr = pc;    }  }  /* Allocate memory from the gap in between the cell pointer array  ** and the cell content area.  */  top = get2byte(&data[hdr+5]);  nCell = get2byte(&data[hdr+3]);  cellOffset = pPage->cellOffset;  if( nFrag>=60 || cellOffset + 2*nCell > top - nByte ){    defragmentPage(pPage);    top = get2byte(&data[hdr+5]);  }  top -= nByte;  assert( cellOffset + 2*nCell <= top );  put2byte(&data[hdr+5], top);  assert( sqlite3PagerIswriteable(pPage->pDbPage) );  return top;}/*** Return a section of the pPage->aData to the freelist.** The first byte of the new free block is pPage->aDisk[start]** and the size of the block is "size" bytes.**** Most of the effort here is involved in coalesing adjacent** free blocks into a single big free block.*/static int freeSpace(MemPage *pPage, int start, int size){  int addr, pbegin, hdr;  unsigned char *data = pPage->aData;  assert( pPage->pBt!=0 );  assert( sqlite3PagerIswriteable(pPage->pDbPage) );  assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) );  assert( (start + size)<=pPage->pBt->usableSize );  assert( sqlite3_mutex_held(pPage->pBt->mutex) );  assert( size>=0 );   /* Minimum cell size is 4 */#ifdef SQLITE_SECURE_DELETE  /* Overwrite deleted information with zeros when the SECURE_DELETE   ** option is enabled at compile-time */  memset(&data[start], 0, size);#endif  /* Add the space back into the linked list of freeblocks */  hdr = pPage->hdrOffset;  addr = hdr + 1;  while( (pbegin = get2byte(&data[addr]))<start && pbegin>0 ){    assert( pbegin<=pPage->pBt->usableSize-4 );    if( pbegin<=addr ) {      return SQLITE_CORRUPT_BKPT;    }    addr = pbegin;  }  if ( pbegin>pPage->pBt->usableSize-4 ) {    return SQLITE_CORRUPT_BKPT;  }  assert( pbegin>addr || pbegin==0 );  put2byte(&data[addr], start);  put2byte(&data[start], pbegin);  put2byte(&data[start+2], size);  pPage->nFree += (u16)size;  /* Coalesce adjacent free blocks */  addr = pPage->hdrOffset + 1;  while( (pbegin = get2byte(&data[addr]))>0 ){    int pnext, psize, x;    assert( pbegin>addr );    assert( pbegin<=pPage->pBt->usableSize-4 );    pnext = get2byte(&data[pbegin]);    psize = get2byte(&data[pbegin+2]);    if( pbegin + psize + 3 >= pnext && pnext>0 ){      int frag = pnext - (pbegin+psize);      if( (frag<0) || (frag>(int)data[pPage->hdrOffset+7]) ){        return SQLITE_CORRUPT_BKPT;      }      data[pPage->hdrOffset+7] -= (u8)frag;      x = get2byte(&data[pnext]);      put2byte(&data[pbegin], x);      x = pnext + get2byte(&data[pnext+2]) - pbegin;      put2byte(&data[pbegin+2], x);    }else{      addr = pbegin;    }  }  /* If the cell content area begins with a freeblock, remove it. */  if( data[hdr+1]==data[hdr+5] && data[hdr+2]==data[hdr+6] ){    int top;    pbegin = get2byte(&data[hdr+1]);    memcpy(&data[hdr+1], &data[pbegin], 2);    top = get2byte(&data[hdr+5]) + get2byte(&data[pbegin+2]);    put2byte(&data[hdr+5], top);  }  assert( sqlite3PagerIswriteable(pPage->pDbPage) );  return SQLITE_OK;}/*** Decode the flags byte (the first byte of the header) for a page** and initialize fields of the MemPage structure accordingly.**** Only the following combinations are supported.  Anything different** indicates a corrupt database files:****         PTF_ZERODATA**         PTF_ZERODATA | PTF_LEAF**         PTF_LEAFDATA | PTF_INTKEY**         PTF_LEAFDATA | PTF_INTKEY | PTF_LEAF*/static int decodeFlags(MemPage *pPage, int flagByte){  BtShared *pBt;     /* A copy of pPage->pBt */  assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );  assert( sqlite3_mutex_held(pPage->pBt->mutex) );  pPage->leaf = (u8)(flagByte>>3);  assert( PTF_LEAF == 1<<3 );  flagByte &= ~PTF_LEAF;  pPage->childPtrSize = 4-4*pPage->leaf;  pBt = pPage->pBt;  if( flagByte==(PTF_LEAFDATA | PTF_INTKEY) ){    pPage->intKey = 1;    pPage->hasData = pPage->leaf;    pPage->maxLocal = pBt->maxLeaf;    pPage->minLocal = pBt->minLeaf;  }else if( flagByte==PTF_ZERODATA ){    pPage->intKey = 0;    pPage->hasData = 0;    pPage->maxLocal = pBt->maxLocal;    pPage->minLocal = pBt->minLocal;  }else{    return SQLITE_CORRUPT_BKPT;  }  return SQLITE_OK;}/*** Initialize the auxiliary information for a disk block.**** Return SQLITE_OK on success.  If we see that the page does** not contain a well-formed database page, then return ** SQLITE_CORRUPT.  Note that a return of SQLITE_OK does not** guarantee that the page is well-formed.  It only shows that** we failed to detect any corruption.*/int sqlite3BtreeInitPage(MemPage *pPage){  assert( pPage->pBt!=0 );  assert( sqlite3_mutex_held(pPage->pBt->mutex) );  assert( pPage->pgno==sqlite3PagerPagenumber(pPage->pDbPage) );  assert( pPage == sqlite3PagerGetExtra(pPage->pDbPage) );  assert( pPage->aData == sqlite3PagerGetData(pPage->pDbPage) );  if( !pPage->isInit ){    u16 pc;            /* Address of a freeblock within pPage->aData[] */    u8 hdr;            /* Offset to beginning of page header */    u8 *data;          /* Equal to pPage->aData */    BtShared *pBt;        /* The main btree structure */    u16 usableSize;    /* Amount of usable space on each page */    u16 cellOffset;    /* Offset from start of page to first cell pointer */    u16 nFree;         /* Number of unused bytes on the page */    u16 top;           /* First byte of the cell content area */    pBt = pPage->pBt;    hdr = pPage->hdrOffset;    data = pPage->aData;    if( decodeFlags(pPage, data[hdr]) ) return SQLITE_CORRUPT_BKPT;    assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );    pPage->maskPage = pBt->pageSize - 1;    pPage->nOverflow = 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;    }      /* 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 ){      u16 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 = (u16)nFree;    if( nFree>=usableSize ){      /* Free space cannot exceed total page size */      return SQLITE_CORRUPT_BKPT;     }#if 0  /* Check that all the offsets in the cell offset array are within range.   **   ** Omitting this consistency check and using the pPage->maskPage mask  ** to prevent overrunning the page buffer in findCell() results in a  ** 2.5% performance gain.  */  {    u8 *pOff;        /* Iterator used to check all cell offsets are in range */    u8 *pEnd;        /* Pointer to end of cell offset array */    u8 mask;         /* Mask of bits that must be zero in MSB of cell offsets */    mask = ~(((u8)(pBt->pageSize>>8))-1);    pEnd = &data[cellOffset + pPage->nCell*2];    for(pOff=&data[cellOffset]; pOff!=pEnd && !((*pOff)&mask); pOff+=2);    if( pOff!=pEnd ){      return SQLITE_CORRUPT_BKPT;    }  }#endif    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;  u8 hdr = pPage->hdrOffset;  u16 first;  assert( sqlite3PagerPagenumber(pPage->pDbPage)==pPage->pgno );  assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );  assert( sqlite3PagerGetData(pPage->pDbPage) == data );  assert( sqlite3PagerIswriteable(pPage->pDbPage) );  assert( sqlite3_mutex_held(pBt->mutex) );  /*memset(&data[hdr], 0, pBt->usableSize - hdr);*/  data[hdr] = (char)flags;  first = hdr + 8 + 4*((flags&PTF_LEAF)==0 ?1: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;  assert( pBt->pageSize>=512 && pBt->pageSize<=32768 );  pPage->maskPage = pBt->pageSize - 1;  pPage->nCell = 0;  pPage->isInit = 1;}/*** Convert a DbPage obtained from the pager into a MemPage used by** the btree layer.*/static MemPage *btreePageFromDbPage(DbPage *pDbPage, Pgno pgno, BtShared *pBt){  MemPage *pPage = (MemPage*)sqlite3PagerGetExtra(pDbPage);  pPage->aData = sqlite3PagerGetData(pDbPage);  pPage->pDbPage = pDbPage;  pPage->pBt = pBt;  pPage->pgno = pgno;  pPage->hdrOffset = pPage->pgno==1 ? 100 : 0;  return pPage; }/*** 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;  DbPage *pDbPage;  assert( sqlite3_mutex_held(pBt->mutex) );  rc = sqlite3PagerAcquire(pBt->pPager, pgno, (DbPage**)&pDbPage, noContent);  if( rc ) return rc;  *ppPage = btreePageFromDbPage(pDbPage, pgno, pBt);  return SQLITE_OK;}/*** Retrieve a page from the pager cache. If the requested page is not** already in the pager cache return NULL. Initialize the MemPage.pBt and** MemPage.aData elements if needed.*/static MemPage *btreePageLookup(BtShared *pBt, Pgno pgno){  DbPage *pDbPage;  assert( sqlite3_mutex_held(pBt->mutex) );  pDbPage = sqlite3PagerLookup(pBt->pPager, pgno);  if( pDbPage ){    return btreePageFromDbPage(pDbPage, pgno, pBt);  }  return 0;}/*** Return the size of the database file in pages. If there is any kind of** error, return ((unsigned int)-1).*/static Pgno pagerPagecount(BtShared *pBt){  int nPage = -1;  int rc;  assert( pBt->pPage1 );  rc = sqlite3PagerPagecount(pBt->pPager, &nPage);  assert( rc==SQLITE_OK || nPage==-1 );  return (Pgno)nPage;}/*** 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 */){  int rc;  MemPage *pPage;  assert( sqlite3_mutex_held(pBt->mutex) );  if( pgno==0 ){    return SQLITE_CORRUPT_BKPT;   }  /* It is often the case that the page we want is already in cache.  ** If so, get it directly.  This saves us from having to call  ** pagerPagecount() to make sure pgno is within limits, which results  ** in a measureable performance improvements.  */  *ppPage = pPage = btreePageLookup(pBt, pgno);  if( pPage ){    /* Page is already in cache */    rc = SQLITE_OK;  }else{    /* Page not in cache.  Acquire it. */    if( pgno>pagerPagecount(pBt) ){      return SQLITE_CORRUPT_BKPT;     }    rc = sqlite3BtreeGetPage(pBt, pgno, ppPage, 0);    if( rc ) return rc;    pPage = *ppPage;  }  if( !pPage->isInit ){    rc = sqlite3BtreeInitPage(pPage);  }  if( rc!=SQLITE_OK ){    releasePage(pPage);    *ppPage = 0;  }  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->nOverflow==0 || sqlite3PagerPageRefcount(pPage->pDbPage)>1 );    assert( pPage->aData );    assert( pPage->pBt );    assert( sqlite3PagerGetExtra(pPage->pDbPage) == (void*)pPage );

⌨️ 快捷键说明

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