/*
** Move data out of a btree key or data field and into a Mem structure.
** The data or key is taken from the entry that pCur is currently pointing
** to. offset and amt determine what portion of the data or key to retrieve.
** key is true to get the key or false to get data. The result is written
** into the pMem element.
**
** The pMem structure is assumed to be uninitialized. Any prior content
** is overwritten without being freed.
**
** If this routine fails for any reason (malloc returns NULL or unable
** to read from the disk) then the pMem is left in an inconsistent state.
*/
private static int sqlite3VdbeMemFromBtree(
BtCursor pCur, /* Cursor pointing at record to retrieve. */
int offset, /* Offset from the start of data to return bytes from. */
int amt, /* Number of bytes to return. */
bool key, /* If true, retrieve from the btree key, not data. */
Mem pMem /* OUT: Return data in this Mem structure. */
)
{
byte[] zData; /* Data from the btree layer */
int available = 0; /* Number of bytes available on the local btree page */
int rc = SQLITE_OK; /* Return code */
Debug.Assert(sqlite3BtreeCursorIsValid(pCur));
/* Note: the calls to BtreeKeyFetch() and DataFetch() below assert()
** that both the BtShared and database handle mutexes are held. */
Debug.Assert((pMem.flags & MEM_RowSet) == 0);
int outOffset = -1;
if (key)
{
zData = sqlite3BtreeKeyFetch(pCur, ref available, ref outOffset);
}
else
{
zData = sqlite3BtreeDataFetch(pCur, ref available, ref outOffset);
}
Debug.Assert(zData != null);
if (offset + amt <= available && (pMem.flags & MEM_Dyn) == 0)
{
sqlite3VdbeMemRelease(pMem);
pMem.zBLOB = sqlite3Malloc(amt);
Buffer.BlockCopy(zData, offset, pMem.zBLOB, 0, amt);//pMem.z = &zData[offset];
pMem.flags = MEM_Blob | MEM_Ephem;
}
else if (SQLITE_OK == (rc = sqlite3VdbeMemGrow(pMem, amt + 2, 0)))
{
pMem.enc = 0;
pMem.type = SQLITE_BLOB;
pMem.z = null;
pMem.zBLOB = sqlite3Malloc(amt);
pMem.flags = MEM_Blob | MEM_Dyn | MEM_Term;
if (key)
{
rc = sqlite3BtreeKey(pCur, (u32)offset, (u32)amt, pMem.zBLOB);
}
else
{
rc = sqlite3BtreeData(pCur, (u32)offset, (u32)amt, pMem.zBLOB);//pMem.z = pMem_z ;
}
//pMem.z[amt] = 0;
//pMem.z[amt+1] = 0;
if (rc != SQLITE_OK)
{
sqlite3VdbeMemRelease(pMem);
}
}
pMem.n = amt;
sqlite3_free(ref zData);
return rc;
}
public static RC PutData(BtCursor cur, uint offset, uint amount, byte[] z)
{
Debug.Assert(cursorHoldsMutex(cur));
Debug.Assert(MutexEx.Held(cur.Btree.Ctx.Mutex));
Debug.Assert(cur.IsIncrblobHandle);
RC rc = restoreCursorPosition(cur);
if (rc != RC.OK)
return rc;
Debug.Assert(cur.State != CURSOR.REQUIRESEEK);
if (cur.State != CURSOR.VALID)
return RC.ABORT;
// Check some assumptions:
// (a) the cursor is open for writing,
// (b) there is a read/write transaction open,
// (c) the connection holds a write-lock on the table (if required),
// (d) there are no conflicting read-locks, and
// (e) the cursor points at a valid row of an intKey table.
if (!cur.WrFlag)
return RC.READONLY;
Debug.Assert((cur.Bt.BtsFlags & BTS.READ_ONLY) == 0 && cur.Bt.InTransaction == TRANS.WRITE);
Debug.Assert(hasSharedCacheTableLock(cur.Btree, cur.RootID, false, LOCK.WRITE));
Debug.Assert(!hasReadConflicts(cur.Btree, cur.RootID));
Debug.Assert(cur.Pages[cur.ID].IntKey);
return accessPayload(cur, offset, amount, z, 1);
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:28,代码来源:Btree.cs
示例7: Delete
public static RC Delete(BtCursor cur)
{
Btree p = cur.Btree;
BtShared bt = p.Bt;
Debug.Assert(cursorHoldsMutex(cur));
Debug.Assert(bt.InTransaction == TRANS.WRITE);
Debug.Assert((bt.BtsFlags & BTS.READ_ONLY) == 0);
Debug.Assert(cur.WrFlag);
Debug.Assert(hasSharedCacheTableLock(p, cur.RootID, cur.KeyInfo != null, LOCK.WRITE));
Debug.Assert(!hasReadConflicts(p, cur.RootID));
if (C._NEVER(cur.Idxs[cur.ID] >= cur.Pages[cur.ID].Cells) || C._NEVER(cur.State != CURSOR.VALID))
return RC.ERROR; // Something has gone awry.
int cellDepth = cur.ID; // Depth of node containing pCell
uint cellIdx = cur.Idxs[cellDepth]; // Index of cell to delete
MemPage page = cur.Pages[cellDepth]; // Page to delete cell from
uint cell_ = findCell(page, cellIdx); // Pointer to cell to delete
// If the page containing the entry to delete is not a leaf page, move the cursor to the largest entry in the tree that is smaller than
// the entry being deleted. This cell will replace the cell being deleted from the internal node. The 'previous' entry is used for this instead
// of the 'next' entry, as the previous entry is always a part of the sub-tree headed by the child page of the cell being deleted. This makes
// balancing the tree following the delete operation easier.
RC rc;
if (!page.Leaf)
{
int notUsed = 0;
rc = Previous(cur, ref notUsed);
if (rc != RC.OK) return rc;
}
// Save the positions of any other cursors open on this table before making any modifications. Make the page containing the entry to be
// deleted writable. Then free any overflow pages associated with the entry and finally remove the cell itself from within the page.
rc = saveAllCursors(bt, cur.RootID, cur);
if (rc != RC.OK) return rc;
// If this is a delete operation to remove a row from a table b-tree, invalidate any incrblob cursors open on the row being deleted.
if (cur.KeyInfo == null)
invalidateIncrblobCursors(p, cur.Info.Key, false);
rc = Pager.Write(page.DBPage);
if (rc != RC.OK) return rc;
rc = clearCell(page, cell_);
dropCell(page, cellIdx, cellSizePtr(page, cell_), ref rc);
if (rc != RC.OK) return rc;
// If the cell deleted was not located on a leaf page, then the cursor is currently pointing to the largest entry in the sub-tree headed
// by the child-page of the cell that was just deleted from an internal node. The cell from the leaf node needs to be moved to the internal
// node to replace the deleted cell.
if (!page.Leaf)
{
MemPage leaf = cur.Pages[cur.ID];
Pid n = cur.Pages[cellDepth + 1].ID;
cell_ = findCell(leaf, (uint)leaf.Cells - 1);
ushort sizeCell = cellSizePtr(leaf, cell_);
Debug.Assert(MX_CELL_SIZE(bt) >= sizeCell);
//allocateTempSpace(bt);
//byte[] tmp = Bt.TmpSpace;
rc = Pager.Write(leaf.DBPage);
{ byte[] cell_4 = new byte[sizeCell + 4]; Buffer.BlockCopy(leaf.Data, (int)cell_ - 4, cell_4, 0, (int)sizeCell + 4); insertCell(page, cellIdx, cell_4, (ushort)(sizeCell + 4), null, n, ref rc); }
dropCell(leaf, (uint)(leaf.Cells - 1), sizeCell, ref rc);
if (rc != RC.OK) return rc;
}
// Balance the tree. If the entry deleted was located on a leaf page, then the cursor still points to that page. In this case the first
// call to balance() repairs the tree, and the if(...) condition is never true.
//
// Otherwise, if the entry deleted was on an internal node page, then pCur is pointing to the leaf page from which a cell was removed to
// replace the cell deleted from the internal node. This is slightly tricky as the leaf node may be underfull, and the internal node may
// be either under or overfull. In this case run the balancing algorithm on the leaf node first. If the balance proceeds far enough up the
// tree that we can be sure that any problem in the internal node has been corrected, so be it. Otherwise, after balancing the leaf node,
// walk the cursor up the tree to the internal node and balance it as well.
rc = balance(cur);
if (rc == RC.OK && cur.ID > cellDepth)
{
while (cur.ID > cellDepth)
releasePage(cur.Pages[cur.ID--]);
rc = balance(cur);
}
if (rc == RC.OK)
moveToRoot(cur);
return rc;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:87,代码来源:Btree.cs
示例8: saveCursorPosition
static RC saveCursorPosition(BtCursor cur)
{
Debug.Assert(cur.State == CURSOR.VALID);
Debug.Assert(cur.Key == null);
Debug.Assert(cursorHoldsMutex(cur));
var rc = KeySize(cur, ref cur.KeyLength);
Debug.Assert(rc == RC.OK); // KeySize() cannot fail
// 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 (!cur.Pages[0].IntKey)
{
var key = C._alloc((int)cur.KeyLength);
rc = Key(cur, 0, (uint)cur.KeyLength, key);
if (rc == RC.OK)
cur.Key = key;
}
Debug.Assert(!cur.Pages[0].IntKey || cur.Key == null);
if (rc == RC.OK)
{
btreeReleaseAllCursorPages(cur);
cur.State = CURSOR.REQUIRESEEK;
}
invalidateOverflowCache(cur);
return rc;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:29,代码来源:Btree.cs
示例9: Next_
public static RC Next_(BtCursor cur, ref int res)
{
Debug.Assert(cursorHoldsMutex(cur));
var rc = restoreCursorPosition(cur);
if (rc != RC.OK)
return rc;
if (cur.State == CURSOR.INVALID)
{
res = 1;
return RC.OK;
}
if (cur.SkipNext > 0)
{
cur.SkipNext = 0;
res = 0;
return RC.OK;
}
cur.SkipNext = 0;
MemPage page = cur.Pages[cur.ID];
uint idx = ++cur.Idxs[cur.ID];
Debug.Assert(page.IsInit);
cur.Info.Size = 0;
cur.ValidNKey = false;
if (idx >= page.Cells)
{
if (!page.Leaf)
{
rc = moveToChild(cur, ConvertEx.Get4(page.Data, page.HdrOffset + 8));
if (rc != RC.OK) return rc;
rc = moveToLeftmost(cur);
res = 0;
return rc;
}
do
{
if (cur.ID == 0)
{
res = 1;
cur.State = CURSOR.INVALID;
return RC.OK;
}
moveToParent(cur);
page = cur.Pages[cur.ID];
} while (cur.Idxs[cur.ID] >= page.Cells);
res = 0;
if (page.IntKey)
rc = Next_(cur, ref res);
else
rc = RC.OK;
return rc;
}
res = 0;
if (page.Leaf)
return RC.OK;
rc = moveToLeftmost(cur);
return rc;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:59,代码来源:Btree.cs
示例10: Eof
public static bool Eof(BtCursor cur)
{
// TODO: What if the cursor is in CURSOR_REQUIRESEEK but all table entries have been deleted? This API will need to change to return an error code
// as well as the boolean result value.
return (cur.State != CURSOR.VALID);
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:6,代码来源:Btree.cs
示例11: btreeReleaseAllCursorPages
static void btreeReleaseAllCursorPages(BtCursor cur)
{
for (int i = 0; i <= cur.ID; i++)
{
releasePage(cur.Pages[i]);
cur.Pages[i] = null;
}
cur.ID = -1;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:9,代码来源:Btree.cs
示例12: MovetoUnpacked
public static RC MovetoUnpacked(BtCursor cur, UnpackedRecord idxKey, long intKey, int biasRight, out int res)
{
Debug.Assert(cursorHoldsMutex(cur));
Debug.Assert(MutexEx.Held(cur.Btree.Ctx.Mutex));
Debug.Assert((idxKey == null) == (cur.KeyInfo == null));
// If the cursor is already positioned at the point we are trying to move to, then just return without doing any work
if (cur.State == CURSOR.VALID && cur.ValidNKey && cur.Pages[0].IntKey)
{
if (cur.Info.Key == intKey)
{
res = 0;
return RC.OK;
}
if (cur.AtLast != 0 && cur.Info.Key < intKey)
{
res = -1;
return RC.OK;
}
}
res = -1;
var rc = moveToRoot(cur);
if (rc != RC.OK)
return rc;
Debug.Assert(cur.RootID == 0 || cur.Pages[cur.ID] != null);
Debug.Assert(cur.RootID == 0 || cur.Pages[cur.ID].IsInit);
Debug.Assert(cur.State == CURSOR.INVALID || cur.Pages[cur.ID].Cells > 0);
if (cur.State == CURSOR.INVALID)
{
res = -1;
Debug.Assert(cur.RootID == 0 || cur.Pages[cur.ID].Cells == 0);
return RC.OK;
}
Debug.Assert(cur.Pages[0].IntKey || idxKey != null);
int c;
for (; ; )
{
// pPage->nCell must be greater than zero. If this is the root-page the cursor would have been INVALID above and this for(;;) loop
// not run. If this is not the root-page, then the moveToChild() routine would have already detected db corruption. Similarly, pPage must
// be the right kind (index or table) of b-tree page. Otherwise a moveToChild() or moveToRoot() call would have detected corruption.
MemPage page = cur.Pages[cur.ID];
Debug.Assert(page.Cells > 0);
Debug.Assert(page.IntKey == (idxKey == null));
uint idx;
uint lwr = 0;
uint upr = (uint)(page.Cells - 1);
if (biasRight != 0)
cur.Idxs[cur.ID] = (ushort)(idx = upr);
else
cur.Idxs[cur.ID] = (ushort)(idx = (upr + lwr) / 2);
for (; ; )
{
Debug.Assert(idx == cur.Idxs[cur.ID]);
cur.Info.Size = 0;
uint cell_ = findCell(page, idx) + page.ChildPtrSize; // Pointer to current cell in pPage
if (page.IntKey)
{
if (page.HasData)
{
uint dummy = 0;
cell_ += ConvertEx.GetVarint32(page.Data, cell_, out dummy);
}
long cellKeyLength = 0;
ConvertEx.GetVarint(page.Data, cell_, out cellKeyLength);
if (cellKeyLength == intKey)
c = 0;
else if (cellKeyLength < intKey)
c = -1;
else
c = +1;
cur.ValidNKey = true;
cur.Info.Key = cellKeyLength;
}
else
{
// The maximum supported page-size is 65536 bytes. This means that the maximum number of record bytes stored on an index B-Tree
// page is less than 16384 bytes and may be stored as a 2-byte varint. This information is used to attempt to avoid parsing
// the entire cell by checking for the cases where the record is stored entirely within the b-tree page by inspecting the first
// 2 bytes of the cell.
int cellLength = page.Data[cell_ + 0];
if (cellLength <= page.Max1bytePayload)
{
// This branch runs if the record-size field of the cell is a single byte varint and the record fits entirely on the main b-tree page.
c = _vdbe.RecordCompare(cellLength, page.Data, cell_ + 1, idxKey);
}
else if ((page.Data[cell_ + 1] & 0x80) == 0 && (cellLength = ((cellLength & 0x7f) << 7) + page.Data[cell_ + 1]) <= page.MaxLocal)
{
// The record-size field is a 2 byte varint and the record fits entirely on the main b-tree page.
c = _vdbe.RecordCompare(cellLength, page.Data, cell_ + 2, idxKey);
}
else
{
// The record flows over onto one or more overflow pages. In this case the whole cell needs to be parsed, a buffer allocated
// and accessPayload() used to retrieve the record into the buffer before VdbeRecordCompare() can be called.
var cellBody = new byte[page.Data.Length - cell_ + page.ChildPtrSize];
Buffer.BlockCopy(page.Data, (int)cell_ - page.ChildPtrSize, cellBody, 0, cellBody.Length);
btreeParseCellPtr(page, cellBody, ref cur.Info);
cellLength = (int)cur.Info.Key;
var cellKey = C._alloc(cellLength);
//.........这里部分代码省略.........
public static RC Last(BtCursor cur, ref int res)
{
Debug.Assert(cursorHoldsMutex(cur));
Debug.Assert(MutexEx.Held(cur.Btree.Ctx.Mutex));
// If the cursor already points to the last entry, this is a no-op.
if (cur.State == CURSOR.VALID && cur.AtLast != 0)
{
#if DEBUG
// This block serves to Debug.Assert() that the cursor really does point to the last entry in the b-tree.
for (var ii = 0; ii < cur.ID; ii++)
Debug.Assert(cur.Idxs[ii] == cur.Pages[ii].Cells);
Debug.Assert(cur.Idxs[cur.ID] == cur.Pages[cur.ID].Cells - 1);
Debug.Assert(cur.Pages[cur.ID].Leaf);
#endif
return RC.OK;
}
var rc = moveToRoot(cur);
if (rc == RC.OK)
{
if (cur.State == CURSOR.INVALID)
{
Debug.Assert(cur.Pages[cur.ID].Cells == 0);
res = 1;
}
else
{
Debug.Assert(cur.State == CURSOR.VALID);
res = 0;
rc = moveToRightmost(cur);
cur.AtLast = (byte)(rc == RC.OK ? 1 : 0);
}
}
return rc;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:36,代码来源:Btree.cs
示例14: First
public static RC First(BtCursor cur, ref int res)
{
Debug.Assert(cursorHoldsMutex(cur));
Debug.Assert(MutexEx.Held(cur.Btree.Ctx.Mutex));
var rc = moveToRoot(cur);
if (rc == RC.OK)
{
if (cur.State == CURSOR.INVALID)
{
Debug.Assert(cur.Pages[cur.ID].Cells == 0);
res = 1;
}
else
{
Debug.Assert(cur.Pages[cur.ID].Cells > 0);
res = 0;
rc = moveToLeftmost(cur);
}
}
return rc;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:21,代码来源:Btree.cs
示例15: balance
static RC balance(BtCursor cur)
{
#if DEBUG
int balance_quick_called = 0;
int balance_deeper_called = 0;
#else
int balance_quick_called = 0;
int balance_deeper_called = 0;
#endif
byte[] free = null;
int min = (int)cur.Bt.UsableSize * 2 / 3;
RC rc = RC.OK;
do
{
int pageID = cur.ID;
MemPage page = cur.Pages[pageID];
if (pageID == 0)
{
if (page.Overflows != 0)
{
// The root page of the b-tree is overfull. In this case call the balance_deeper() function to create a new child for the root-page
// and copy the current contents of the root-page to it. The next iteration of the do-loop will balance the child page.
Debug.Assert(balance_deeper_called++ == 0);
rc = balance_deeper(page, ref cur.Pages[1]);
if (rc == RC.OK)
{
cur.ID = 1;
cur.Idxs[0] = 0;
cur.Idxs[1] = 0;
Debug.Assert(cur.Pages[1].Overflows != 0);
}
}
else
break;
}
else if (page.Overflows == 0 && page.Frees <= min)
break;
else
{
MemPage parent = cur.Pages[pageID - 1];
ushort idx = cur.Idxs[pageID - 1];
rc = Pager.Write(parent.DBPage);
if (rc == RC.OK)
{
#if !OMIT_QUICKBALANCE
if (page.HasData && page.Overflows == 1 && page.OvflIdxs[0] == page.Cells && parent.ID != 1 && parent.Cells == idx)
{
// Call balance_quick() to create a new sibling of pPage on which to store the overflow cell. balance_quick() inserts a new cell
// into pParent, which may cause pParent overflow. If this happens, the next interation of the do-loop will balance pParent
// use either balance_nonroot() or balance_deeper(). Until this happens, the overflow cell is stored in the aBalanceQuickSpace[] buffer.
//
// The purpose of the following assert() is to check that only a single call to balance_quick() is made for each call to this
// function. If this were not verified, a subtle bug involving reuse of the aBalanceQuickSpace[] might sneak in.
Debug.Assert((balance_quick_called++) == 0);
rc = balance_quick(parent, page, _balanceQuickSpace);
}
else
#endif
{
// In this case, call balance_nonroot() to redistribute cells between pPage and up to 2 of its sibling pages. This involves
// modifying the contents of pParent, which may cause pParent to become overfull or underfull. The next iteration of the do-loop
// will balance the parent page to correct this.
//
// If the parent page becomes overfull, the overflow cell or cells are stored in the pSpace buffer allocated immediately below.
// A subsequent iteration of the do-loop will deal with this by calling balance_nonroot() (balance_deeper() may be called first,
// but it doesn't deal with overflow cells - just moves them to a different page). Once this subsequent call to balance_nonroot()
// has completed, it is safe to release the pSpace buffer used by the previous call, as the overflow cell data will have been
// copied either into the body of a database page or into the new pSpace buffer passed to the latter call to balance_nonroot().
byte[] space = null; //PCache.PageAlloc2((int)cur.Bt.PageSize);
rc = balance_nonroot(parent, idx, space, pageID == 1, cur.Hints != 0);
if (free != null)
{
// If pFree is not NULL, it points to the pSpace buffer used by a previous call to balance_nonroot(). Its contents are
// now stored either on real database pages or within the new pSpace buffer, so it may be safely freed here.
PCache.PageFree2(ref free);
}
// The pSpace buffer will be freed after the next call to balance_nonroot(), or just before this function returns, whichever comes first.
free = space;
}
}
page.Overflows = 0;
// The next iteration of the do-loop balances the parent page.
releasePage(page);
cur.ID--;
}
} while (rc == RC.OK);
if (free != null)
PCache.PageFree2(ref free);
return rc;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:97,代码来源:Btree.cs
示例16: Insert
public static RC Insert(BtCursor cur, byte[] key, long keyLength, byte[] data, int dataLength, int zero, int appendBias, int seekResult)
{
if (cur.State == CURSOR.FAULT)
{
Debug.Assert(cur.SkipNext != 0);
return (RC)cur.SkipNext;
}
Btree p = cur.Btree;
BtShared bt = p.Bt;
Debug.Assert(cursorHoldsMutex(cur));
Debug.Assert(cur.WrFlag && bt.InTransaction == TRANS.WRITE && (bt.BtsFlags & BTS.READ_ONLY) == 0);
Debug.Assert(hasSharedCacheTableLock(p, cur.RootID, cur.KeyInfo != null, LOCK.WRITE));
// Assert that the caller has been consistent. If this cursor was opened expecting an index b-tree, then the caller should be inserting blob
// keys with no associated data. If the cursor was opened expecting an intkey table, the caller should be inserting integer keys with a
// blob of associated data.
Debug.Assert((key == null) == (cur.KeyInfo == null));
// Save the positions of any other cursors open on this table.
//
// In some cases, the call to btreeMoveto() below is a no-op. For example, when inserting data into a table with auto-generated integer
// keys, the VDBE layer invokes sqlite3BtreeLast() to figure out the integer key to use. It then calls this function to actually insert the
// data into the intkey B-Tree. In this case btreeMoveto() recognizes that the cursor is already where it needs to be and returns without
// doing any work. To avoid thwarting these optimizations, it is important not to clear the cursor here.
RC rc = saveAllCursors(bt, cur.RootID, cur);
if (rc != RC.OK) return rc;
// If this is an insert into a table b-tree, invalidate any incrblob cursors open on the row being replaced (assuming this is a replace
// operation - if it is not, the following is a no-op).
if (cur.KeyInfo == null)
invalidateIncrblobCursors(p, keyLength, false);
int loc = seekResult; // -1: before desired location +1: after
if (loc == 0)
{
rc = btreeMoveto(cur, key, keyLength, appendBias, ref loc);
if (rc != RC.OK) return rc;
}
Debug.Assert(cur.State == CURSOR.VALID || (cur.State == CURSOR.INVALID && loc != 0));
MemPage page = cur.Pages[cur.ID];
Debug.Assert(page.IntKey || keyLength >= 0);
Debug.Assert(page.Leaf || !page.IntKey);
TRACE("INSERT: table=%d nkey=%lld ndata=%d page=%d %s\n", cur.RootID, keyLength, dataLength, page.ID, loc == 0 ? "overwrite" : "new entry");
Debug.Assert(page.IsInit);
allocateTempSpace(bt);
byte[] newCell = bt.TmpSpace;
if (newCell == null) return RC.NOMEM;
ushort sizeNew = 0;
rc = fillInCell(page, newCell, key, keyLength, data, dataLength, zero, ref sizeNew);
if (rc != RC.OK) goto end_insert;
Debug.Assert(sizeNew == cellSizePtr(page, newCell));
Debug.Assert(sizeNew <= MX_CELL_SIZE(bt));
uint idx = cur.Idxs[cur.ID];
if (loc == 0)
{
Debug.Assert(idx < page.Cells);
rc = Pager.Write(page.DBPage);
if (rc != RC.OK)
goto end_insert;
uint oldCell_ = findCell(page, idx);
if (!page.Leaf)
{
//_memcpy(newCell, oldCell, 4);
newCell[0] = page.Data[oldCell_ + 0];
newCell[1] = page.Data[oldCell_ + 1];
newCell[2] = page.Data[oldCell_ + 2];
newCell[3] = page.Data[oldCell_ + 3];
}
ushort sizeOld = cellSizePtr(page, oldCell_);
rc = clearCell(page, oldCell_);
dropCell(page, idx, sizeOld, ref rc);
if (rc != RC.OK) goto end_insert;
}
else if (loc < 0 && page.Cells > 0)
{
Debug.Assert(page.Leaf);
idx = ++cur.Idxs[cur.ID];
}
else
Debug.Assert(page.Leaf);
insertCell(page, idx, newCell, sizeNew, null, 0, ref rc);
Debug.Assert(rc != RC.OK || page.Cells > 0 || page.Overflows > 0);
// If no error has occurred and pPage has an overflow cell, call balance() to redistribute the cells within the tree. Since balance() may move
// the cursor, zero the BtCursor.info.nSize and BtCursor.validNKey variables.
//
// Previous versions of SQLite called moveToRoot() to move the cursor back to the root page as balance() used to invalidate the contents
// of BtCursor.apPage[] and BtCursor.aiIdx[]. Instead of doing that, set the cursor state to "invalid". This makes common insert operations
// slightly faster.
//
// There is a subtle but important optimization here too. When inserting multiple records into an intkey b-tree using a single cursor (as can
// happen while processing an "INSERT INTO ... SELECT" statement), it is advantageous to leave the cursor pointing to the last entry in
// the b-tree if possible. If the cursor is left pointing to the last entry in the table, and the next row inserted has an integer key
// larger than the largest existing key, it is possible to insert the row without seeking the cursor. This can be a big performance boost.
cur.Info.Size = 0;
cur.ValidNKey = false;
if (rc == RC.OK && page.Overflows != 0)
//.........这里部分代码省略.........
public static RC Previous(BtCursor cur, ref int res)
{
Debug.Assert(cursorHoldsMutex(cur));
var rc = restoreCursorPosition(cur);
if (rc != RC.OK)
return rc;
cur.AtLast = 0;
if (cur.State == CURSOR.INVALID)
{
res = 1;
return RC.OK;
}
if (cur.SkipNext < 0)
{
cur.SkipNext = 0;
res = 0;
return RC.OK;
}
cur.SkipNext = 0;
MemPage page = cur.Pages[cur.ID];
Debug.Assert(page.IsInit);
if (!page.Leaf)
{
uint idx = cur.Idxs[cur.ID];
rc = moveToChild(cur, ConvertEx.Get4(page.Data, findCell(page, idx)));
if (rc != RC.OK)
return rc;
rc = moveToRightmost(cur);
}
else
{
while (cur.Idxs[cur.ID] == 0)
{
if (cur.ID == 0)
{
cur.State = CURSOR.INVALID;
res = 1;
return RC.OK;
}
moveToParent(cur);
}
cur.Info.Size = 0;
cur.ValidNKey = false;
cur.Idxs[cur.ID]--;
page = cur.Pages[cur.ID];
if (page.IntKey && !page.Leaf)
rc = Previous(cur, ref res);
else
rc = RC.OK;
}
res = 0;
return rc;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:55,代码来源:Btree.cs
示例18: Count
public static RC Count(BtCursor cur, ref long entrysRef)
{
if (cur.RootID == 0)
{
entrysRef = 0;
return RC.OK;
}
var rc = moveToRoot(cur);
// Unless an error occurs, the following loop runs one iteration for each page in the B-Tree structure (not including overflow pages).
long entrys = 0; // Value to return in pnEntry
while (rc == RC.OK)
{
// If this is a leaf page or the tree is not an int-key tree, then this page contains countable entries. Increment the entry counter accordingly.
MemPage page = cur.Pages[cur.ID]; // Current page of the b-tree
if (page.Leaf || !page.IntKey)
entrys += page.Cells;
// pPage is a leaf node. This loop navigates the cursor so that it points to the first interior cell that it points to the parent of
// the next page in the tree that has not yet been visited. The pCur->aiIdx[pCur->iPage] value is set to the index of the parent cell
// of the page, or to the number of cells in the page if the next page to visit is the right-child of its parent.
//
// If all pages in the tree have been visited, return SQLITE_OK to the caller.
if (page.Leaf)
{
do
{
if (cur.ID == 0)
{
// All pages of the b-tree have been visited. Return successfully.
entrysRef = entrys;
return RC.OK;
}
moveToParent(cur);
} while (cur.Idxs[cur.ID] >= cur.Pages[cur.ID].Cells);
cur.Idxs[cur.ID]++;
page = cur.Pages[cur.ID];
}
// Descend to the child node of the cell that the cursor currently points at. This is the right-child if (iIdx==pPage->nCell).
uint idx = cur.Idxs[cur.ID]; // Index of child node in parent
if (idx == page.Cells)
rc = moveToChild(cur, ConvertEx.Get4(page.Data, page.HdrOffset + 8));
else
rc = moveToChild(cur, ConvertEx.Get4(page.Data, findCell(page, idx)));
}
// An error has occurred. Return an error code.
return rc;
}
开发者ID:BclEx,项目名称:GpuStructs,代码行数:51,代码来源:Btree.cs
示例19: saveAllCursors
static RC saveAllCursors(BtShared bt, Pid root, BtCursor except)
{
Debug.Assert(MutexEx.Held(bt.Mutex));
Debug.Assert(except == null || except.Bt == bt);
for (var p = bt.Cursor; p != null; p = p.Next)
{
if (p != except && (root == 0 || p.RootID == root) && p.State == CURSOR.VALID)
{
var rc = saveCursorPosition(p);
if (rc != RC.OK)
return rc;
}
}
return RC.OK;
}
请发表评论