private static void pcache1PinPage(PgHdr1 pPage) { if (pPage == null) { return; } var pCache = pPage.pCache; var pGroup = pCache.pGroup; Debug.Assert(MutexEx.Held(pGroup.mutex)); if (pPage.pLruNext != null || pPage == pGroup.pLruTail) { if (pPage.pLruPrev != null) { pPage.pLruPrev.pLruNext = pPage.pLruNext; } if (pPage.pLruNext != null) { pPage.pLruNext.pLruPrev = pPage.pLruPrev; } if (pGroup.pLruHead == pPage) { pGroup.pLruHead = pPage.pLruNext; } if (pGroup.pLruTail == pPage) { pGroup.pLruTail = pPage.pLruPrev; } pPage.pLruNext = null; pPage.pLruPrev = null; pPage.pCache.nRecyclable--; } }
internal void assemblePage(int nCell, byte[] apCell, int[] aSize) { Debug.Assert(this.NOverflows == 0); Debug.Assert(MutexEx.Held(this.Shared.Mutex)); Debug.Assert(nCell >= 0 && nCell <= (int)Btree.MX_CELL(this.Shared) && (int)Btree.MX_CELL(this.Shared) <= 10921); Debug.Assert(Pager.IsPageWriteable(this.DbPage)); // Check that the page has just been zeroed by zeroPage() Debug.Assert(this.Cells == 0); // var data = this.Data; // Pointer to data for pPage int hdr = this.HeaderOffset; // Offset of header on pPage var nUsable = (int)this.Shared.UsableSize; // Usable size of page Debug.Assert(ConvertEx.Get2nz(data, hdr + 5) == nUsable); var pCellptr = this.CellOffset + nCell * 2; // Address of next cell pointer var cellbody = nUsable; // Address of next cell body for (var i = nCell - 1; i >= 0; i--) { var sz = (ushort)aSize[i]; pCellptr -= 2; cellbody -= sz; ConvertEx.Put2(data, pCellptr, cellbody); Buffer.BlockCopy(apCell, 0, data, cellbody, sz); } ConvertEx.Put2(data, hdr + 3, nCell); ConvertEx.Put2(data, hdr + 5, cellbody); this.FreeBytes -= (ushort)(nCell * 2 + nUsable - cellbody); this.Cells = (ushort)nCell; }
internal RC decodeFlags(int flagByte) { Debug.Assert(this.HeaderOffset == (this.ID == 1 ? 100 : 0)); Debug.Assert(MutexEx.Held(this.Shared.Mutex)); this.Leaf = (byte)(flagByte >> 3); Debug.Assert(Btree.PTF_LEAF == 1 << 3); flagByte &= ~Btree.PTF_LEAF; this.ChildPtrSize = (byte)(4 - 4 * this.Leaf); var pBt = this.Shared; if (flagByte == (Btree.PTF_LEAFDATA | Btree.PTF_INTKEY)) { this.HasIntKey = true; this.HasData = this.Leaf; this.MaxLocal = pBt.MaxLeaf; this.MinLocal = pBt.MinLeaf; } else if (flagByte == Btree.PTF_ZERODATA) { this.HasIntKey = false; this.HasData = 0; this.MaxLocal = pBt.MaxLocal; this.MinLocal = pBt.MinLocal; } else { return(SysEx.SQLITE_CORRUPT_BKPT()); } return(RC.OK); }
// was:sqlite3BtreePutData public RC BtreePutData(uint offset, uint amt, byte[] z) { Debug.Assert(HoldsMutex()); Debug.Assert(MutexEx.Held(Tree.DB.Mutex)); Debug.Assert(IsIncrblob); var rc = RestorePosition(); if (rc != RC.OK) { return(rc); } Debug.Assert(State != CursorState.REQUIRESEEK); if (State != CursorState.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 (!Writeable) { return(RC.READONLY); } Debug.Assert(!Shared.ReadOnly && Shared.InTransaction == TRANS.WRITE); Debug.Assert(Tree.hasSharedCacheTableLock(RootID, false, LOCK.WRITE)); Debug.Assert(!Tree.hasReadConflicts(RootID)); Debug.Assert(Pages[PageID].HasIntKey); return(AccessPayload(offset, amt, z, true)); }
// was:sqlite3BtreeCacheOverflow public void BtreeCacheOverflow() { Debug.Assert(HoldsMutex()); Debug.Assert(MutexEx.Held(Tree.DB.Mutex)); Btree.invalidateOverflowCache(this); IsIncrblob = true; }
internal RC ptrmapGet(Pgno key, ref PTRMAP pEType, ref Pgno pPgno) { Debug.Assert(MutexEx.Held(this.Mutex)); var iPtrmap = (int)MemPage.PTRMAP_PAGENO(this, key); var pDbPage = new PgHdr(); // The pointer map page var rc = this.Pager.Get((Pgno)iPtrmap, ref pDbPage); if (rc != RC.OK) { return(rc); } var pPtrmap = Pager.sqlite3PagerGetData(pDbPage);// Pointer map page data var offset = (int)MemPage.PTRMAP_PTROFFSET((Pgno)iPtrmap, key); if (offset < 0) { Pager.Unref(pDbPage); return(SysEx.SQLITE_CORRUPT_BKPT()); } Debug.Assert(offset <= (int)this.UsableSize - 5); var v = pPtrmap[offset]; if (v < 1 || v > 5) { return(SysEx.SQLITE_CORRUPT_BKPT()); } pEType = (PTRMAP)v; pPgno = ConvertEx.Get4(pPtrmap, offset + 1); Pager.Unref(pDbPage); return(RC.OK); }
internal RC setChildPtrmaps() { var hasInitLast = HasInit; Debug.Assert(MutexEx.Held(Shared.Mutex)); var rc = btreeInitPage(); if (rc != RC.OK) { goto set_child_ptrmaps_out; } var cells = Cells; // Number of cells in page pPage var shared = Shared; var id = ID; for (var i = 0; i < cells; i++) { var cell = FindCell(i); ptrmapPutOvflPtr(cell, ref rc); if (Leaf == 0) { var childPgno = (Pgno)ConvertEx.Get4(Data, cell); shared.ptrmapPut(childPgno, PTRMAP.BTREE, id, ref rc); } } if (Leaf == 0) { var childPgno = (Pgno)ConvertEx.Get4(Data, HeaderOffset + 8); shared.ptrmapPut(childPgno, PTRMAP.BTREE, id, ref rc); } set_child_ptrmaps_out: HasInit = hasInitLast; return(rc); }
internal void zeroPage(int flags) { var data = this.Data; var pBt = this.Shared; var hdr = this.HeaderOffset; Debug.Assert(Pager.GetPageID(this.DbPage) == this.ID); Debug.Assert(Pager.sqlite3PagerGetExtra <MemPage>(this.DbPage) == this); Debug.Assert(Pager.sqlite3PagerGetData(this.DbPage) == data); Debug.Assert(Pager.IsPageWriteable(this.DbPage)); Debug.Assert(MutexEx.Held(pBt.Mutex)); if (pBt.SecureDelete) { Array.Clear(data, hdr, (int)(pBt.UsableSize - hdr)); } data[hdr] = (byte)flags; var first = (ushort)(hdr + 8 + 4 * ((flags & Btree.PTF_LEAF) == 0 ? 1 : 0)); Array.Clear(data, hdr + 1, 4); data[hdr + 7] = 0; ConvertEx.Put2(data, hdr + 5, pBt.UsableSize); this.FreeBytes = (ushort)(pBt.UsableSize - first); decodeFlags(flags); this.HeaderOffset = hdr; this.CellOffset = first; this.NOverflows = 0; Debug.Assert(pBt.PageSize >= 512 && pBt.PageSize <= 65536); this.MaskPage = (ushort)(pBt.PageSize - 1); this.Cells = 0; this.HasInit = true; }
internal MemPage btreePageLookup(Pgno pgno) { Debug.Assert(MutexEx.Held(this.Mutex)); var pDbPage = this.Pager.Lookup(pgno); return(pDbPage ? MemPage.btreePageFromDbPage(pDbPage, pgno, this) : null); }
internal void dropCell(int idx, int sz, ref RC pRC) { if (pRC != RC.OK) { return; } Debug.Assert(idx >= 0 && idx < this.Cells); #if DEBUG Debug.Assert(sz == cellSize(idx)); #endif Debug.Assert(Pager.IsPageWriteable(this.DbPage)); Debug.Assert(MutexEx.Held(this.Shared.Mutex)); var data = this.Data; var ptr = this.CellOffset + 2 * idx; // Used to move bytes around within data[] var pc = (uint)ConvertEx.Get2(data, ptr); // Offset to cell content of cell being deleted var hdr = this.HeaderOffset; // Beginning of the header. 0 most pages. 100 page 1 if (pc < (uint)ConvertEx.Get2(data, hdr + 5) || pc + sz > this.Shared.UsableSize) { pRC = SysEx.SQLITE_CORRUPT_BKPT(); return; } var rc = freeSpace(pc, sz); if (rc != RC.OK) { pRC = rc; return; } Buffer.BlockCopy(data, ptr + 2, data, ptr, (this.Cells - 1 - idx) * 2); this.Cells--; data[this.HeaderOffset + 3] = (byte)(this.Cells >> 8); data[this.HeaderOffset + 4] = (byte)(this.Cells); this.FreeBytes += 2; }
internal static RC autoVacuumCommit(BtShared pBt) { var rc = RC.OK; var pPager = pBt.Pager; #if DEBUG var nRef = pPager.RefCount; #else var nRef = 0; #endif Debug.Assert(MutexEx.Held(pBt.Mutex)); Btree.invalidateAllOverflowCache(pBt); Debug.Assert(pBt.AutoVacuum); if (!pBt.IncrVacuum) { var nOrig = pBt.btreePagecount(); // Database size before freeing if (PTRMAP_ISPAGE(pBt, nOrig) || nOrig == PENDING_BYTE_PAGE(pBt)) { // It is not possible to create a database for which the final page is either a pointer-map page or the pending-byte page. If one // is encountered, this indicates corruption. return(SysEx.SQLITE_CORRUPT_BKPT()); } var nFree = (Pgno)ConvertEx.Get4(pBt.Page1.Data, 36); // Number of pages on the freelist initially var nEntry = (int)pBt.UsableSize / 5; // Number of entries on one ptrmap page var nPtrmap = (Pgno)((nFree - nOrig + PTRMAP_PAGENO(pBt, nOrig) + (Pgno)nEntry) / nEntry); // Number of PtrMap pages to be freed var nFin = nOrig - nFree - nPtrmap; // Number of pages in database after autovacuuming if (nOrig > PENDING_BYTE_PAGE(pBt) && nFin < PENDING_BYTE_PAGE(pBt)) { nFin--; } while (PTRMAP_ISPAGE(pBt, nFin) || nFin == PENDING_BYTE_PAGE(pBt)) { nFin--; } if (nFin > nOrig) { return(SysEx.SQLITE_CORRUPT_BKPT()); } for (var iFree = nOrig; iFree > nFin && rc == RC.OK; iFree--) { rc = incrVacuumStep(pBt, nFin, iFree); } if ((rc == RC.DONE || rc == RC.OK) && nFree > 0) { rc = Pager.Write(pBt.Page1.DbPage); ConvertEx.Put4(pBt.Page1.Data, 32, 0); ConvertEx.Put4(pBt.Page1.Data, 36, 0); ConvertEx.Put4(pBt.Page1.Data, 28, nFin); pBt.Pager.TruncateImage(nFin); pBt.Pages = nFin; } if (rc != RC.OK) { pPager.Rollback(); } } Debug.Assert(nRef == pPager.RefCount); return(rc); }
internal void btreeParseCellPtr(byte[] cell, int cellID, ref CellInfo info) { var nPayload = (uint)0; // Number of bytes of cell payload Debug.Assert(MutexEx.Held(Shared.Mutex)); if (info.Cells != cell) { info.Cells = cell; } info.CellID = cellID; Debug.Assert(Leaf == 0 || Leaf == 1); var n = (ushort)ChildPtrSize; // Number bytes in cell content header Debug.Assert(n == 4 - 4 * Leaf); if (HasIntKey) { if (HasData != 0) { n += (ushort)ConvertEx.GetVariant4(cell, (uint)(cellID + n), out nPayload); } else { nPayload = 0; } n += (ushort)ConvertEx.GetVariant9L(cell, (uint)(cellID + n), out info.nKey); info.nData = nPayload; } else { info.nData = 0; n += (ushort)ConvertEx.GetVariant4(cell, (uint)(cellID + n), out nPayload); info.nKey = nPayload; } info.nPayload = nPayload; info.nHeader = n; if (Check.LIKELY(nPayload <= this.MaxLocal)) { // This is the (easy) common case where the entire payload fits on the local page. No overflow is required. if ((info.nSize = (ushort)(n + nPayload)) < 4) { info.nSize = 4; } info.nLocal = (ushort)nPayload; info.iOverflow = 0; } 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. var minLocal = (int)MinLocal; // Minimum amount of payload held locally var maxLocal = (int)MaxLocal; // Maximum amount of payload held locally var surplus = (int)(minLocal + (nPayload - minLocal) % (Shared.UsableSize - 4)); // Overflow payload available for local storage info.nLocal = (surplus <= maxLocal ? (ushort)surplus : (ushort)minLocal); info.iOverflow = (ushort)(info.nLocal + n); info.nSize = (ushort)(info.iOverflow + 4); } }
internal static int btreeInvokeBusyHandler(object pArg) { var pBt = (BtShared)pArg; Debug.Assert(pBt.DB != null); Debug.Assert(MutexEx.Held(pBt.DB.Mutex)); return(pBt.DB.sqlite3InvokeBusyHandler()); }
// was:invalidateAllOverflowCache internal static void invalidateAllOverflowCache(BtShared shared) { Debug.Assert(MutexEx.Held(shared.Mutex)); for (var cursor = shared.Cursors; cursor != null; cursor = cursor.Next) { invalidateOverflowCache(cursor); } }
internal RC clearDatabasePage(Pgno pgno, int freePageFlag, ref int pnChange) { var pPage = new MemPage(); Debug.Assert(MutexEx.Held(this.Mutex)); if (pgno > btreePagecount()) { return(SysEx.SQLITE_CORRUPT_BKPT()); } var rc = getAndInitPage(pgno, ref pPage); if (rc != RC.OK) { return(rc); } for (var i = 0; i < pPage.Cells; i++) { var iCell = pPage.FindCell(i); var pCell = pPage.Data; if (pPage.Leaf == 0) { rc = clearDatabasePage(ConvertEx.Get4(pCell, iCell), 1, ref pnChange); if (rc != RC.OK) { goto cleardatabasepage_out; } } rc = pPage.clearCell(iCell); if (rc != RC.OK) { goto cleardatabasepage_out; } } if (pPage.Leaf == 0) { rc = clearDatabasePage(ConvertEx.Get4(pPage.Data, 8), 1, ref pnChange); if (rc != RC.OK) { goto cleardatabasepage_out; } } else { pnChange += pPage.Cells; } if (freePageFlag != 0) { pPage.freePage(ref rc); } else if ((rc = Pager.Write(pPage.DbPage)) == RC.OK) { pPage.zeroPage(pPage.Data[0] | Btree.PTF_LEAF); } cleardatabasepage_out: pPage.releasePage(); return(rc); }
internal RC modifyPagePointer(Pgno iFrom, Pgno iTo, PTRMAP eType) { Debug.Assert(MutexEx.Held(this.Shared.Mutex)); Debug.Assert(Pager.IsPageWriteable(this.DbPage)); if (eType == PTRMAP.OVERFLOW2) { // The pointer is always the first 4 bytes of the page in this case. if (ConvertEx.Get4(this.Data) != iFrom) { return(SysEx.SQLITE_CORRUPT_BKPT()); } ConvertEx.Put4L(this.Data, iTo); } else { var isInitOrig = this.HasInit; btreeInitPage(); var nCell = this.Cells; int i; for (i = 0; i < nCell; i++) { var pCell = FindCell(i); if (eType == PTRMAP.OVERFLOW1) { var info = new CellInfo(); btreeParseCellPtr(pCell, ref info); if (info.iOverflow != 0) { if (iFrom == ConvertEx.Get4(this.Data, pCell + info.iOverflow)) { ConvertEx.Put4(this.Data, pCell + info.iOverflow, (int)iTo); break; } } } else { if (ConvertEx.Get4(this.Data, pCell) == iFrom) { ConvertEx.Put4(this.Data, pCell, (int)iTo); break; } } } if (i == nCell) { if (eType != PTRMAP.BTREE || ConvertEx.Get4(this.Data, this.HeaderOffset + 8) != iFrom) { return(SysEx.SQLITE_CORRUPT_BKPT()); } ConvertEx.Put4L(this.Data, (uint)this.HeaderOffset + 8, iTo); } this.HasInit = isInitOrig; } return(RC.OK); }
// was:sqlite3BtreeSetCacheSize public RC SetCacheSize(int mxPage) { Debug.Assert(MutexEx.Held(this.DB.Mutex)); sqlite3BtreeEnter(); var pBt = this.Shared; pBt.Pager.SetCacheSize(mxPage); sqlite3BtreeLeave(); return(RC.OK); }
// was:sqlite3BtreeSyncDisabled public int SyncDisabled() { Debug.Assert(MutexEx.Held(this.DB.Mutex)); sqlite3BtreeEnter(); var pBt = this.Shared; Debug.Assert(pBt != null && pBt.Pager != null); var rc = (pBt.Pager.sqlite3PagerNosync ? 1 : 0); sqlite3BtreeLeave(); return rc; }
internal RC getOverflowPage(Pgno ovfl, out MemPage ppPage, out Pgno pPgnoNext) { Pgno next = 0; MemPage pPage = null; ppPage = null; var rc = RC.OK; Debug.Assert(MutexEx.Held(this.Mutex)); // Debug.Assert( pPgnoNext != 0); #if !SQLITE_OMIT_AUTOVACUUM // Try to find the next page in the overflow list using the autovacuum pointer-map pages. Guess that the next page in // the overflow list is page number (ovfl+1). If that guess turns out to be wrong, fall back to loading the data of page // number ovfl to determine the next page number. if (this.AutoVacuum) { Pgno pgno = 0; Pgno iGuess = ovfl + 1; PTRMAP eType = 0; while (MemPage.PTRMAP_ISPAGE(this, iGuess) || iGuess == MemPage.PENDING_BYTE_PAGE(this)) { iGuess++; } if (iGuess <= btreePagecount()) { rc = ptrmapGet(iGuess, ref eType, ref pgno); if (rc == RC.OK && eType == PTRMAP.OVERFLOW2 && pgno == ovfl) { next = iGuess; rc = RC.DONE; } } } #endif Debug.Assert(next == 0 || rc == RC.DONE); if (rc == RC.OK) { rc = btreeGetPage(ovfl, ref pPage, 0); Debug.Assert(rc == RC.OK || pPage == null); if (rc == RC.OK) { next = ConvertEx.Get4(pPage.Data); } } pPgnoNext = next; if (ppPage != null) { ppPage = pPage; } else { pPage.releasePage(); } return(rc == RC.DONE ? RC.OK : rc); }
// was:sqlite3BtreeSetSafetyLevel public RC SetSafetyLevel(int level, int fullSync, int ckptFullSync) { var pBt = this.Shared; Debug.Assert(MutexEx.Held(this.DB.Mutex)); Debug.Assert(level >= 1 && level <= 3); sqlite3BtreeEnter(); pBt.Pager.SetSafetyLevel(level, fullSync, ckptFullSync); sqlite3BtreeLeave(); return(RC.OK); }
internal RC defragmentPage() { Debug.Assert(Pager.IsPageWriteable(this.DbPage)); Debug.Assert(this.Shared != null); Debug.Assert(this.Shared.UsableSize <= Pager.SQLITE_MAX_PAGE_SIZE); Debug.Assert(this.NOverflows == 0); Debug.Assert(MutexEx.Held(this.Shared.Mutex)); var temp = this.Shared.Pager.sqlite3PagerTempSpace(); // Temp area for cell content var data = this.Data; // The page data var hdr = this.HeaderOffset; // Offset to the page header var cellOffset = this.CellOffset; // Offset to the cell pointer array var nCell = this.Cells; // Number of cells on the page Debug.Assert(nCell == ConvertEx.Get2(data, hdr + 3)); var usableSize = (int)this.Shared.UsableSize; // Number of usable bytes on a page var cbrk = (int)ConvertEx.Get2(data, hdr + 5); // Offset to the cell content area Buffer.BlockCopy(data, cbrk, temp, cbrk, usableSize - cbrk); cbrk = usableSize; var iCellFirst = cellOffset + 2 * nCell; // First allowable cell index var iCellLast = usableSize - 4; // Last possible cell index for (var i = 0; i < nCell; i++) { var pAddr = cellOffset + i * 2; // The i-th cell pointer var pc = ConvertEx.Get2(data, pAddr); // Address of a i-th cell #if !SQLITE_ENABLE_OVERSIZE_CELL_CHECK // These conditions have already been verified in btreeInitPage() if SQLITE_ENABLE_OVERSIZE_CELL_CHECK is defined if (pc < iCellFirst || pc > iCellLast) { return(SysEx.SQLITE_CORRUPT_BKPT()); } #endif Debug.Assert(pc >= iCellFirst && pc <= iCellLast); var size = cellSizePtr(temp, pc); // Size of a cell cbrk -= size; if (cbrk < iCellFirst || pc + size > usableSize) { return(SysEx.SQLITE_CORRUPT_BKPT()); } Debug.Assert(cbrk + size <= usableSize && cbrk >= iCellFirst); Buffer.BlockCopy(temp, pc, data, cbrk, size); ConvertEx.Put2(data, pAddr, cbrk); } Debug.Assert(cbrk >= iCellFirst); ConvertEx.Put2(data, hdr + 5, cbrk); data[hdr + 1] = 0; data[hdr + 2] = 0; data[hdr + 7] = 0; var addr = cellOffset + 2 * nCell; // Offset of first byte after cell pointer array Array.Clear(data, addr, cbrk - addr); Debug.Assert(Pager.IsPageWriteable(this.DbPage)); return(cbrk - iCellFirst != this.FreeBytes ? SysEx.SQLITE_CORRUPT_BKPT() : RC.OK); }
// was:sqlite3BtreeKeyFetch public byte[] FetchKey(ref int size, out int offset) { Debug.Assert(MutexEx.Held(Tree.DB.Mutex)); Debug.Assert(HoldsMutex()); if (Check.ALWAYS(State == CursorState.VALID)) { return(FetchPayload(ref size, out offset, false)); } offset = 0; return(null); }
private static void pcache1EnforceMaxPage(PGroup pGroup) { Debug.Assert(MutexEx.Held(pGroup.mutex)); while (pGroup.nCurrentPage > pGroup.nMaxPage && pGroup.pLruTail != null) { PgHdr1 p = pGroup.pLruTail; Debug.Assert(p.pCache.pGroup == pGroup); pcache1PinPage(p); pcache1RemoveFromHash(p); pcache1FreePage(ref p); } }
internal void unlockBtreeIfUnused() { Debug.Assert(MutexEx.Held(this.Mutex)); Debug.Assert(this.Cursors == null || this.InTransaction > TRANS.NONE); if (this.InTransaction == TRANS.NONE && this.Page1 != null) { Debug.Assert(this.Page1.Data != null); //Debug.Assert(pBt.pPager.sqlite3PagerRefcount() == 1 ); this.Page1.releasePage(); this.Page1 = null; } }
internal void releasePage() { if (this != null) { Debug.Assert(this.Data != null); Debug.Assert(this.Shared != null); // TODO -- find out why corrupt9 & diskfull fail on this tests //Debug.Assert( Pager.sqlite3PagerGetExtra( pPage.pDbPage ) == pPage ); //Debug.Assert( Pager.sqlite3PagerGetData( pPage.pDbPage ) == pPage.aData ); Debug.Assert(MutexEx.Held(this.Shared.Mutex)); Pager.Unref(this.DbPage); } }
internal RC btreeGetPage(Pgno pgno, ref MemPage ppPage, int noContent) { Debug.Assert(MutexEx.Held(this.Mutex)); DbPage pDbPage = null; var rc = this.Pager.Get(pgno, ref pDbPage, (byte)noContent); if (rc != RC.OK) { return(rc); } ppPage = MemPage.btreePageFromDbPage(pDbPage, pgno, this); return(RC.OK); }
internal void ptrmapPut(Pgno key, PTRMAP eType, Pgno parent, ref RC rRC) { if (rRC != RC.OK) { return; } Debug.Assert(MutexEx.Held(this.Mutex)); // The master-journal page number must never be used as a pointer map page Debug.Assert(!MemPage.PTRMAP_ISPAGE(this, MemPage.PENDING_BYTE_PAGE(this))); Debug.Assert(this.AutoVacuum); if (key == 0) { rRC = SysEx.SQLITE_CORRUPT_BKPT(); return; } var iPtrmap = MemPage.PTRMAP_PAGENO(this, key); var pDbPage = new PgHdr(); // The pointer map page var rc = this.Pager.Get(iPtrmap, ref pDbPage); if (rc != RC.OK) { rRC = rc; return; } var offset = (int)MemPage.PTRMAP_PTROFFSET(iPtrmap, key); if (offset < 0) { rRC = SysEx.SQLITE_CORRUPT_BKPT(); goto ptrmap_exit; } Debug.Assert(offset <= (int)this.UsableSize - 5); var pPtrmap = Pager.sqlite3PagerGetData(pDbPage); // The pointer map data if (eType != (PTRMAP)pPtrmap[offset] || ConvertEx.Get4(pPtrmap, offset + 1) != parent) { Btree.TRACE("PTRMAP_UPDATE: {0}->({1},{2})", key, eType, parent); rRC = rc = Pager.Write(pDbPage); if (rc == RC.OK) { pPtrmap[offset] = (byte)eType; ConvertEx.Put4L(pPtrmap, (uint)offset + 1, parent); } } ptrmap_exit: Pager.Unref(pDbPage); }
internal RC saveAllCursors(Pgno iRoot, BtreeCursor pExcept) { Debug.Assert(MutexEx.Held(this.Mutex)); Debug.Assert(pExcept == null || pExcept.Shared == this); for (var p = this.Cursors; p != null; p = p.Next) { if (p != pExcept && (0 == iRoot || p.RootID == iRoot) && p.State == CURSOR.VALID) { var rc = p.SavePosition(); if (rc != RC.OK) { return(rc); } } } return(RC.OK); }
internal Pgno ptrmapPageno(Pgno pgno) { Debug.Assert(MutexEx.Held(this.Mutex)); if (pgno < 2) { return(0); } var nPagesPerMapPage = (int)(this.UsableSize / 5 + 1); var iPtrMap = (Pgno)((pgno - 2) / nPagesPerMapPage); var ret = (Pgno)(iPtrMap * nPagesPerMapPage) + 2; if (ret == MemPage.PENDING_BYTE_PAGE(this)) { ret++; } return(ret); }
// was:findOverflowCell private int FindOverflowCell(int cellID) { Debug.Assert(MutexEx.Held(Shared.Mutex)); for (var i = NOverflows - 1; i >= 0; i--) { var overflow = Overflows[i]; var k = overflow.Index; if (k <= cellID) { if (k == cellID) { return(-i - 1); // Negative Offset means overflow cells } cellID--; } } return(FindCell(cellID)); }