internal static void copyNodeContent(MemPage pFrom, MemPage pTo, ref RC pRC) { if (pRC != RC.OK) { return; } var pBt = pFrom.Shared; var aFrom = pFrom.Data; var aTo = pTo.Data; var iFromHdr = pFrom.HeaderOffset; var iToHdr = (pTo.ID == 1 ? 100 : 0); Debug.Assert(pFrom.HasInit); Debug.Assert(pFrom.FreeBytes >= iToHdr); Debug.Assert(ConvertEx.Get2(aFrom, iFromHdr + 5) <= (int)pBt.UsableSize); // Copy the b-tree node content from page pFrom to page pTo. var iData = (int)ConvertEx.Get2(aFrom, iFromHdr + 5); Buffer.BlockCopy(aFrom, iData, aTo, iData, (int)pBt.UsableSize - iData); Buffer.BlockCopy(aFrom, iFromHdr, aTo, iToHdr, pFrom.CellOffset + 2 * pFrom.Cells); // Reinitialize page pTo so that the contents of the MemPage structure match the new data. The initialization of pTo can actually fail under // fairly obscure circumstances, even though it is a copy of initialized page pFrom. pTo.HasInit = false; var rc = pTo.btreeInitPage(); if (rc != RC.OK) { pRC = rc; return; } // If this is an auto-vacuum database, update the pointer-map entries for any b-tree or overflow pages that pTo now contains the pointers to. #if !SQLITE_OMIT_AUTOVACUUM if (pBt.AutoVacuum) #else if (false) #endif { pRC = pTo.setChildPtrmaps(); } }
internal static void copyNodeContent(MemPage pFrom, MemPage pTo, ref RC pRC) { if (pRC != RC.OK) return; var pBt = pFrom.Shared; var aFrom = pFrom.Data; var aTo = pTo.Data; var iFromHdr = pFrom.HeaderOffset; var iToHdr = (pTo.ID == 1 ? 100 : 0); Debug.Assert(pFrom.HasInit); Debug.Assert(pFrom.FreeBytes >= iToHdr); Debug.Assert(ConvertEx.Get2(aFrom, iFromHdr + 5) <= (int)pBt.UsableSize); // Copy the b-tree node content from page pFrom to page pTo. var iData = (int)ConvertEx.Get2(aFrom, iFromHdr + 5); Buffer.BlockCopy(aFrom, iData, aTo, iData, (int)pBt.UsableSize - iData); Buffer.BlockCopy(aFrom, iFromHdr, aTo, iToHdr, pFrom.CellOffset + 2 * pFrom.Cells); // Reinitialize page pTo so that the contents of the MemPage structure match the new data. The initialization of pTo can actually fail under // fairly obscure circumstances, even though it is a copy of initialized page pFrom. pTo.HasInit = false; var rc = pTo.btreeInitPage(); if (rc != RC.OK) { pRC = rc; return; } // If this is an auto-vacuum database, update the pointer-map entries for any b-tree or overflow pages that pTo now contains the pointers to. #if !SQLITE_OMIT_AUTOVACUUM if (pBt.AutoVacuum) #else if (false) #endif { pRC = pTo.setChildPtrmaps(); } }
internal static RC relocatePage(BtShared pBt, MemPage pDbPage, PTRMAP eType, Pgno iPtrPage, Pgno iFreePage, int isCommit) { var pPtrPage = new MemPage(); // The page that contains a pointer to pDbPage var iDbPage = pDbPage.ID; var pPager = pBt.Pager; Debug.Assert(eType == PTRMAP.OVERFLOW2 || eType == PTRMAP.OVERFLOW1 || eType == PTRMAP.BTREE || eType == PTRMAP.ROOTPAGE); Debug.Assert(MutexEx.Held(pBt.Mutex)); Debug.Assert(pDbPage.Shared == pBt); // Move page iDbPage from its current location to page number iFreePage Btree.TRACE("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", iDbPage, iFreePage, iPtrPage, eType); var rc = pPager.sqlite3PagerMovepage(pDbPage.DbPage, iFreePage, isCommit); if (rc != RC.OK) { return(rc); } pDbPage.ID = iFreePage; // If pDbPage was a btree-page, then it may have child pages and/or cells that point to overflow pages. The pointer map entries for all these // pages need to be changed. // If pDbPage is an overflow page, then the first 4 bytes may store a pointer to a subsequent overflow page. If this is the case, then // the pointer map needs to be updated for the subsequent overflow page. if (eType == PTRMAP.BTREE || eType == PTRMAP.ROOTPAGE) { rc = pDbPage.setChildPtrmaps(); if (rc != RC.OK) { return(rc); } } else { var nextOvfl = (Pgno)ConvertEx.Get4(pDbPage.Data); if (nextOvfl != 0) { pBt.ptrmapPut(nextOvfl, PTRMAP.OVERFLOW2, iFreePage, ref rc); if (rc != RC.OK) { return(rc); } } } // Fix the database pointer on page iPtrPage that pointed at iDbPage so that it points at iFreePage. Also fix the pointer map entry for iPtrPage. if (eType != PTRMAP.ROOTPAGE) { rc = pBt.btreeGetPage(iPtrPage, ref pPtrPage, 0); if (rc != RC.OK) { return(rc); } rc = Pager.Write(pPtrPage.DbPage); if (rc != RC.OK) { pPtrPage.releasePage(); return(rc); } rc = pPtrPage.modifyPagePointer(iDbPage, iFreePage, eType); pPtrPage.releasePage(); if (rc == RC.OK) { pBt.ptrmapPut(iFreePage, eType, iPtrPage, ref rc); } } return(rc); }
internal static RC relocatePage(BtShared pBt, MemPage pDbPage, PTRMAP eType, Pgno iPtrPage, Pgno iFreePage, int isCommit) { var pPtrPage = new MemPage(); // The page that contains a pointer to pDbPage var iDbPage = pDbPage.ID; var pPager = pBt.Pager; Debug.Assert(eType == PTRMAP.OVERFLOW2 || eType == PTRMAP.OVERFLOW1 || eType == PTRMAP.BTREE || eType == PTRMAP.ROOTPAGE); Debug.Assert(MutexEx.Held(pBt.Mutex)); Debug.Assert(pDbPage.Shared == pBt); // Move page iDbPage from its current location to page number iFreePage Btree.TRACE("AUTOVACUUM: Moving %d to free page %d (ptr page %d type %d)\n", iDbPage, iFreePage, iPtrPage, eType); var rc = pPager.sqlite3PagerMovepage(pDbPage.DbPage, iFreePage, isCommit); if (rc != RC.OK) return rc; pDbPage.ID = iFreePage; // If pDbPage was a btree-page, then it may have child pages and/or cells that point to overflow pages. The pointer map entries for all these // pages need to be changed. // If pDbPage is an overflow page, then the first 4 bytes may store a pointer to a subsequent overflow page. If this is the case, then // the pointer map needs to be updated for the subsequent overflow page. if (eType == PTRMAP.BTREE || eType == PTRMAP.ROOTPAGE) { rc = pDbPage.setChildPtrmaps(); if (rc != RC.OK) return rc; } else { var nextOvfl = (Pgno)ConvertEx.Get4(pDbPage.Data); if (nextOvfl != 0) { pBt.ptrmapPut(nextOvfl, PTRMAP.OVERFLOW2, iFreePage, ref rc); if (rc != RC.OK) return rc; } } // Fix the database pointer on page iPtrPage that pointed at iDbPage so that it points at iFreePage. Also fix the pointer map entry for iPtrPage. if (eType != PTRMAP.ROOTPAGE) { rc = pBt.btreeGetPage(iPtrPage, ref pPtrPage, 0); if (rc != RC.OK) return rc; rc = Pager.Write(pPtrPage.DbPage); if (rc != RC.OK) { pPtrPage.releasePage(); return rc; } rc = pPtrPage.modifyPagePointer(iDbPage, iFreePage, eType); pPtrPage.releasePage(); if (rc == RC.OK) pBt.ptrmapPut(iFreePage, eType, iPtrPage, ref rc); } return rc; }