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

📄 btree.c

📁 调用sqlite开源数据的小程序
💻 C
📖 第 1 页 / 共 5 页
字号:
#else# define TRACE(X)#endifint sqlite3_btree_trace=0;  /* True to enable tracing *//*** Forward declaration*/static int checkReadLocks(Btree*,Pgno,BtCursor*);/*** Read or write a two- and four-byte big-endian integer values.*/static u32 get2byte(unsigned char *p){  return (p[0]<<8) | p[1];}static u32 get4byte(unsigned char *p){  return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];}static void put2byte(unsigned char *p, u32 v){  p[0] = v>>8;  p[1] = v;}static void put4byte(unsigned char *p, u32 v){  p[0] = v>>24;  p[1] = v>>16;  p[2] = v>>8;  p[3] = v;}/*** Routines to read and write variable-length integers.  These used to** be defined locally, but now we use the varint routines in the util.c** file.*/#define getVarint    sqlite3GetVarint#define getVarint32  sqlite3GetVarint32#define putVarint    sqlite3PutVarint/* The database page the PENDING_BYTE occupies. This page is never used.** TODO: This macro is very similary to PAGER_MJ_PGNO() in pager.c. They** should possibly be consolidated (presumably in pager.h).*/#define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)#ifndef SQLITE_OMIT_AUTOVACUUM/*** These macros define the location of the pointer-map entry for a ** database page. The first argument to each is the number of usable** bytes on each page of the database (often 1024). The second is the** page number to look up in the pointer map.**** PTRMAP_PAGENO returns the database page number of the pointer-map** page that stores the required pointer. PTRMAP_PTROFFSET returns** the offset of the requested map entry.**** If the pgno argument passed to PTRMAP_PAGENO is a pointer-map page,** then pgno is returned. So (pgno==PTRMAP_PAGENO(pgsz, pgno)) can be** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements** this test.*/#define PTRMAP_PAGENO(pgsz, pgno) (((pgno-2)/(pgsz/5+1))*(pgsz/5+1)+2)#define PTRMAP_PTROFFSET(pgsz, pgno) (((pgno-2)%(pgsz/5+1)-1)*5)#define PTRMAP_ISPAGE(pgsz, pgno) (PTRMAP_PAGENO(pgsz,pgno)==pgno)/*** The pointer map is a lookup table that identifies the parent page for** each child page in the database file.  The parent page is the page that** contains a pointer to the child.  Every page in the database contains** 0 or 1 parent pages.  (In this context 'database page' refers** to any page that is not part of the pointer map itself.)  Each pointer map** entry consists of a single byte 'type' and a 4 byte parent page number.** The PTRMAP_XXX identifiers below are the valid types.**** The purpose of the pointer map is to facility moving pages from one** position in the file to another as part of autovacuum.  When a page** is moved, the pointer in its parent must be updated to point to the** new location.  The pointer map is used to locate the parent page quickly.**** PTRMAP_ROOTPAGE: The database page is a root-page. The page-number is not**                  used in this case.**** PTRMAP_FREEPAGE: The database page is an unused (free) page. The page-number **                  is not used in this case.**** PTRMAP_OVERFLOW1: The database page is the first page in a list of **                   overflow pages. The page number identifies the page that**                   contains the cell with a pointer to this overflow page.**** PTRMAP_OVERFLOW2: The database page is the second or later page in a list of**                   overflow pages. The page-number identifies the previous**                   page in the overflow page list.**** PTRMAP_BTREE: The database page is a non-root btree page. The page number**               identifies the parent page in the btree.*/#define PTRMAP_ROOTPAGE 1#define PTRMAP_FREEPAGE 2#define PTRMAP_OVERFLOW1 3#define PTRMAP_OVERFLOW2 4#define PTRMAP_BTREE 5/*** Write an entry into the pointer map.**** This routine updates the pointer map entry for page number 'key'** so that it maps to type 'eType' and parent page number 'pgno'.** An error code is returned if something goes wrong, otherwise SQLITE_OK.*/static int ptrmapPut(Btree *pBt, Pgno key, u8 eType, Pgno parent){  u8 *pPtrmap;    /* The pointer map page */  Pgno iPtrmap;   /* The pointer map page number */  int offset;     /* Offset in pointer map page */  int rc;  assert( pBt->autoVacuum );  if( key==0 ){    return SQLITE_CORRUPT_BKPT;  }  iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);  rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);  if( rc!=SQLITE_OK ){    return rc;  }  offset = PTRMAP_PTROFFSET(pBt->usableSize, key);  if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){    TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));    rc = sqlite3pager_write(pPtrmap);    if( rc==SQLITE_OK ){      pPtrmap[offset] = eType;      put4byte(&pPtrmap[offset+1], parent);    }  }  sqlite3pager_unref(pPtrmap);  return rc;}/*** Read an entry from the pointer map.**** This routine retrieves the pointer map entry for page 'key', writing** the type and parent page number to *pEType and *pPgno respectively.** An error code is returned if something goes wrong, otherwise SQLITE_OK.*/static int ptrmapGet(Btree *pBt, Pgno key, u8 *pEType, Pgno *pPgno){  int iPtrmap;       /* Pointer map page index */  u8 *pPtrmap;       /* Pointer map page data */  int offset;        /* Offset of entry in pointer map */  int rc;  iPtrmap = PTRMAP_PAGENO(pBt->usableSize, key);  rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);  if( rc!=0 ){    return rc;  }  offset = PTRMAP_PTROFFSET(pBt->usableSize, key);  if( pEType ) *pEType = pPtrmap[offset];  if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);  sqlite3pager_unref(pPtrmap);  if( *pEType<1 || *pEType>5 ) return SQLITE_CORRUPT_BKPT;  return SQLITE_OK;}#endif /* SQLITE_OMIT_AUTOVACUUM *//*** Given a btree page and a cell index (0 means the first cell on** the page, 1 means the second cell, and so forth) return a pointer** to the cell content.**** This routine works only for pages that do not contain overflow cells.*/static u8 *findCell(MemPage *pPage, int iCell){  u8 *data = pPage->aData;  assert( iCell>=0 );  assert( iCell<get2byte(&data[pPage->hdrOffset+3]) );  return data + get2byte(&data[pPage->cellOffset+2*iCell]);}/*** This a more complex version of findCell() that works for** pages that do contain overflow cells.  See insert*/static u8 *findOverflowCell(MemPage *pPage, int iCell){  int i;  for(i=pPage->nOverflow-1; i>=0; i--){    int k;    struct _OvflCell *pOvfl;    pOvfl = &pPage->aOvfl[i];    k = pOvfl->idx;    if( k<=iCell ){      if( k==iCell ){        return pOvfl->pCell;      }      iCell--;    }  }  return findCell(pPage, iCell);}/*** Parse a cell content block and fill in the CellInfo structure.  There** are two versions of this function.  parseCell() takes a cell index** as the second argument and parseCellPtr() takes a pointer to the** body of the cell as its second argument.*/static void parseCellPtr(  MemPage *pPage,         /* Page containing the cell */  u8 *pCell,              /* Pointer to the cell text. */  CellInfo *pInfo         /* Fill in this structure */){  int n;                  /* Number bytes in cell content header */  u32 nPayload;           /* Number of bytes of cell payload */  pInfo->pCell = pCell;  assert( pPage->leaf==0 || pPage->leaf==1 );  n = pPage->childPtrSize;  assert( n==4-4*pPage->leaf );  if( pPage->hasData ){    n += getVarint32(&pCell[n], &nPayload);  }else{    nPayload = 0;  }  n += getVarint(&pCell[n], (u64 *)&pInfo->nKey);  pInfo->nHeader = n;  pInfo->nData = nPayload;  if( !pPage->intKey ){    nPayload += pInfo->nKey;  }  if( nPayload<=pPage->maxLocal ){    /* This is the (easy) common case where the entire payload fits    ** on the local page.  No overflow is required.    */    int nSize;          /* Total size of cell content in bytes */    pInfo->nLocal = nPayload;    pInfo->iOverflow = 0;    nSize = nPayload + n;    if( nSize<4 ){      nSize = 4;        /* Minimum cell size is 4 */    }    pInfo->nSize = nSize;  }else{    /* If the payload will not fit completely on the local page, we have    ** to decide how much to store locally and how much to spill onto    ** overflow pages.  The strategy is to minimize the amount of unused    ** space on overflow pages while keeping the amount of local storage    ** in between minLocal and maxLocal.    **    ** Warning:  changing the way overflow payload is distributed in any    ** way will result in an incompatible file format.    */    int minLocal;  /* Minimum amount of payload held locally */    int maxLocal;  /* Maximum amount of payload held locally */    int surplus;   /* Overflow payload available for local storage */    minLocal = pPage->minLocal;    maxLocal = pPage->maxLocal;    surplus = minLocal + (nPayload - minLocal)%(pPage->pBt->usableSize - 4);    if( surplus <= maxLocal ){      pInfo->nLocal = surplus;    }else{      pInfo->nLocal = minLocal;    }    pInfo->iOverflow = pInfo->nLocal + n;    pInfo->nSize = pInfo->iOverflow + 4;  }}static void parseCell(  MemPage *pPage,         /* Page containing the cell */  int iCell,              /* The cell index.  First cell is 0 */  CellInfo *pInfo         /* Fill in this structure */){  parseCellPtr(pPage, findCell(pPage, iCell), pInfo);}/*** Compute the total number of bytes that a Cell needs in the cell** data area of the btree-page.  The return number includes the cell** data header and the local payload, but not any overflow page or** the space used by the cell pointer.*/#ifndef NDEBUGstatic int cellSize(MemPage *pPage, int iCell){  CellInfo info;  parseCell(pPage, iCell, &info);  return info.nSize;}#endifstatic int cellSizePtr(MemPage *pPage, u8 *pCell){  CellInfo info;  parseCellPtr(pPage, pCell, &info);  return info.nSize;}#ifndef SQLITE_OMIT_AUTOVACUUM/*** If the cell pCell, part of page pPage contains a pointer** to an overflow page, insert an entry into the pointer-map** for the overflow page.*/static int ptrmapPutOvflPtr(MemPage *pPage, u8 *pCell){  if( pCell ){    CellInfo info;    parseCellPtr(pPage, pCell, &info);    if( (info.nData+(pPage->intKey?0:info.nKey))>info.nLocal ){      Pgno ovfl = get4byte(&pCell[info.iOverflow]);      return ptrmapPut(pPage->pBt, ovfl, PTRMAP_OVERFLOW1, pPage->pgno);    }  }  return SQLITE_OK;}/*** If the cell with index iCell on page pPage contains a pointer** to an overflow page, insert an entry into the pointer-map** for the overflow page.*/static int ptrmapPutOvfl(MemPage *pPage, int iCell){  u8 *pCell;  pCell = findOverflowCell(pPage, iCell);  return ptrmapPutOvflPtr(pPage, pCell);}#endif/*** Do sanity checking on a page.  Throw an exception if anything is** not right.**** This routine is used for internal error checking only.  It is omitted** from most builds.*/#if defined(BTREE_DEBUG) && !defined(NDEBUG) && 0static void _pageIntegrity(MemPage *pPage){  int usableSize;  u8 *data;  int i, j, idx, c, pc, hdr, nFree;  int cellOffset;  int nCell, cellLimit;  u8 *used;  used = sqliteMallocRaw( pPage->pBt->pageSize );  if( used==0 ) return;  usableSize = pPage->pBt->usableSize;  assert( pPage->aData==&((unsigned char*)pPage)[-pPage->pBt->pageSize] );  hdr = pPage->hdrOffset;  assert( hdr==(pPage->pgno==1 ? 100 : 0) );  assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );  c = pPage->aData[hdr];  if( pPage->isInit ){    assert( pPage->leaf == ((c & PTF_LEAF)!=0) );    assert( pPage->zeroData == ((c & PTF_ZERODATA)!=0) );    assert( pPage->leafData == ((c & PTF_LEAFDATA)!=0) );    assert( pPage->intKey == ((c & (PTF_INTKEY|PTF_LEAFDATA))!=0) );    assert( pPage->hasData ==             !(pPage->zeroData || (!pPage->leaf && pPage->leafData)) );    assert( pPage->cellOffset==pPage->hdrOffset+12-4*pPage->leaf );    assert( pPage->nCell = get2byte(&pPage->aData[hdr+3]) );  }  data = pPage->aData;  memset(used, 0, usableSize);  for(i=0; i<hdr+10-pPage->leaf*4; i++) used[i] = 1;  nFree = 0;  pc = get2byte(&data[hdr+1]);  while( pc ){    int size;    assert( pc>0 && pc<usableSize-4 );    size = get2byte(&data[pc+2]);    assert( pc+size<=usableSize );    nFree += size;    for(i=pc; i<pc+size; i++){      assert( used[i]==0 );      used[i] = 1;    }    pc = get2byte(&data[pc]);  }

⌨️ 快捷键说明

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