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

📄 btree.c

📁 轻量级数据库软件,嵌入式设计可以考虑考虑,性能不错
💻 C
📖 第 1 页 / 共 5 页
字号:
  if( pPage->nFree<nByte || pPage->nOverflow>0 ) return 0;  pPage->nFree -= 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 ){        if( size<nByte+4 ){          memcpy(&data[addr], &data[pc], 2);          data[hdr+7] = nFrag + size - nByte;          return pc;        }else{          put2byte(&data[pc+2], size-nByte);          return pc + size - nByte;        }      }      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 ){    if( defragmentPage(pPage) ) return 0;    top = get2byte(&data[hdr+5]);  }  top -= nByte;  assert( cellOffset + 2*nCell <= top );  put2byte(&data[hdr+5], top);  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 void freeSpace(MemPage *pPage, int start, int size){  int addr, pbegin, hdr;  unsigned char *data = pPage->aData;  assert( pPage->pBt!=0 );  assert( sqlite3pager_iswriteable(data) );  assert( start>=pPage->hdrOffset+6+(pPage->leaf?0:4) );  assert( (start + size)<=pPage->pBt->usableSize );  if( size<4 ) size = 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 );    assert( pbegin>addr );    addr = pbegin;  }  assert( pbegin<=pPage->pBt->usableSize-4 );  assert( pbegin>addr || pbegin==0 );  put2byte(&data[addr], start);  put2byte(&data[start], pbegin);  put2byte(&data[start+2], size);  pPage->nFree += size;  /* Coalesce adjacent free blocks */  addr = pPage->hdrOffset + 1;  while( (pbegin = get2byte(&data[addr]))>0 ){    int pnext, psize;    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);      assert( frag<=data[pPage->hdrOffset+7] );      data[pPage->hdrOffset+7] -= frag;      put2byte(&data[pbegin], get2byte(&data[pnext]));      put2byte(&data[pbegin+2], pnext+get2byte(&data[pnext+2])-pbegin);    }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]);    put2byte(&data[hdr+5], top + get2byte(&data[pbegin+2]));  }}/*** Decode the flags byte (the first byte of the header) for a page** and initialize fields of the MemPage structure accordingly.*/static void decodeFlags(MemPage *pPage, int flagByte){  BtShared *pBt;     /* A copy of pPage->pBt */  assert( pPage->hdrOffset==(pPage->pgno==1 ? 100 : 0) );  pPage->intKey = (flagByte & (PTF_INTKEY|PTF_LEAFDATA))!=0;  pPage->zeroData = (flagByte & PTF_ZERODATA)!=0;  pPage->leaf = (flagByte & PTF_LEAF)!=0;  pPage->childPtrSize = 4*(pPage->leaf==0);  pBt = pPage->pBt;  if( flagByte & PTF_LEAFDATA ){    pPage->leafData = 1;    pPage->maxLocal = pBt->maxLeaf;    pPage->minLocal = pBt->minLeaf;  }else{    pPage->leafData = 0;    pPage->maxLocal = pBt->maxLocal;    pPage->minLocal = pBt->minLocal;  }  pPage->hasData = !(pPage->zeroData || (!pPage->leaf && pPage->leafData));}/*** Initialize the auxiliary information for a disk block.**** The pParent parameter must be a pointer to the MemPage which** is the parent of the page being initialized.  The root of a** BTree has no parent and so for that page, pParent==NULL.**** 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.*/static int initPage(  MemPage *pPage,        /* The page to be initialized */  MemPage *pParent       /* The parent.  Might be NULL */){  int pc;            /* Address of a freeblock within pPage->aData[] */  int hdr;           /* Offset to beginning of page header */  u8 *data;          /* Equal to pPage->aData */  BtShared *pBt;        /* The main btree structure */  int usableSize;    /* Amount of usable space on each page */  int cellOffset;    /* Offset from start of page to first cell pointer */  int nFree;         /* Number of unused bytes on the page */  int top;           /* First byte of the cell content area */  pBt = pPage->pBt;  assert( pBt!=0 );  assert( pParent==0 || pParent->pBt==pBt );  assert( pPage->pgno==sqlite3pager_pagenumber(pPage->aData) );  assert( pPage->aData == &((unsigned char*)pPage)[-pBt->pageSize] );  if( pPage->pParent!=pParent && (pPage->pParent!=0 || pPage->isInit) ){    /* The parent page should never change unless the file is corrupt */    return SQLITE_CORRUPT_BKPT;  }  if( pPage->isInit ) return SQLITE_OK;  if( pPage->pParent==0 && pParent!=0 ){    pPage->pParent = pParent;    sqlite3pager_ref(pParent->aData);  }  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( sqlite3pager_pagenumber(data)==pPage->pgno );  assert( &data[pBt->pageSize] == (unsigned char*)pPage );  assert( sqlite3pager_iswriteable(data) );  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.*/static int getPage(BtShared *pBt, Pgno pgno, MemPage **ppPage){  int rc;  unsigned char *aData;  MemPage *pPage;  rc = sqlite3pager_get(pBt->pPager, pgno, (void**)&aData);  if( rc ) return rc;  pPage = (MemPage*)&aData[pBt->pageSize];  pPage->aData = aData;  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** getPage() and initPage().*/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 = getPage(pBt, pgno, ppPage);  if( rc==SQLITE_OK && (*ppPage)->isInit==0 ){    rc = initPage(*ppPage, pParent);  }  return rc;}/*** Release a MemPage.  This should be called once for each prior** call to getPage.*/static void releasePage(MemPage *pPage){  if( pPage ){    assert( pPage->aData );    assert( pPage->pBt );    assert( &pPage->aData[pPage->pBt->pageSize]==(unsigned char*)pPage );    sqlite3pager_unref(pPage->aData);  }}/*** 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(void *pData, int pageSize){  MemPage *pPage;  assert( (pageSize & 7)==0 );  pPage = (MemPage*)&((char*)pData)[pageSize];  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(void *pData, int pageSize){  MemPage *pPage;  assert( (pageSize & 7)==0 );  pPage = (MemPage*)&((char*)pData)[pageSize];  if( pPage->isInit ){    pPage->isInit = 0;    initPage(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;  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;  }

⌨️ 快捷键说明

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