📄 btree.c
字号:
** MemPage.aCell[] of the entry.*/struct BtCursor { Btree *pBtree; /* The Btree to which this cursor belongs */ BtCursor *pNext, *pPrev; /* Forms a linked list of all cursors */ int (*xCompare)(void*,int,const void*,int,const void*); /* Key comp func */ void *pArg; /* First arg to xCompare() */ Pgno pgnoRoot; /* The root page of this tree */ MemPage *pPage; /* Page that contains the entry */ int idx; /* Index of the entry in pPage->aCell[] */ CellInfo info; /* A parse of the cell we are pointing at */ u8 wrFlag; /* True if writable */ u8 eState; /* One of the CURSOR_XXX constants (see below) */#ifndef SQLITE_OMIT_SHARED_CACHE void *pKey; /* Saved key that was cursor's last known position */ i64 nKey; /* Size of pKey, or last integer key */ int skip; /* (skip<0) -> Prev() is a no-op. (skip>0) -> Next() is */#endif};/*** Potential values for BtCursor.eState. The first two values (VALID and ** INVALID) may occur in any build. The third (REQUIRESEEK) may only occur ** if sqlite was compiled without the OMIT_SHARED_CACHE symbol defined.**** CURSOR_VALID:** Cursor points to a valid entry. getPayload() etc. may be called.**** CURSOR_INVALID:** Cursor does not point to a valid entry. This can happen (for example) ** because the table is empty or because BtreeCursorFirst() has not been** called.**** CURSOR_REQUIRESEEK:** The table that this cursor was opened on still exists, but has been ** modified since the cursor was last used. The cursor position is saved** in variables BtCursor.pKey and BtCursor.nKey. When a cursor is in ** this state, restoreOrClearCursorPosition() can be called to attempt to** seek the cursor to the saved position.*/#define CURSOR_INVALID 0#define CURSOR_VALID 1#define CURSOR_REQUIRESEEK 2/*** The TRACE macro will print high-level status information about the** btree operation when the global variable sqlite3_btree_trace is** enabled.*/#if SQLITE_TEST# define TRACE(X) if( sqlite3_btree_trace )\ { sqlite3DebugPrintf X; fflush(stdout); }#else# define TRACE(X)#endifint sqlite3_btree_trace=0; /* True to enable tracing *//*** Forward declaration*/static int checkReadLocks(BtShared*,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 getVarint32(A,B) ((*B=*(A))<=0x7f?1:sqlite3GetVarint32(A,B))#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).**** If disk I/O is omitted (meaning that the database is stored purely** in memory) then there is no pending byte.*/#ifdef SQLITE_OMIT_DISKIO# define PENDING_BYTE_PAGE(pBt) 0x7fffffff#else# define PENDING_BYTE_PAGE(pBt) ((PENDING_BYTE/(pBt)->pageSize)+1)#endif/*** A linked list of the following structures is stored at BtShared.pLock.** Locks are added (or upgraded from READ_LOCK to WRITE_LOCK) when a cursor ** is opened on the table with root page BtShared.iTable. Locks are removed** from this list when a transaction is committed or rolled back, or when** a btree handle is closed.*/struct BtLock { Btree *pBtree; /* Btree handle holding this lock */ Pgno iTable; /* Root page of table */ u8 eLock; /* READ_LOCK or WRITE_LOCK */ BtLock *pNext; /* Next in BtShared.pLock list */};/* Candidate values for BtLock.eLock */#define READ_LOCK 1#define WRITE_LOCK 2#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) #define restoreOrClearCursorPosition(a,b) SQLITE_OK #define saveAllCursors(a,b,c) SQLITE_OK#elsestatic void releasePage(MemPage *pPage);/*** 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; } 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; if( sqlite3ThreadDataReadOnly()->useSharedData ){ 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;}/*** 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.*/static int restoreOrClearCursorPositionX(BtCursor *pCur, int doSeek){ int rc = SQLITE_OK; assert( sqlite3ThreadDataReadOnly()->useSharedData ); assert( pCur->eState==CURSOR_REQUIRESEEK ); pCur->eState = CURSOR_INVALID; if( doSeek ){ rc = sqlite3BtreeMoveto(pCur, pCur->pKey, pCur->nKey, &pCur->skip); } if( rc==SQLITE_OK ){ sqliteFree(pCur->pKey); pCur->pKey = 0; assert( CURSOR_VALID==pCur->eState || CURSOR_INVALID==pCur->eState ); } return rc;}#define restoreOrClearCursorPosition(p,x) \ (p->eState==CURSOR_REQUIRESEEK?restoreOrClearCursorPositionX(p,x):SQLITE_OK)/*** 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 */#ifndef SQLITE_OMIT_AUTOVACUUM/*** These macros define the location of the pointer-map entry for a
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -