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

📄 btree.c

📁 sqlite-3.4.1,嵌入式数据库.是一个功能强大的开源数据库,给学习和研发以及小型公司的发展带来了全所未有的好处.
💻 C
📖 第 1 页 / 共 5 页
字号:
/*** 2004 April 6**** The author disclaims copyright to this source code.  In place of** a legal notice, here is a blessing:****    May you do good and not evil.**    May you find forgiveness for yourself and forgive others.**    May you share freely, never taking more than you give.***************************************************************************** $Id: btree.c,v 1.392 2007/06/26 01:04:49 drh Exp $**** This file implements a external (disk-based) database using BTrees.** See the header comment on "btreeInt.h" for additional information.** Including a description of file format and an overview of operation.*/#include "btreeInt.h"/*** The header string that appears at the beginning of every** SQLite database.*/static const char zMagicHeader[] = SQLITE_FILE_HEADER;/*** Set this global variable to 1 to enable tracing using the TRACE** macro.*/#if SQLITE_TESTint sqlite3_btree_trace=0;  /* True to enable tracing */#endif/*** Forward declaration*/static int checkReadLocks(Btree*,Pgno,BtCursor*);#ifdef SQLITE_OMIT_SHARED_CACHE  /*  ** The functions queryTableLock(), lockTable() and unlockAllTables()  ** manipulate entries in the BtShared.pLock linked list used to store  ** shared-cache table level locks. If the library is compiled with the  ** shared-cache feature disabled, then there is only ever one user  ** of each BtShared structure and so this locking is not necessary.   ** So define the lock related functions as no-ops.  */  #define queryTableLock(a,b,c) SQLITE_OK  #define lockTable(a,b,c) SQLITE_OK  #define unlockAllTables(a)#else/*** Query to see if btree handle p may obtain a lock of type eLock ** (READ_LOCK or WRITE_LOCK) on the table with root-page iTab. Return** SQLITE_OK if the lock may be obtained (by calling lockTable()), or** SQLITE_LOCKED if not.*/static int queryTableLock(Btree *p, Pgno iTab, u8 eLock){  BtShared *pBt = p->pBt;  BtLock *pIter;  /* This is a no-op if the shared-cache is not enabled */  if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){    return SQLITE_OK;  }  /* This (along with lockTable()) is where the ReadUncommitted flag is  ** dealt with. If the caller is querying for a read-lock and the flag is  ** set, it is unconditionally granted - even if there are write-locks  ** on the table. If a write-lock is requested, the ReadUncommitted flag  ** is not considered.  **  ** In function lockTable(), if a read-lock is demanded and the   ** ReadUncommitted flag is set, no entry is added to the locks list   ** (BtShared.pLock).  **  ** To summarize: If the ReadUncommitted flag is set, then read cursors do  ** not create or respect table locks. The locking procedure for a   ** write-cursor does not change.  */  if(     !p->pSqlite ||     0==(p->pSqlite->flags&SQLITE_ReadUncommitted) ||     eLock==WRITE_LOCK ||    iTab==MASTER_ROOT  ){    for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){      if( pIter->pBtree!=p && pIter->iTable==iTab &&           (pIter->eLock!=eLock || eLock!=READ_LOCK) ){        return SQLITE_LOCKED;      }    }  }  return SQLITE_OK;}/*** Add a lock on the table with root-page iTable to the shared-btree used** by Btree handle p. Parameter eLock must be either READ_LOCK or ** WRITE_LOCK.**** SQLITE_OK is returned if the lock is added successfully. SQLITE_BUSY and** SQLITE_NOMEM may also be returned.*/static int lockTable(Btree *p, Pgno iTable, u8 eLock){  BtShared *pBt = p->pBt;  BtLock *pLock = 0;  BtLock *pIter;  /* This is a no-op if the shared-cache is not enabled */  if( 0==sqlite3ThreadDataReadOnly()->useSharedData ){    return SQLITE_OK;  }  assert( SQLITE_OK==queryTableLock(p, iTable, eLock) );  /* If the read-uncommitted flag is set and a read-lock is requested,  ** return early without adding an entry to the BtShared.pLock list. See  ** comment in function queryTableLock() for more info on handling   ** the ReadUncommitted flag.  */  if(     (p->pSqlite) &&     (p->pSqlite->flags&SQLITE_ReadUncommitted) &&     (eLock==READ_LOCK) &&    iTable!=MASTER_ROOT  ){    return SQLITE_OK;  }  /* First search the list for an existing lock on this table. */  for(pIter=pBt->pLock; pIter; pIter=pIter->pNext){    if( pIter->iTable==iTable && pIter->pBtree==p ){      pLock = pIter;      break;    }  }  /* If the above search did not find a BtLock struct associating Btree p  ** with table iTable, allocate one and link it into the list.  */  if( !pLock ){    pLock = (BtLock *)sqliteMalloc(sizeof(BtLock));    if( !pLock ){      return SQLITE_NOMEM;    }    pLock->iTable = iTable;    pLock->pBtree = p;    pLock->pNext = pBt->pLock;    pBt->pLock = pLock;  }  /* Set the BtLock.eLock variable to the maximum of the current lock  ** and the requested lock. This means if a write-lock was already held  ** and a read-lock requested, we don't incorrectly downgrade the lock.  */  assert( WRITE_LOCK>READ_LOCK );  if( eLock>pLock->eLock ){    pLock->eLock = eLock;  }  return SQLITE_OK;}/*** Release all the table locks (locks obtained via calls to the lockTable()** procedure) held by Btree handle p.*/static void unlockAllTables(Btree *p){  BtLock **ppIter = &p->pBt->pLock;  /* If the shared-cache extension is not enabled, there should be no  ** locks in the BtShared.pLock list, making this procedure a no-op. Assert  ** that this is the case.  */  assert( sqlite3ThreadDataReadOnly()->useSharedData || 0==*ppIter );  while( *ppIter ){    BtLock *pLock = *ppIter;    if( pLock->pBtree==p ){      *ppIter = pLock->pNext;      sqliteFree(pLock);    }else{      ppIter = &pLock->pNext;    }  }}#endif /* SQLITE_OMIT_SHARED_CACHE */static void releasePage(MemPage *pPage);  /* Forward reference */#ifndef SQLITE_OMIT_INCRBLOB/*** Invalidate the overflow page-list cache for cursor pCur, if any.*/static void invalidateOverflowCache(BtCursor *pCur){  sqliteFree(pCur->aOverflow);  pCur->aOverflow = 0;}/*** Invalidate the overflow page-list cache for all cursors opened** on the shared btree structure pBt.*/static void invalidateAllOverflowCache(BtShared *pBt){  BtCursor *p;  for(p=pBt->pCursor; p; p=p->pNext){    invalidateOverflowCache(p);  }}#else  #define invalidateOverflowCache(x)  #define invalidateAllOverflowCache(x)#endif/*** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.*/static int saveCursorPosition(BtCursor *pCur){  int rc;  assert( CURSOR_VALID==pCur->eState );  assert( 0==pCur->pKey );  rc = sqlite3BtreeKeySize(pCur, &pCur->nKey);  /* If this is an intKey table, then the above call to BtreeKeySize()  ** stores the integer key in pCur->nKey. In this case this value is  ** all that is required. Otherwise, if pCur is not open on an intKey  ** table, then malloc space for and store the pCur->nKey bytes of key   ** data.  */  if( rc==SQLITE_OK && 0==pCur->pPage->intKey){    void *pKey = sqliteMalloc(pCur->nKey);    if( pKey ){      rc = sqlite3BtreeKey(pCur, 0, pCur->nKey, pKey);      if( rc==SQLITE_OK ){        pCur->pKey = pKey;      }else{        sqliteFree(pKey);      }    }else{      rc = SQLITE_NOMEM;    }  }  assert( !pCur->pPage->intKey || !pCur->pKey );  if( rc==SQLITE_OK ){    releasePage(pCur->pPage);    pCur->pPage = 0;    pCur->eState = CURSOR_REQUIRESEEK;  }  invalidateOverflowCache(pCur);  return rc;}/*** Save the positions of all cursors except pExcept open on the table ** with root-page iRoot. Usually, this is called just before cursor** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()).*/static int saveAllCursors(BtShared *pBt, Pgno iRoot, BtCursor *pExcept){  BtCursor *p;  for(p=pBt->pCursor; p; p=p->pNext){    if( p!=pExcept && (0==iRoot || p->pgnoRoot==iRoot) &&         p->eState==CURSOR_VALID ){      int rc = saveCursorPosition(p);      if( SQLITE_OK!=rc ){        return rc;      }    }  }  return SQLITE_OK;}/*** Clear the current cursor position.*/static void clearCursorPosition(BtCursor *pCur){  sqliteFree(pCur->pKey);  pCur->pKey = 0;  pCur->eState = CURSOR_INVALID;}/*** Restore the cursor to the position it was in (or as close to as possible)** when saveCursorPosition() was called. Note that this call deletes the ** saved position info stored by saveCursorPosition(), so there can be** at most one effective restoreOrClearCursorPosition() call after each ** saveCursorPosition().**** If the second argument argument - doSeek - is false, then instead of ** returning the cursor to it's saved position, any saved position is deleted** and the cursor state set to CURSOR_INVALID.*/int sqlite3BtreeRestoreOrClearCursorPosition(BtCursor *pCur){  int rc;  assert( pCur->eState==CURSOR_REQUIRESEEK );#ifndef SQLITE_OMIT_INCRBLOB  if( pCur->isIncrblobHandle ){    return SQLITE_ABORT;  }#endif  pCur->eState = CURSOR_INVALID;  rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, 0, &pCur->skip);  if( rc==SQLITE_OK ){    sqliteFree(pCur->pKey);    pCur->pKey = 0;    assert( pCur->eState==CURSOR_VALID || pCur->eState==CURSOR_INVALID );  }  return rc;}#define restoreOrClearCursorPosition(p) \  (p->eState==CURSOR_REQUIRESEEK ? \         sqlite3BtreeRestoreOrClearCursorPosition(p) : \         SQLITE_OK)#ifndef SQLITE_OMIT_AUTOVACUUM/*** Given a page number of a regular database page, return the page** number for the pointer-map page that contains the entry for the** input page number.*/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;}/*** 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){  DbPage *pDbPage;  /* The pointer map page */  u8 *pPtrmap;      /* The pointer map data */  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 = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);  if( rc!=SQLITE_OK ){    return rc;  }  offset = PTRMAP_PTROFFSET(pBt, key);  pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);  if( eType!=pPtrmap[offset] || get4byte(&pPtrmap[offset+1])!=parent ){    TRACE(("PTRMAP_UPDATE: %d->(%d,%d)\n", key, eType, parent));    rc = sqlite3PagerWrite(pDbPage);    if( rc==SQLITE_OK ){      pPtrmap[offset] = eType;      put4byte(&pPtrmap[offset+1], parent);    }  }  sqlite3PagerUnref(pDbPage);  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){  DbPage *pDbPage;   /* The pointer map page */  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 = sqlite3PagerGet(pBt->pPager, iPtrmap, &pDbPage);  if( rc!=0 ){    return rc;  }  pPtrmap = (u8 *)sqlite3PagerGetData(pDbPage);  offset = PTRMAP_PTROFFSET(pBt, key);  assert( pEType!=0 );  *pEType = pPtrmap[offset];  if( pPgno ) *pPgno = get4byte(&pPtrmap[offset+1]);  sqlite3PagerUnref(pDbPage);  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.

⌨️ 快捷键说明

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