/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #define DBTUP_C #include "Dbtup.hpp" #include #include #include #include #include #include #define ljam() { jamLine(26000 + __LINE__); } #define ljamEntry() { jamEntryLine(26000 + __LINE__); } /* **************************************************************** */ /* ********************* SYSTEM RESTART MANAGER ******************* */ /* **************************************************************** */ /***************************************************************/ /* CHECK RESTART STATE AND SET NEW STATE CALLED IN OPEN, */ /* READ AND COPY STATES */ /***************************************************************/ void Dbtup::execTUP_SRREQ(Signal* signal) { RestartInfoRecordPtr riPtr; PendingFileOpenInfoPtr pfoiPtr; ljamEntry(); Uint32 userPtr = signal->theData[0]; Uint32 userBlockref = signal->theData[1]; Uint32 tableId = signal->theData[2]; Uint32 fragId = signal->theData[3]; Uint32 checkpointNumber = signal->theData[4]; seizeRestartInfoRecord(riPtr); riPtr.p->sriUserptr = userPtr; riPtr.p->sriBlockref = userBlockref; riPtr.p->sriState = OPENING_DATA_FILE; riPtr.p->sriCheckpointVersion = checkpointNumber; riPtr.p->sriFragid = fragId; riPtr.p->sriTableId = tableId; /* OPEN THE DATA FILE IN THE FOLLOWING FORM */ /* D5/DBTUP/T/F/S.DATA */ Uint32 fileType = 1; /* VERSION */ fileType = (fileType << 8) | 0; /* .DATA */ fileType = (fileType << 8) | 5; /* D5 */ fileType = (fileType << 8) | 0xff; /* DON'T USE P DIRECTORY LEVEL */ Uint32 fileFlag = 0; /* READ ONLY */ seizePendingFileOpenInfoRecord(pfoiPtr); pfoiPtr.p->pfoOpenType = LCP_DATA_FILE_READ; pfoiPtr.p->pfoRestartInfoP = riPtr.i; signal->theData[0] = cownref; signal->theData[1] = pfoiPtr.i; signal->theData[2] = tableId; signal->theData[3] = fragId; signal->theData[4] = checkpointNumber; signal->theData[5] = fileType; signal->theData[6] = fileFlag; sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA); return; }//Dbtup::execTUP_SRREQ() void Dbtup::seizeRestartInfoRecord(RestartInfoRecordPtr& riPtr) { riPtr.i = cfirstfreeSri; ptrCheckGuard(riPtr, cnoOfRestartInfoRec, restartInfoRecord); cfirstfreeSri = riPtr.p->sriNextRec; riPtr.p->sriNextRec = RNIL; }//Dbtup::seizeRestartInfoRecord() void Dbtup::rfrReadRestartInfoLab(Signal* signal, RestartInfoRecordPtr riPtr) { DiskBufferSegmentInfoPtr dbsiPtr; seizeDiskBufferSegmentRecord(dbsiPtr); riPtr.p->sriDataBufferSegmentP = dbsiPtr.i; Uint32 retPageRef = RNIL; Uint32 noAllocPages = 1; Uint32 noOfPagesAllocated; { /** * Use low pages for 0-pages during SR * bitmask of free pages is kept in c_sr_free_page_0 */ Uint32 tmp = c_sr_free_page_0; for(Uint32 i = 1; i<(1+MAX_PARALLELL_TUP_SRREQ); i++){ if(tmp & (1 << i)){ retPageRef = i; c_sr_free_page_0 = tmp & (~(1 << i)); break; } } ndbrequire(retPageRef != RNIL); } dbsiPtr.p->pdxDataPage[0] = retPageRef; dbsiPtr.p->pdxNumDataPages = 1; dbsiPtr.p->pdxFilePage = 0; rfrReadNextDataSegment(signal, riPtr, dbsiPtr); dbsiPtr.p->pdxOperation = CHECKPOINT_DATA_READ_PAGE_ZERO; }//Dbtup::rfrReadRestartInfoLab() /***************************************************************/ /* THE RESTART INFORMATION IS NOW READ INTO THE DATA BUFFER */ /* USE THE RESTART INFORMATION TO INITIATE THE RESTART RECORD */ /***************************************************************/ void Dbtup::rfrInitRestartInfoLab(Signal* signal, DiskBufferSegmentInfoPtr dbsiPtr) { Uint32 TzeroDataPage[64]; Uint32 Ti; FragrecordPtr regFragPtr; LocalLogInfoPtr lliPtr; PagePtr pagePtr; RestartInfoRecordPtr riPtr; TablerecPtr regTabPtr; riPtr.i = dbsiPtr.p->pdxRestartInfoP; ptrCheckGuard(riPtr, cnoOfRestartInfoRec, restartInfoRecord); regTabPtr.i = riPtr.p->sriTableId; ptrCheckGuard(regTabPtr, cnoOfTablerec, tablerec); Uint32 fragId = riPtr.p->sriFragid; getFragmentrec(regFragPtr, fragId, regTabPtr.p); riPtr.p->sriFragP = regFragPtr.i; /* ----- PAGE ALLOCATION --- */ /* ALLOCATE PAGES TO FRAGMENT, INSERT THEM INTO PAGE RANGE TABLE AND */ /* ALSO CONVERT THEM INTO EMPTY PAGES AND INSERT THEM INTO THE EMPTY LIST */ /* OF THE FRAGMENT. SET ALL LISTS OF FREE PAGES TO RNIL */ ndbrequire(cfirstfreerange != RNIL); pagePtr.i = dbsiPtr.p->pdxDataPage[0]; ptrCheckGuard(pagePtr, cnoOfPage, page); for (Ti = 0; Ti < 63; Ti++) { /***************************************************************/ // Save Important content from Page zero in stack variable so // that we can immediately release page zero. /***************************************************************/ TzeroDataPage[Ti] = pagePtr.p->pageWord[Ti]; }//for /************************************************************************/ /* NOW WE DON'T NEED THE RESTART INFO BUFFER PAGE ANYMORE */ /* LETS REMOVE IT AND REUSE THE SEGMENT FOR REAL DATA PAGES */ /* REMOVE ONE PAGE ONLY, PAGEP IS ALREADY SET TO THE RESTART INFO PAGE */ /************************************************************************/ { ndbrequire(pagePtr.i > 0 && pagePtr.i <= MAX_PARALLELL_TUP_SRREQ); c_sr_free_page_0 |= (1 << pagePtr.i); } Uint32 undoFileVersion = TzeroDataPage[ZSRI_UNDO_FILE_VER]; lliPtr.i = (undoFileVersion << 2) + (regTabPtr.i & 0x3); ptrCheckGuard(lliPtr, cnoOfParallellUndoFiles, localLogInfo); riPtr.p->sriLocalLogInfoP = lliPtr.i; ndbrequire(regFragPtr.p->fragTableId == regTabPtr.i); ndbrequire(regFragPtr.p->fragmentId == fragId); regFragPtr.p->fragStatus = SYSTEM_RESTART; regFragPtr.p->noCopyPagesAlloc = TzeroDataPage[ZSRI_NO_COPY_PAGES_ALLOC]; riPtr.p->sriCurDataPageFromBuffer = 0; riPtr.p->sriNumDataPages = TzeroDataPage[ZSRI_NO_OF_FRAG_PAGES_POS]; ndbrequire(riPtr.p->sriNumDataPages >= regFragPtr.p->noOfPages); const Uint32 pageCount = riPtr.p->sriNumDataPages - regFragPtr.p->noOfPages; if(pageCount > 0){ Uint32 noAllocPages = allocFragPages(regFragPtr.p, pageCount); ndbrequire(noAllocPages == pageCount); }//if ndbrequire(getNoOfPages(regFragPtr.p) == riPtr.p->sriNumDataPages); /***************************************************************/ // Set the variables on fragment record which might have been // affected by allocFragPages. /***************************************************************/ regFragPtr.p->emptyPrimPage = TzeroDataPage[ZSRI_EMPTY_PRIM_PAGE]; regFragPtr.p->thFreeFirst = TzeroDataPage[ZSRI_TH_FREE_FIRST]; regFragPtr.p->thFreeCopyFirst = TzeroDataPage[ZSRI_TH_FREE_COPY_FIRST]; /***************************************************************/ /* THE RESTART INFORMATION IS NOW READ INTO THE DATA BUFFER */ /* USE THE RESTART INFORMATION TO INITIATE THE FRAGMENT */ /***************************************************************/ /** * IF THIS UNDO FILE IS NOT OPEN, IT WILL BE OPENED HERE AND THE EXECUTION * WILL CONTINUE WHEN THE FSOPENCONF IS ENTERED. * IF IT'S ALREADY IN USE THE EXECUTION WILL CONTINUE BY A * CONTINUE B SIGNAL */ if (lliPtr.p->lliActiveLcp == 0) { PendingFileOpenInfoPtr pfoiPtr; ljam(); /***************************************************************/ /* OPEN THE UNDO FILE FOR READ */ /* THE FILE HANDLE WILL BE SET IN THE LOCAL_LOG_INFO_REC */ /* UPON FSOPENCONF */ /***************************************************************/ cnoOfLocalLogInfo++; /* F_LEVEL NOT USED */ Uint32 fileType = 1; /* VERSION */ fileType = (fileType << 8) | 2; /* .LOCLOG */ fileType = (fileType << 8) | 6; /* D6 */ fileType = (fileType << 8) | 0xff; /* DON'T USE P DIRECTORY LEVEL */ Uint32 fileFlag = 0; /* READ ONLY */ seizePendingFileOpenInfoRecord(pfoiPtr); pfoiPtr.p->pfoOpenType = LCP_UNDO_FILE_READ; pfoiPtr.p->pfoRestartInfoP = riPtr.i; signal->theData[0] = cownref; signal->theData[1] = pfoiPtr.i; signal->theData[2] = lliPtr.i; signal->theData[3] = 0xFFFFFFFF; signal->theData[4] = undoFileVersion; signal->theData[5] = fileType; signal->theData[6] = fileFlag; sendSignal(NDBFS_REF, GSN_FSOPENREQ, signal, 7, JBA); lliPtr.p->lliPrevRecordId = 0; lliPtr.p->lliActiveLcp = 1; lliPtr.p->lliNumFragments = 1; } else { ljam(); signal->theData[0] = ZCONT_LOAD_DP; signal->theData[1] = riPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); lliPtr.p->lliNumFragments++; }//if /* RETAIN THE HIGH- AND LOWSCORE ID:S OF THE LOGRECORD POSITIONS. WE HAVE TO EXECUTE THE */ /* UNDO LOG BETWEEN THE END AND START RECORDS FOR ALL RECORDS THAT INCLUDE FRAGMENTS OF */ /* THE RIGHT CHECKPOINT VERSION TO COMPLETE THE OPERATION WE HAVE TO RUN ALL LOGS THAT */ /* HAS THE NUMBER OF LCP ELEMENT GREATER THAN 0, I.E. IS INCLUDED. */ if (TzeroDataPage[ZSRI_UNDO_LOG_END_REC_ID] > lliPtr.p->lliPrevRecordId) { ljam(); lliPtr.p->lliPrevRecordId = TzeroDataPage[ZSRI_UNDO_LOG_END_REC_ID]; lliPtr.p->lliEndPageId = TzeroDataPage[ZSRI_UNDO_LOG_END_PAGE_ID]; }//if return; }//Dbtup::rfrInitRestartInfoLab() /***************************************************************/ /* LOAD THE NEXT DATA PAGE SEGMENT INTO MEMORY */ /***************************************************************/ void Dbtup::rfrLoadDataPagesLab(Signal* signal, RestartInfoRecordPtr riPtr, DiskBufferSegmentInfoPtr dbsiPtr) { FragrecordPtr regFragPtr; if (riPtr.p->sriCurDataPageFromBuffer >= riPtr.p->sriNumDataPages) { ljam(); rfrCompletedLab(signal, riPtr); return; }//if Uint32 startPage = riPtr.p->sriCurDataPageFromBuffer; Uint32 endPage; if ((startPage + ZDB_SEGMENT_SIZE) < riPtr.p->sriNumDataPages) { ljam(); endPage = startPage + ZDB_SEGMENT_SIZE; } else { ljam(); endPage = riPtr.p->sriNumDataPages; }//if regFragPtr.i = riPtr.p->sriFragP; ptrCheckGuard(regFragPtr, cnoOfFragrec, fragrecord); ndbrequire((endPage - startPage) <= 16); Uint32 i = 0; for (Uint32 pageId = startPage; pageId < endPage; pageId++) { ljam(); dbsiPtr.p->pdxDataPage[i] = getRealpid(regFragPtr.p, pageId); i++; }//for dbsiPtr.p->pdxNumDataPages = endPage - startPage; /* SET THE NUMBER OF DATA PAGES */ riPtr.p->sriCurDataPageFromBuffer = endPage; dbsiPtr.p->pdxFilePage = startPage + 1; rfrReadNextDataSegment(signal, riPtr, dbsiPtr); return; }//Dbtup::rfrLoadDataPagesLab() void Dbtup::rfrCompletedLab(Signal* signal, RestartInfoRecordPtr riPtr) { PendingFileOpenInfoPtr pfoPtr; /* ---------------------------------------------------------------------- */ /* CLOSE THE DATA FILE BEFORE SENDING TUP_SRCONF */ /* ---------------------------------------------------------------------- */ seizePendingFileOpenInfoRecord(pfoPtr); pfoPtr.p->pfoOpenType = LCP_DATA_FILE_READ; pfoPtr.p->pfoCheckpointInfoP = riPtr.i; signal->theData[0] = riPtr.p->sriDataFileHandle; signal->theData[1] = cownref; signal->theData[2] = pfoPtr.i; signal->theData[3] = 0; sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA); }//Dbtup::rfrCompletedLab() void Dbtup::rfrClosedDataFileLab(Signal* signal, Uint32 restartIndex) { RestartInfoRecordPtr riPtr; DiskBufferSegmentInfoPtr dbsiPtr; riPtr.i = restartIndex; ptrCheckGuard(riPtr, cnoOfRestartInfoRec, restartInfoRecord); riPtr.p->sriDataFileHandle = RNIL; dbsiPtr.i = riPtr.p->sriDataBufferSegmentP; ptrCheckGuard(dbsiPtr, cnoOfConcurrentWriteOp, diskBufferSegmentInfo); releaseDiskBufferSegmentRecord(dbsiPtr); signal->theData[0] = riPtr.p->sriUserptr; signal->theData[1] = riPtr.p->sriFragP; sendSignal(riPtr.p->sriBlockref, GSN_TUP_SRCONF, signal, 2, JBB); releaseRestartInfoRecord(riPtr); }//Dbtup::rfrClosedDataFileLab() /* ---------------------------------------------------------------- */ /* ---------------------- EXECUTE LOCAL LOG ---------------------- */ /* ---------------------------------------------------------------- */ void Dbtup::execSTART_RECREQ(Signal* signal) { ljamEntry(); clqhUserpointer = signal->theData[0]; clqhBlockref = signal->theData[1]; for (int i = 0; i < ZNO_CHECKPOINT_RECORDS; i++){ cSrUndoRecords[i] = 0; }//for if (cnoOfLocalLogInfo == 0) { ljam(); /* ---------------------------------------------------------------- */ /* THERE WERE NO LOCAL LOGS TO EXECUTE IN THIS SYSTEM RESTART */ /* ---------------------------------------------------------------- */ xlcRestartCompletedLab(signal); return; }//if LocalLogInfoPtr lliPtr; for (lliPtr.i = 0; lliPtr.i < 16; lliPtr.i++) { ljam(); ptrAss(lliPtr, localLogInfo); if (lliPtr.p->lliActiveLcp == 1) { ljam(); signal->theData[0] = ZSTART_EXEC_UNDO_LOG; signal->theData[1] = lliPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); }//if }//for return; }//Dbtup::execSTART_RECREQ() void Dbtup::closeExecUndoLogLab(Signal* signal, LocalLogInfoPtr lliPtr) { PendingFileOpenInfoPtr pfoPtr; /* ---------------------------------------------------------------------- */ /* CLOSE THE UNDO LOG BEFORE COMPLETION OF THE SYSTEM RESTART */ /* ---------------------------------------------------------------------- */ seizePendingFileOpenInfoRecord(pfoPtr); pfoPtr.p->pfoOpenType = LCP_UNDO_FILE_READ; pfoPtr.p->pfoCheckpointInfoP = lliPtr.i; signal->theData[0] = lliPtr.p->lliUndoFileHandle; signal->theData[1] = cownref; signal->theData[2] = pfoPtr.i; signal->theData[3] = 0; sendSignal(NDBFS_REF, GSN_FSCLOSEREQ, signal, 4, JBA); return; }//Dbtup::closeExecUndoLogLab() void Dbtup::endExecUndoLogLab(Signal* signal, Uint32 lliIndex) { DiskBufferSegmentInfoPtr dbsiPtr; LocalLogInfoPtr lliPtr; lliPtr.i = lliIndex; ptrCheckGuard(lliPtr, cnoOfParallellUndoFiles, localLogInfo); lliPtr.p->lliUndoFileHandle = RNIL; lliPtr.p->lliActiveLcp = 0; /* ---------------------------------------------------------------------- */ /* WE HAVE NOW CLOSED THE LOG. WE WAIT FOR ALL LOCAL LOGS TO */ /* COMPLETE LOG EXECUTION BEFORE SENDING THE RESPONSE TO LQH. */ /* ---------------------------------------------------------------------- */ dbsiPtr.i = lliPtr.p->lliUndoBufferSegmentP; ptrCheckGuard(dbsiPtr, cnoOfConcurrentWriteOp, diskBufferSegmentInfo); freeDiskBufferSegmentRecord(signal, dbsiPtr); lliPtr.p->lliUndoBufferSegmentP = RNIL; for (lliPtr.i = 0; lliPtr.i < 16; lliPtr.i++) { ljam(); ptrAss(lliPtr, localLogInfo); if (lliPtr.p->lliActiveLcp == 1) { ljam(); return; }//if }//for xlcRestartCompletedLab(signal); return; }//Dbtup::endExecUndoLogLab() void Dbtup::xlcRestartCompletedLab(Signal* signal) { cnoOfLocalLogInfo = 0; signal->theData[0] = EventReport::UNDORecordsExecuted; signal->theData[1] = DBTUP; // From block signal->theData[2] = 0; // Total records executed for (int i = 0; i < 10; i++) { if (i < ZNO_CHECKPOINT_RECORDS){ signal->theData[i+3] = cSrUndoRecords[i]; signal->theData[2] += cSrUndoRecords[i]; } else { signal->theData[i+3] = 0; // Unsused data }//if }//for sendSignal(CMVMI_REF, GSN_EVENT_REP, signal, 12, JBB); /* ---------------------------------------------------------------------- */ /* ALL LOCAL LOGS HAVE COMPLETED. WE HAVE COMPLETED OUR PART OF THE */ /* SYSTEM RESTART. */ /* ---------------------------------------------------------------------- */ signal->theData[0] = clqhUserpointer; sendSignal(clqhBlockref, GSN_START_RECCONF, signal, 1, JBB); return; }//Dbtup::xlcRestartCompletedLab() void Dbtup::startExecUndoLogLab(Signal* signal, Uint32 lliIndex) { DiskBufferSegmentInfoPtr dbsiPtr; LocalLogInfoPtr lliPtr; /* ---------------------------------------------------------------------- */ /* START EXECUTING THE LOG FOR THIS PART. WE BEGIN BY READING THE */ /* LAST 16 PAGES. */ /* ---------------------------------------------------------------------- */ /* SET THE PREVIOS RECORD TO THE LAST ONE BECAUSE THAT'S WHERE TO START */ lliPtr.i = lliIndex; ptrCheckGuard(lliPtr, cnoOfParallellUndoFiles, localLogInfo); allocRestartUndoBufferSegment(signal, dbsiPtr, lliPtr); lliPtr.p->lliUndoBufferSegmentP = dbsiPtr.i; dbsiPtr.p->pdxCheckpointInfoP = lliPtr.i; if (lliPtr.p->lliEndPageId > ((2 * ZUB_SEGMENT_SIZE) - 1)) { ljam(); dbsiPtr.p->pdxNumDataPages = ZUB_SEGMENT_SIZE; dbsiPtr.p->pdxFilePage = lliPtr.p->lliEndPageId - (ZUB_SEGMENT_SIZE - 1); } else if (lliPtr.p->lliEndPageId > (ZUB_SEGMENT_SIZE - 1)) { ljam(); dbsiPtr.p->pdxNumDataPages = lliPtr.p->lliEndPageId - (ZUB_SEGMENT_SIZE - 1); dbsiPtr.p->pdxFilePage = ZUB_SEGMENT_SIZE; } else { ljam(); dbsiPtr.p->pdxNumDataPages = lliPtr.p->lliEndPageId + 1; dbsiPtr.p->pdxFilePage = 0; rfrReadNextUndoSegment(signal, dbsiPtr, lliPtr); return; }//if rfrReadFirstUndoSegment(signal, dbsiPtr, lliPtr); return; }//Dbtup::startExecUndoLogLab() void Dbtup::rfrReadSecondUndoLogLab(Signal* signal, DiskBufferSegmentInfoPtr dbsiPtr) { LocalLogInfoPtr lliPtr; lliPtr.i = dbsiPtr.p->pdxCheckpointInfoP; ptrCheckGuard(lliPtr, cnoOfParallellUndoFiles, localLogInfo); dbsiPtr.p->pdxNumDataPages = ZUB_SEGMENT_SIZE; dbsiPtr.p->pdxFilePage -= ZUB_SEGMENT_SIZE; rfrReadNextUndoSegment(signal, dbsiPtr, lliPtr); return; }//Dbtup::rfrReadSecondUndoLogLab() void Dbtup::readExecUndoLogLab(Signal* signal, DiskBufferSegmentInfoPtr dbsiPtr, LocalLogInfoPtr lliPtr) { /* ---------------------------------------------------------------------- */ /* THE NEXT UNDO LOG RECORD HAS NOT BEEN READ FROM DISK YET. WE WILL*/ /* READ UPTO 8 PAGES BACKWARDS OF THE UNDO LOG FILE. WE WILL KEEP */ /* THE LAST 8 PAGES TO ENSURE THAT WE WILL BE ABLE TO READ THE NEXT */ /* LOG RECORD EVEN IF IT SPANS UPTO 8 PAGES. */ /* ---------------------------------------------------------------------- */ if (dbsiPtr.p->pdxFilePage >= ZUB_SEGMENT_SIZE) { ljam(); for (Uint32 i = 0; i < ZUB_SEGMENT_SIZE; i++) { ljam(); Uint32 savePageId = dbsiPtr.p->pdxDataPage[i + ZUB_SEGMENT_SIZE]; dbsiPtr.p->pdxDataPage[i + ZUB_SEGMENT_SIZE] = dbsiPtr.p->pdxDataPage[i]; dbsiPtr.p->pdxDataPage[i] = savePageId; }//for dbsiPtr.p->pdxNumDataPages = ZUB_SEGMENT_SIZE; dbsiPtr.p->pdxFilePage = dbsiPtr.p->pdxFilePage - ZUB_SEGMENT_SIZE; } else { ljam(); Uint32 dataPages[16]; ndbrequire(dbsiPtr.p->pdxFilePage > 0); ndbrequire(dbsiPtr.p->pdxFilePage <= ZUB_SEGMENT_SIZE); Uint32 i; for (i = 0; i < dbsiPtr.p->pdxFilePage; i++) { ljam(); dataPages[i] = dbsiPtr.p->pdxDataPage[i + ZUB_SEGMENT_SIZE]; }//for for (i = 0; i < ZUB_SEGMENT_SIZE; i++) { ljam(); dataPages[i + dbsiPtr.p->pdxFilePage] = dbsiPtr.p->pdxDataPage[i]; }//for Uint32 limitLoop = ZUB_SEGMENT_SIZE + dbsiPtr.p->pdxFilePage; for (i = 0; i < limitLoop; i++) { ljam(); dbsiPtr.p->pdxDataPage[i] = dataPages[i]; }//for dbsiPtr.p->pdxNumDataPages = dbsiPtr.p->pdxFilePage; dbsiPtr.p->pdxFilePage = 0; }//if rfrReadNextUndoSegment(signal, dbsiPtr, lliPtr); return; }//Dbtup::readExecUndoLogLab() void Dbtup::rfrReadNextDataSegment(Signal* signal, RestartInfoRecordPtr riPtr, DiskBufferSegmentInfoPtr dbsiPtr) { dbsiPtr.p->pdxRestartInfoP = riPtr.i; dbsiPtr.p->pdxOperation = CHECKPOINT_DATA_READ; ndbrequire(dbsiPtr.p->pdxNumDataPages <= 8); signal->theData[0] = riPtr.p->sriDataFileHandle; signal->theData[1] = cownref; signal->theData[2] = dbsiPtr.i; signal->theData[3] = 2; signal->theData[4] = ZBASE_ADDR_PAGE_WORD; signal->theData[5] = dbsiPtr.p->pdxNumDataPages; for (Uint32 i = 0; i < dbsiPtr.p->pdxNumDataPages; i++) { ljam(); signal->theData[6 + i] = dbsiPtr.p->pdxDataPage[i]; }//for signal->theData[6 + dbsiPtr.p->pdxNumDataPages] = dbsiPtr.p->pdxFilePage; sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 15, JBA); }//Dbtup::rfrReadNextDataSegment() /* ---------------------------------------------------------------- */ /* ------------------- RFR_READ_FIRST_UNDO_SEGMENT ---------------- */ /* ---------------------------------------------------------------- */ /* THIS ROUTINE READS IN THE FIRST UNDO SEGMENT INTO THE CURRENTLY */ /* ACTIVE UNDO BUFFER SEGMENT */ /* -----------------------------------------------------------------*/ void Dbtup::rfrReadFirstUndoSegment(Signal* signal, DiskBufferSegmentInfoPtr dbsiPtr, LocalLogInfoPtr lliPtr) { dbsiPtr.p->pdxOperation = CHECKPOINT_UNDO_READ_FIRST; signal->theData[0] = lliPtr.p->lliUndoFileHandle; signal->theData[1] = cownref; signal->theData[2] = dbsiPtr.i; signal->theData[3] = 1; signal->theData[4] = ZBASE_ADDR_UNDO_WORD; signal->theData[5] = dbsiPtr.p->pdxNumDataPages; signal->theData[6] = dbsiPtr.p->pdxDataPage[ZUB_SEGMENT_SIZE]; signal->theData[7] = dbsiPtr.p->pdxFilePage; sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA); }//Dbtup::rfrReadFirstUndoSegment() /* ---------------------------------------------------------------- */ /* ------------------- RFR_READ_NEXT_UNDO_SEGMENT ----------------- */ /* ---------------------------------------------------------------- */ /* THIS ROUTINE READS IN THE NEXT UNDO SEGMENT INTO THE CURRENTLY */ /* ACTIVE UNDO BUFFER SEGMENT AND SWITCH TO THE UNACTIVE, READY ONE */ /* -----------------------------------------------------------------*/ void Dbtup::rfrReadNextUndoSegment(Signal* signal, DiskBufferSegmentInfoPtr dbsiPtr, LocalLogInfoPtr lliPtr) { dbsiPtr.p->pdxOperation = CHECKPOINT_UNDO_READ; signal->theData[0] = lliPtr.p->lliUndoFileHandle; signal->theData[1] = cownref; signal->theData[2] = dbsiPtr.i; signal->theData[3] = 1; signal->theData[4] = ZBASE_ADDR_UNDO_WORD; signal->theData[5] = dbsiPtr.p->pdxNumDataPages; signal->theData[6] = dbsiPtr.p->pdxDataPage[0]; signal->theData[7] = dbsiPtr.p->pdxFilePage; sendSignal(NDBFS_REF, GSN_FSREADREQ, signal, 8, JBA); }//Dbtup::rfrReadNextUndoSegment() void Dbtup::xlcGetNextRecordLab(Signal* signal, DiskBufferSegmentInfoPtr dbsiPtr, LocalLogInfoPtr lliPtr) { Uint32 loopCount = 0; /* ---------------------------------------------------------------------- */ /* EXECUTE A NEW SET OF UNDO LOG RECORDS. */ /* ---------------------------------------------------------------------- */ XlcStruct xlcStruct; xlcStruct.LliPtr = lliPtr; xlcStruct.DbsiPtr = dbsiPtr; do { ljam(); loopCount++; if (loopCount == 20) { ljam(); signal->theData[0] = ZCONT_EXECUTE_LC; signal->theData[1] = xlcStruct.LliPtr.i; sendSignal(cownref, GSN_CONTINUEB, signal, 2, JBB); return; }//if if (xlcStruct.LliPtr.p->lliPrevRecordId == 0) { ljam(); closeExecUndoLogLab(signal, xlcStruct.LliPtr); return; }//if xlcStruct.PageId = xlcStruct.LliPtr.p->lliPrevRecordId >> ZUNDO_RECORD_ID_PAGE_INDEX; xlcStruct.PageIndex = xlcStruct.LliPtr.p->lliPrevRecordId & ZUNDO_RECORD_ID_PAGE_INDEX_MASK; if (xlcStruct.PageId < xlcStruct.DbsiPtr.p->pdxFilePage) { ljam(); readExecUndoLogLab(signal, xlcStruct.DbsiPtr, xlcStruct.LliPtr); return; }//if ndbrequire((xlcStruct.PageId - xlcStruct.DbsiPtr.p->pdxFilePage) < 16); xlcStruct.UPPtr.i = xlcStruct.DbsiPtr.p->pdxDataPage[xlcStruct.PageId - xlcStruct.DbsiPtr.p->pdxFilePage]; ptrCheckGuard(xlcStruct.UPPtr, cnoOfUndoPage, undoPage); xlcGetLogHeader(xlcStruct); getFragmentrec(xlcStruct.FragPtr, xlcStruct.FragId, xlcStruct.TabPtr.p); if (xlcStruct.FragPtr.i == RNIL) { ljam(); continue; }//if if (xlcStruct.FragPtr.p->fragStatus != SYSTEM_RESTART) { ljam(); continue; }//if ndbrequire(xlcStruct.LogRecordType < ZNO_CHECKPOINT_RECORDS); cSrUndoRecords[xlcStruct.LogRecordType]++; switch (xlcStruct.LogRecordType) { case ZLCPR_TYPE_INSERT_TH: ljam(); xlcInsertTh(xlcStruct); break; case ZLCPR_TYPE_DELETE_TH: ljam(); xlcDeleteTh(xlcStruct); break; case ZLCPR_TYPE_UPDATE_TH: ljam(); xlcUpdateTh(xlcStruct); break; case ZLCPR_TYPE_INSERT_TH_NO_DATA: ljam(); xlcInsertTh(xlcStruct); break; case ZLCPR_ABORT_UPDATE: ljam(); xlcAbortUpdate(signal, xlcStruct); break; case ZLCPR_ABORT_INSERT: ljam(); xlcAbortInsert(signal, xlcStruct); break; case ZTABLE_DESCRIPTOR: ljam(); xlcTableDescriptor(xlcStruct); if (xlcStruct.LliPtr.p->lliNumFragments == 0) { ljam(); closeExecUndoLogLab(signal, xlcStruct.LliPtr); return; }//if break; case ZLCPR_UNDO_LOG_PAGE_HEADER: ljam(); xlcUndoLogPageHeader(xlcStruct); break; case ZINDICATE_NO_OP_ACTIVE: ljam(); xlcIndicateNoOpActive(xlcStruct); break; case ZLCPR_TYPE_UPDATE_GCI: ljam(); xlcUpdateGCI(xlcStruct); break; default: ndbrequire(false); break; }//switch } while (1); }//Dbtup::xlcGetNextRecordLab() /* ---------------------------------------------------------------- */ /* ----------------- XLC_GET_LOG_HEADER ---------------------- */ /* ---------------------------------------------------------------- */ void Dbtup::xlcGetLogHeader(XlcStruct& xlcStruct) { Uint32 pIndex = xlcStruct.PageIndex; Uint32 fragId; Uint32 tableId; Uint32 prevId; if ((pIndex + 4) < ZWORDS_ON_PAGE) { UndoPage* const regUndoPagePtr = xlcStruct.UPPtr.p; ljam(); xlcStruct.LogRecordType = regUndoPagePtr->undoPageWord[pIndex]; prevId = regUndoPagePtr->undoPageWord[pIndex + 1]; tableId = regUndoPagePtr->undoPageWord[pIndex + 2]; fragId = regUndoPagePtr->undoPageWord[pIndex + 3]; xlcStruct.PageIndex = pIndex + 4; } else { ljam(); xlcStruct.LogRecordType = xlcGetLogWord(xlcStruct); prevId = xlcGetLogWord(xlcStruct); tableId = xlcGetLogWord(xlcStruct); fragId = xlcGetLogWord(xlcStruct); }//if xlcStruct.LliPtr.p->lliPrevRecordId = prevId; xlcStruct.FragId = fragId; xlcStruct.TabPtr.i = tableId; ptrCheckGuard(xlcStruct.TabPtr, cnoOfTablerec, tablerec); }//Dbtup::xlcGetLogHeader() /* ------------------------------------------------------------------- */ /* ---------------------- XLC_GET_LOG_WORD --------------------------- */ /* ------------------------------------------------------------------- */ Uint32 Dbtup::xlcGetLogWord(XlcStruct& xlcStruct) { Uint32 pIndex = xlcStruct.PageIndex; ndbrequire(xlcStruct.UPPtr.p != NULL); ndbrequire(pIndex < ZWORDS_ON_PAGE); Uint32 logWord = xlcStruct.UPPtr.p->undoPageWord[pIndex]; pIndex++; xlcStruct.PageIndex = pIndex; if (pIndex == ZWORDS_ON_PAGE) { ljam(); xlcStruct.PageIndex = ZUNDO_PAGE_HEADER_SIZE; xlcStruct.PageId++; if ((xlcStruct.PageId - xlcStruct.DbsiPtr.p->pdxFilePage) >= (2 * ZUB_SEGMENT_SIZE)) { ljam(); xlcStruct.UPPtr.i = RNIL; ptrNull(xlcStruct.UPPtr); } else { ljam(); Uint32 index = xlcStruct.PageId - xlcStruct.DbsiPtr.p->pdxFilePage; ndbrequire(index < 16); xlcStruct.UPPtr.i = xlcStruct.DbsiPtr.p->pdxDataPage[index]; ptrCheckGuard(xlcStruct.UPPtr, cnoOfUndoPage, undoPage); }//if }//if return logWord; }//Dbtup::xlcGetLogWord() /****************************************************/ /* INSERT A TUPLE HEADER THE DATA IS THE TUPLE DATA */ /****************************************************/ void Dbtup::xlcInsertTh(XlcStruct& xlcStruct) { PagePtr pagePtr; Fragrecord* const regFragPtr = xlcStruct.FragPtr.p; Tablerec* const regTabPtr = xlcStruct.TabPtr.p; Uint32 fragPageId = xlcGetLogWord(xlcStruct); Uint32 pageIndex = xlcGetLogWord(xlcStruct); ndbrequire((pageIndex & 1) == 0); pagePtr.i = getRealpid(regFragPtr, fragPageId); ptrCheckGuard(pagePtr, cnoOfPage, page); Uint32 pageOffset; getThAtPageSr(pagePtr.p, pageOffset); ndbrequire(pageOffset == (ZPAGE_HEADER_SIZE + (regTabPtr->tupheadsize * (pageIndex >> 1)))); if (xlcStruct.LogRecordType == ZLCPR_TYPE_INSERT_TH) { ljam(); xlcCopyData(xlcStruct, pageOffset, regTabPtr->tupheadsize, pagePtr); } else { ndbrequire(xlcStruct.LogRecordType == ZLCPR_TYPE_INSERT_TH_NO_DATA); ljam(); }//if /* ----------------------------------------*/ /* INDICATE THAT NO OPERATIONS ACTIVE */ /* ----------------------------------------*/ ndbrequire(pageOffset < ZWORDS_ON_PAGE); pagePtr.p->pageWord[pageOffset] = RNIL; }//Dbtup::xlcInsertTh() /**********************************************/ /* DELETE A TUPLE HEADER - NO ADDITIONAL DATA */ /**********************************************/ void Dbtup::xlcDeleteTh(XlcStruct& xlcStruct) { PagePtr pagePtr; Fragrecord* const regFragPtr = xlcStruct.FragPtr.p; Tablerec* const regTabPtr = xlcStruct.TabPtr.p; Uint32 fragPageId = xlcGetLogWord(xlcStruct); Uint32 pageIndex = xlcGetLogWord(xlcStruct); ndbrequire((pageIndex & 1) == 0); pagePtr.i = getRealpid(regFragPtr, fragPageId); ptrCheckGuard(pagePtr, cnoOfPage, page); Uint32 pageOffset = ZPAGE_HEADER_SIZE + (regTabPtr->tupheadsize * (pageIndex >> 1)); freeThSr(regTabPtr, pagePtr.p, pageOffset); }//Dbtup::xlcDeleteTh() /*****************************************************/ /* UPDATE A TUPLE HEADER, THE DATA IS THE TUPLE DATA */ /*****************************************************/ void Dbtup::xlcUpdateTh(XlcStruct& xlcStruct) { PagePtr pagePtr; Fragrecord* const regFragPtr = xlcStruct.FragPtr.p; Tablerec* const regTabPtr = xlcStruct.TabPtr.p; Uint32 fragPageId = xlcGetLogWord(xlcStruct); Uint32 pageIndex = xlcGetLogWord(xlcStruct); ndbrequire((pageIndex & 1) == 0); pagePtr.i = getRealpid(regFragPtr, fragPageId); ptrCheckGuard(pagePtr, cnoOfPage, page); Uint32 pageOffset = ZPAGE_HEADER_SIZE + (regTabPtr->tupheadsize * (pageIndex >> 1)); xlcCopyData(xlcStruct, pageOffset, regTabPtr->tupheadsize, pagePtr); /* ----------------------------------------*/ /* INDICATE THAT NO OPERATIONS ACTIVE */ /* ----------------------------------------*/ ndbrequire(pageOffset < ZWORDS_ON_PAGE); pagePtr.p->pageWord[pageOffset] = RNIL; }//Dbtup::xlcUpdateTh() /**************************************************/ /* ABORT AN INSERT OPERATION - NO ADDITIONAL DATA */ /**************************************************/ void Dbtup::xlcAbortInsert(Signal* signal, XlcStruct& xlcStruct) { PagePtr pagePtr; Fragrecord* const regFragPtr = xlcStruct.FragPtr.p; Tablerec* const regTabPtr = xlcStruct.TabPtr.p; Uint32 fragPageId = xlcGetLogWord(xlcStruct); Uint32 pageIndex = xlcGetLogWord(xlcStruct); ndbrequire((pageIndex & 1) == 0); pagePtr.i = getRealpid(regFragPtr, fragPageId); ptrCheckGuard(pagePtr, cnoOfPage, page); Uint32 pageOffset = ZPAGE_HEADER_SIZE + (regTabPtr->tupheadsize * (pageIndex >> 1)); freeTh(regFragPtr, regTabPtr, signal, pagePtr.p, pageOffset); }//Dbtup::xlcAbortInsert() /*****************************************************/ /* COPY DATA FROM COPY TUPLE TO ORIGINAL TUPLE */ /*****************************************************/ void Dbtup::xlcAbortUpdate(Signal* signal, XlcStruct& xlcStruct) { PagePtr pagePtr; Fragrecord* const regFragPtr = xlcStruct.FragPtr.p; Tablerec* const regTabPtr = xlcStruct.TabPtr.p; Uint32 tuple_size = regTabPtr->tupheadsize; Uint32 fragPageIdC = xlcGetLogWord(xlcStruct); Uint32 pageIndexC = xlcGetLogWord(xlcStruct); ndbrequire((pageIndexC & 1) == 0); Uint32 TdestPageId = getRealpid(regFragPtr, fragPageIdC); Uint32 TcmDestIndex = ZPAGE_HEADER_SIZE + (tuple_size * (pageIndexC >> 1)); Uint32 fragPageId = xlcGetLogWord(xlcStruct); Uint32 pageIndex = xlcGetLogWord(xlcStruct); ndbrequire((pageIndex & 1) == 0); Uint32 TsourcePageId = getRealpid(regFragPtr, fragPageId); Uint32 TcmSourceIndex = ZPAGE_HEADER_SIZE + (tuple_size * (pageIndex >> 1)); Uint32 end_source = tuple_size + TcmSourceIndex; Uint32 end_dest = tuple_size + TcmDestIndex; void* Tdestination = (void*)&page[TdestPageId].pageWord[TcmDestIndex + 1]; const void* Tsource = (void*)&page[TsourcePageId].pageWord[TcmSourceIndex + 1]; ndbrequire(TsourcePageId < cnoOfPage && TdestPageId < cnoOfPage && end_source <= ZWORDS_ON_PAGE && end_dest <= ZWORDS_ON_PAGE); MEMCOPY_NO_WORDS(Tdestination, Tsource, (tuple_size - 1)); pagePtr.i = TsourcePageId; ptrAss(pagePtr, page); freeTh(regFragPtr, regTabPtr, signal, pagePtr.p, TcmSourceIndex); pagePtr.i = TdestPageId; ptrAss(pagePtr, page); pagePtr.p->pageWord[TcmDestIndex] = RNIL; }//Dbtup::xlcAbortUpdate() /*****************************/ /* RESTORE UPDATED GCI VALUE */ /*****************************/ void Dbtup::xlcUpdateGCI(XlcStruct& xlcStruct) { PagePtr pagePtr; Fragrecord* const regFragPtr = xlcStruct.FragPtr.p; Tablerec* const regTabPtr = xlcStruct.TabPtr.p; Uint32 fragPageId = xlcGetLogWord(xlcStruct); Uint32 pageIndex = xlcGetLogWord(xlcStruct); Uint32 restoredGCI = xlcGetLogWord(xlcStruct); ndbrequire((pageIndex & 1) == 0); pagePtr.i = getRealpid(regFragPtr, fragPageId); ptrCheckGuard(pagePtr, cnoOfPage, page); Uint32 pageOffset = ZPAGE_HEADER_SIZE + (regTabPtr->tupheadsize * (pageIndex >> 1)); Uint32 gciOffset = pageOffset + regTabPtr->tupGCPIndex; ndbrequire((gciOffset < ZWORDS_ON_PAGE) && (regTabPtr->tupGCPIndex < regTabPtr->tupheadsize)); pagePtr.p->pageWord[gciOffset] = restoredGCI; }//Dbtup::xlcUpdateGCI() /*****************************************************/ /* READ TABLE DESCRIPTOR FROM UNDO LOG */ /*****************************************************/ void Dbtup::xlcTableDescriptor(XlcStruct& xlcStruct) { xlcStruct.LliPtr.p->lliNumFragments--; xlcStruct.FragPtr.p->fragStatus = ACTIVE; }//Dbtup::xlcTableDescriptor() /********************************************************/ /* UPDATE PAGE STATE AND NEXT POINTER IN PAGE */ /********************************************************/ void Dbtup::xlcUndoLogPageHeader(XlcStruct& xlcStruct) { Fragrecord* const regFragPtr = xlcStruct.FragPtr.p; PagePtr xlcPagep; Uint32 fragPageId = xlcGetLogWord(xlcStruct); xlcPagep.i = getRealpid(regFragPtr, fragPageId); ptrCheckGuard(xlcPagep, cnoOfPage, page); Uint32 logWord = xlcGetLogWord(xlcStruct); ndbrequire(logWord != 0); ndbrequire(logWord <= ZAC_MM_FREE_COPY); xlcPagep.p->pageWord[ZPAGE_STATE_POS] = logWord; xlcPagep.p->pageWord[ZPAGE_NEXT_POS] = xlcGetLogWord(xlcStruct); }//Dbtup::xlcUndoLogPageHeader() /********************************************************/ /* INDICATE THAT NO OPERATIONS ACTIVE */ /********************************************************/ void Dbtup::xlcIndicateNoOpActive(XlcStruct& xlcStruct) { PagePtr pagePtr; Fragrecord* const regFragPtr = xlcStruct.FragPtr.p; Tablerec* const regTabPtr = xlcStruct.TabPtr.p; Uint32 fragPageId = xlcGetLogWord(xlcStruct); Uint32 pageIndex = xlcGetLogWord(xlcStruct); ndbrequire((pageIndex & 1) == 0); pagePtr.i = getRealpid(regFragPtr, fragPageId); ptrCheckGuard(pagePtr, cnoOfPage, page); Uint32 pageOffset = ZPAGE_HEADER_SIZE + (regTabPtr->tupheadsize * (pageIndex >> 1)); /* ----------------------------------------*/ /* INDICATE THAT NO OPERATIONS ACTIVE */ /* ----------------------------------------*/ ndbrequire(pageOffset < ZWORDS_ON_PAGE); pagePtr.p->pageWord[pageOffset] = RNIL; }//Dbtup::xlcIndicateNoOpActive() /********************************************************/ /* THIS IS THE COMMON ROUTINE TO COPY DATA FROM THE */ /* UNDO BUFFER TO THE DATA PAGES. IT USES THE */ /* XLC_REQUEST_SEGMENT SUB TO GET MORE DATA WHEN NEEDED */ /********************************************************/ void Dbtup::xlcCopyData(XlcStruct& xlcStruct, Uint32 pageOffset, Uint32 noOfWords, PagePtr pagePtr) { ndbrequire((pageOffset + noOfWords - 1) < ZWORDS_ON_PAGE); for (Uint32 i = 1; i < noOfWords; i++) { ljam(); pagePtr.p->pageWord[pageOffset + i] = xlcGetLogWord(xlcStruct); }//for }//Dbtup::xlcCopyData() void Dbtup::allocRestartUndoBufferSegment(Signal* signal, DiskBufferSegmentInfoPtr& dbsiPtr, LocalLogInfoPtr lliPtr) { UndoPagePtr undoPagePtr; ndbrequire(cfirstfreeUndoSeg != RNIL); if (cnoFreeUndoSeg == ZMIN_PAGE_LIMIT_TUP_COMMITREQ) { EXECUTE_DIRECT(DBLQH, GSN_TUP_COM_BLOCK, signal, 1); ljamEntry(); }//if cnoFreeUndoSeg--; ndbrequire(cnoFreeUndoSeg >= 0); undoPagePtr.i = cfirstfreeUndoSeg; ptrCheckGuard(undoPagePtr, cnoOfUndoPage, undoPage); cfirstfreeUndoSeg = undoPagePtr.p->undoPageWord[ZPAGE_NEXT_POS]; undoPagePtr.p->undoPageWord[ZPAGE_NEXT_POS] = RNIL; seizeDiskBufferSegmentRecord(dbsiPtr); dbsiPtr.p->pdxBuffertype = UNDO_RESTART_PAGES; dbsiPtr.p->pdxUndoBufferSet[0] = undoPagePtr.i; Uint32 i; for (i = 0; i < ZUB_SEGMENT_SIZE; i++) { dbsiPtr.p->pdxDataPage[i] = undoPagePtr.i + i; }//for ndbrequire(cfirstfreeUndoSeg != RNIL); if (cnoFreeUndoSeg == ZMIN_PAGE_LIMIT_TUP_COMMITREQ) { EXECUTE_DIRECT(DBLQH, GSN_TUP_COM_BLOCK, signal, 1); ljamEntry(); }//if cnoFreeUndoSeg--; ndbrequire(cnoFreeUndoSeg >= 0); undoPagePtr.i = cfirstfreeUndoSeg; ptrCheckGuard(undoPagePtr, cnoOfUndoPage, undoPage); cfirstfreeUndoSeg = undoPagePtr.p->undoPageWord[ZPAGE_NEXT_POS]; undoPagePtr.p->undoPageWord[ZPAGE_NEXT_POS] = RNIL; dbsiPtr.p->pdxUndoBufferSet[1] = undoPagePtr.i; // lliPtr.p->lliUndoPage = undoPagePtr.i; for (i = ZUB_SEGMENT_SIZE; i < (2 * ZUB_SEGMENT_SIZE); i++) { dbsiPtr.p->pdxDataPage[i] = undoPagePtr.i + (i - ZUB_SEGMENT_SIZE); }//for return; }//Dbtup::allocRestartUndoBufferSegment()