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

📄 btree.c

📁 轻量级数据库软件,嵌入式设计可以考虑考虑,性能不错
💻 C
📖 第 1 页 / 共 5 页
字号:
** used to test if pgno is a pointer-map page. PTRMAP_ISPAGE implements** this test.*/#define PTRMAP_PAGENO(pBt, pgno) ptrmapPageno(pBt, pgno)#define PTRMAP_PTROFFSET(pBt, pgno) (5*(pgno-ptrmapPageno(pBt, pgno)-1))#define PTRMAP_ISPAGE(pBt, pgno) (PTRMAP_PAGENO((pBt),(pgno))==(pgno))static Pgno ptrmapPageno(BtShared *pBt, Pgno pgno){  int nPagesPerMapPage = (pBt->usableSize/5)+1;  int iPtrMap = (pgno-2)/nPagesPerMapPage;  int ret = (iPtrMap*nPagesPerMapPage) + 2;   if( ret==PENDING_BYTE_PAGE(pBt) ){    ret++;  }  return ret;}/*** 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(BtShared *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;  /* The master-journal page number must never be used as a pointer map page */  assert( 0==PTRMAP_ISPAGE(pBt, PENDING_BYTE_PAGE(pBt)) );  assert( pBt->autoVacuum );  if( key==0 ){    return SQLITE_CORRUPT_BKPT;  }  iPtrmap = PTRMAP_PAGENO(pBt, key);  rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);  if( rc!=SQLITE_OK ){    return rc;  }  offset = PTRMAP_PTROFFSET(pBt, 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(BtShared *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, key);  rc = sqlite3pager_get(pBt->pPager, iPtrmap, (void **)&pPtrmap);  if( rc!=0 ){    return rc;  }  offset = PTRMAP_PTROFFSET(pBt, key);  assert( pEType!=0 );  *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;  }  pInfo->nData = nPayload;  if( pPage->intKey ){    n += getVarint(&pCell[n], (u64 *)&pInfo->nKey);  }else{    u32 x;    n += getVarint32(&pCell[n], &x);    pInfo->nKey = x;    nPayload += x;  }  pInfo->nHeader = n;  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/* A bunch of assert() statements to check the transaction state variables** of handle p (type Btree*) are internally consistent.*/#define btreeIntegrity(p) \  assert( p->inTrans!=TRANS_NONE || p->pBt->nTransaction<p->pBt->nRef ); \  assert( p->pBt->nTransaction<=p->pBt->nRef ); \  assert( p->pBt->inTransaction!=TRANS_NONE || p->pBt->nTransaction==0 ); \  assert( p->pBt->inTransaction>=p->inTrans ); /*** Defragment the page given.  All Cells are moved to the** end of the page and all free space is collected into one** big FreeBlk that occurs in between the header and cell** pointer array and the cell content area.*/static int defragmentPage(MemPage *pPage){  int i;                     /* Loop counter */  int pc;                    /* Address of a i-th cell */  int addr;                  /* Offset of first byte after cell pointer array */  int hdr;                   /* Offset to the page header */  int size;                  /* Size of a cell */  int usableSize;            /* Number of usable bytes on a page */  int cellOffset;            /* Offset to the cell pointer array */  int brk;                   /* Offset to the cell content area */  int nCell;                 /* Number of cells on the page */  unsigned char *data;       /* The page data */  unsigned char *temp;       /* Temp area for cell content */  assert( sqlite3pager_iswriteable(pPage->aData) );  assert( pPage->pBt!=0 );  assert( pPage->pBt->usableSize <= SQLITE_MAX_PAGE_SIZE );  assert( pPage->nOverflow==0 );  temp = sqliteMalloc( pPage->pBt->pageSize );  if( temp==0 ) return SQLITE_NOMEM;  data = pPage->aData;  hdr = pPage->hdrOffset;  cellOffset = pPage->cellOffset;  nCell = pPage->nCell;  assert( nCell==get2byte(&data[hdr+3]) );  usableSize = pPage->pBt->usableSize;  brk = get2byte(&data[hdr+5]);  memcpy(&temp[brk], &data[brk], usableSize - brk);  brk = usableSize;  for(i=0; i<nCell; i++){    u8 *pAddr;     /* The i-th cell pointer */    pAddr = &data[cellOffset + i*2];    pc = get2byte(pAddr);    assert( pc<pPage->pBt->usableSize );    size = cellSizePtr(pPage, &temp[pc]);    brk -= size;    memcpy(&data[brk], &temp[pc], size);    put2byte(pAddr, brk);  }  assert( brk>=cellOffset+2*nCell );  put2byte(&data[hdr+5], brk);  data[hdr+1] = 0;  data[hdr+2] = 0;  data[hdr+7] = 0;  addr = cellOffset+2*nCell;  memset(&data[addr], 0, brk-addr);  sqliteFree(temp);  return SQLITE_OK;}/*** Allocate nByte bytes of space on a page.**** Return the index into pPage->aData[] of the first byte of** the new allocation. Or return 0 if there is not enough free** space on the page to satisfy the allocation request.**** If the page contains nBytes of free space but does not contain** nBytes of contiguous free space, then this routine automatically** calls defragementPage() to consolidate all free space before ** allocating the new chunk.*/static int allocateSpace(MemPage *pPage, int nByte){  int addr, pc, hdr;  int size;  int nFrag;  int top;  int nCell;  int cellOffset;  unsigned char *data;    data = pPage->aData;  assert( sqlite3pager_iswriteable(data) );  assert( pPage->pBt );  if( nByte<4 ) nByte = 4;

⌨️ 快捷键说明

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