Exemple #1
0
        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);
        }
Exemple #2
0
        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 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);
        }
        private static PgHdr pcache1Alloc(int nByte)
        {
            PgHdr p = null;

            Debug.Assert(MutexEx.NotHeld(pcache1.grp.mutex));
            StatusEx.sqlite3StatusSet(StatusEx.STATUS.PAGECACHE_SIZE, nByte);
            if (nByte <= pcache1.szSlot)
            {
                MutexEx.Enter(pcache1.mutex);
                p = pcache1.pFree._PgHdr;
                if (p != null)
                {
                    pcache1.pFree = pcache1.pFree.pNext;
                    pcache1.nFreeSlot--;
                    pcache1.bUnderPressure = pcache1.nFreeSlot < pcache1.nReserve;
                    Debug.Assert(pcache1.nFreeSlot >= 0);
                    StatusEx.sqlite3StatusAdd(StatusEx.STATUS.PAGECACHE_USED, 1);
                }
                MutexEx.Leave(pcache1.mutex);
            }
            if (p == null)
            {
                // Memory is not available in the SQLITE_CONFIG_PAGECACHE pool.  Get it from sqlite3Malloc instead.
                p = new PgHdr();
                {
                    var sz = nByte;
                    MutexEx.Enter(pcache1.mutex);
                    StatusEx.sqlite3StatusAdd(StatusEx.STATUS.PAGECACHE_OVERFLOW, sz);
                    MutexEx.Leave(pcache1.mutex);
                }
                SysEx.sqlite3MemdebugSetType(p, SysEx.MEMTYPE.PCACHE);
            }
            return(p);
        }
        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);
        }
Exemple #7
0
        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;
        }
 private static void pcache1Free(ref PgHdr p)
 {
     if (p == null)
     {
         return;
     }
     if (p.CacheAllocated)
     {
         var pSlot = new PgFreeslot();
         MutexEx.Enter(pcache1.mutex);
         StatusEx.sqlite3StatusAdd(StatusEx.STATUS.PAGECACHE_USED, -1);
         pSlot._PgHdr  = p;
         pSlot.pNext   = pcache1.pFree;
         pcache1.pFree = pSlot;
         pcache1.nFreeSlot++;
         pcache1.bUnderPressure = pcache1.nFreeSlot < pcache1.nReserve;
         Debug.Assert(pcache1.nFreeSlot <= pcache1.nSlot);
         MutexEx.Leave(pcache1.mutex);
     }
     else
     {
         Debug.Assert(SysEx.sqlite3MemdebugHasType(p, SysEx.MEMTYPE.PCACHE));
         SysEx.sqlite3MemdebugSetType(p, SysEx.MEMTYPE.HEAP);
         var iSize = MallocEx.sqlite3MallocSize(p.Data);
         MutexEx.Enter(pcache1.mutex);
         StatusEx.sqlite3StatusAdd(StatusEx.STATUS.PAGECACHE_OVERFLOW, -iSize);
         MutexEx.Leave(pcache1.mutex);
         MallocEx.sqlite3_free(ref p.Data);
     }
 }
Exemple #9
0
 // was:sqlite3BtreeCacheOverflow
 public void BtreeCacheOverflow()
 {
     Debug.Assert(HoldsMutex());
     Debug.Assert(MutexEx.Held(Tree.DB.Mutex));
     Btree.invalidateOverflowCache(this);
     IsIncrblob = true;
 }
Exemple #10
0
        public static VirtualFileSystem FindVfs(string zVfs)
        {
            VirtualFileSystem pVfs = null;

            //#if !SQLITE_OMIT_AUTOINIT
            //            var rc = sqlite3_initialize();
            //            if (rc != SQLITE.OK)
            //                return null;
            //#endif
#if SQLITE_THREADSAFE
            var mutex = MutexEx.Alloc(MutexEx.MUTEX.STATIC_MASTER);
#endif
            MutexEx.Enter(mutex);
            for (pVfs = vfsList; pVfs != null; pVfs = pVfs.pNext)
            {
                if (zVfs == null || zVfs == "")
                {
                    break;
                }
                if (zVfs == pVfs.zName)
                {
                    break;
                }
            }
            MutexEx.Leave(mutex);
            return(pVfs);
        }
Exemple #11
0
        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--;
            }
        }
Exemple #12
0
        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;
        }
Exemple #13
0
        // 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));
        }
Exemple #14
0
        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 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);
        }
Exemple #16
0
 // 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);
     }
 }
Exemple #17
0
        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());
        }
        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);
 }
Exemple #20
0
        // 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);
        }
Exemple #21
0
 // 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);
        }
Exemple #23
0
        // 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);
        }
Exemple #24
0
 // 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);
 }
Exemple #25
0
        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);
        }
 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;
     }
 }
Exemple #27
0
 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);
     }
 }
Exemple #28
0
 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);
     }
 }
 public static RC xInit(object NotUsed)
 {
     SysEx.UNUSED_PARAMETER(NotUsed);
     Debug.Assert(pcache1 == null);
     pcache1 = new PCacheGlobal();
     if (sqlite3GlobalConfig_bCoreMutex)
     {
         pcache1.grp.mutex = MutexEx.sqlite3_mutex_alloc(MutexEx.MUTEX.STATIC_LRU);
         pcache1.mutex     = MutexEx.sqlite3_mutex_alloc(MutexEx.MUTEX.STATIC_PMEM);
     }
     pcache1.grp.mxPinned = 10;
     return(RC.OK);
 }
        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);
        }
Exemple #31
0
 public static void Enter(MutexEx mutex)
 {
 }
Exemple #32
0
 public static void Free(MutexEx mutex)
 {
 }
Exemple #33
0
 public static void Leave(MutexEx mutex)
 {
 }
Exemple #34
0
 public static bool NotHeld(MutexEx mutex)
 {
     return true;
 }