diff options
author | unknown <tulin@dl145b.mysql.com> | 2005-05-04 15:13:00 +0200 |
---|---|---|
committer | unknown <tulin@dl145b.mysql.com> | 2005-05-04 15:13:00 +0200 |
commit | f81661ba71b026e5e8dc635bc449c132609b6316 (patch) | |
tree | 6e93257a24ad11252e1e751ae829c2cdce6c3b01 /ndb/src/kernel | |
parent | 3d66af2ef364f076594cfb6cad316fabee6888ea (diff) | |
download | mariadb-git-f81661ba71b026e5e8dc635bc449c132609b6316.tar.gz |
testSuperPool.cpp:
Rename: ndb/src/kernel/vm/testSuperPool.cpp -> storage/ndb/src/kernel/vm/testSuperPool.cpp
SuperPool.hpp:
Rename: ndb/src/kernel/vm/SuperPool.hpp -> storage/ndb/src/kernel/vm/SuperPool.hpp
SuperPool.cpp:
Rename: ndb/src/kernel/vm/SuperPool.cpp -> storage/ndb/src/kernel/vm/SuperPool.cpp
DbtupScan.cpp:
Rename: ndb/src/kernel/blocks/dbtup/DbtupScan.cpp -> storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp
storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp:
Rename: ndb/src/kernel/blocks/dbtup/DbtupScan.cpp -> storage/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp
storage/ndb/src/kernel/vm/SuperPool.cpp:
Rename: ndb/src/kernel/vm/SuperPool.cpp -> storage/ndb/src/kernel/vm/SuperPool.cpp
storage/ndb/src/kernel/vm/SuperPool.hpp:
Rename: ndb/src/kernel/vm/SuperPool.hpp -> storage/ndb/src/kernel/vm/SuperPool.hpp
storage/ndb/src/kernel/vm/testSuperPool.cpp:
Rename: ndb/src/kernel/vm/testSuperPool.cpp -> storage/ndb/src/kernel/vm/testSuperPool.cpp
Diffstat (limited to 'ndb/src/kernel')
-rw-r--r-- | ndb/src/kernel/blocks/dbtup/DbtupScan.cpp | 315 | ||||
-rw-r--r-- | ndb/src/kernel/vm/SuperPool.cpp | 442 | ||||
-rw-r--r-- | ndb/src/kernel/vm/SuperPool.hpp | 561 | ||||
-rw-r--r-- | ndb/src/kernel/vm/testSuperPool.cpp | 220 |
4 files changed, 0 insertions, 1538 deletions
diff --git a/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp b/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp deleted file mode 100644 index 396404faa8c..00000000000 --- a/ndb/src/kernel/blocks/dbtup/DbtupScan.cpp +++ /dev/null @@ -1,315 +0,0 @@ -/* 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 <signaldata/AccScan.hpp> -#include <signaldata/NextScan.hpp> - -#undef jam -#undef jamEntry -#define jam() { jamLine(32000 + __LINE__); } -#define jamEntry() { jamEntryLine(32000 + __LINE__); } - -void -Dbtup::execACC_SCANREQ(Signal* signal) -{ - jamEntry(); - const AccScanReq reqCopy = *(const AccScanReq*)signal->getDataPtr(); - const AccScanReq* const req = &reqCopy; - ScanOpPtr scanPtr; - scanPtr.i = RNIL; - do { - // find table and fragments - TablerecPtr tablePtr; - tablePtr.i = req->tableId; - ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec); - FragrecordPtr fragPtr[2]; - Uint32 fragId = req->fragmentNo << 1; - fragPtr[0].i = fragPtr[1].i = RNIL; - getFragmentrec(fragPtr[0], fragId | 0, tablePtr.p); - getFragmentrec(fragPtr[1], fragId | 1, tablePtr.p); - ndbrequire(fragPtr[0].i != RNIL && fragPtr[1].i != RNIL); - Fragrecord& frag = *fragPtr[0].p; - // seize from pool and link to per-fragment list - if (! frag.m_scanList.seize(scanPtr)) { - jam(); - break; - } - new (scanPtr.p) ScanOp(); - ScanOp& scan = *scanPtr.p; - scan.m_state = ScanOp::First; - scan.m_userPtr = req->senderData; - scan.m_userRef = req->senderRef; - scan.m_tableId = tablePtr.i; - scan.m_fragId = frag.fragmentId; - scan.m_fragPtrI[0] = fragPtr[0].i; - scan.m_fragPtrI[1] = fragPtr[1].i; - scan.m_transId1 = req->transId1; - scan.m_transId2 = req->transId2; - // conf - AccScanConf* const conf = (AccScanConf*)signal->getDataPtrSend(); - conf->scanPtr = req->senderData; - conf->accPtr = scanPtr.i; - conf->flag = AccScanConf::ZNOT_EMPTY_FRAGMENT; - sendSignal(req->senderRef, GSN_ACC_SCANCONF, signal, - AccScanConf::SignalLength, JBB); - return; - } while (0); - if (scanPtr.i != RNIL) { - jam(); - releaseScanOp(scanPtr); - } - // LQH does not handle REF - signal->theData[0] = 0x313; - sendSignal(req->senderRef, GSN_ACC_SCANREF, signal, 1, JBB); -} - -void -Dbtup::execNEXT_SCANREQ(Signal* signal) -{ - jamEntry(); - const NextScanReq reqCopy = *(const NextScanReq*)signal->getDataPtr(); - const NextScanReq* const req = &reqCopy; - ScanOpPtr scanPtr; - c_scanOpPool.getPtr(scanPtr, req->accPtr); - ScanOp& scan = *scanPtr.p; - FragrecordPtr fragPtr; - fragPtr.i = scan.m_fragPtrI[0]; - ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); - Fragrecord& frag = *fragPtr.p; - switch (req->scanFlag) { - case NextScanReq::ZSCAN_NEXT: - jam(); - break; - case NextScanReq::ZSCAN_NEXT_COMMIT: - jam(); - break; - case NextScanReq::ZSCAN_COMMIT: - jam(); - { - NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend(); - conf->scanPtr = scan.m_userPtr; - unsigned signalLength = 1; - sendSignal(scanPtr.p->m_userRef, GSN_NEXT_SCANCONF, - signal, signalLength, JBB); - return; - } - break; - case NextScanReq::ZSCAN_CLOSE: - jam(); - scanClose(signal, scanPtr); - return; - case NextScanReq::ZSCAN_NEXT_ABORT: - jam(); - default: - jam(); - ndbrequire(false); - break; - } - // start looking for next scan result - AccCheckScan* checkReq = (AccCheckScan*)signal->getDataPtrSend(); - checkReq->accPtr = scanPtr.i; - checkReq->checkLcpStop = AccCheckScan::ZNOT_CHECK_LCP_STOP; - EXECUTE_DIRECT(DBTUP, GSN_ACC_CHECK_SCAN, signal, AccCheckScan::SignalLength); - jamEntry(); -} - -void -Dbtup::execACC_CHECK_SCAN(Signal* signal) -{ - jamEntry(); - const AccCheckScan reqCopy = *(const AccCheckScan*)signal->getDataPtr(); - const AccCheckScan* const req = &reqCopy; - ScanOpPtr scanPtr; - c_scanOpPool.getPtr(scanPtr, req->accPtr); - ScanOp& scan = *scanPtr.p; - FragrecordPtr fragPtr; - fragPtr.i = scan.m_fragPtrI[0]; - ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); - Fragrecord& frag = *fragPtr.p; - if (req->checkLcpStop == AccCheckScan::ZCHECK_LCP_STOP) { - jam(); - signal->theData[0] = scan.m_userPtr; - signal->theData[1] = true; - EXECUTE_DIRECT(DBLQH, GSN_CHECK_LCP_STOP, signal, 2); - jamEntry(); - return; - } - if (scan.m_state == ScanOp::First) { - jam(); - scanFirst(signal, scanPtr); - } - if (scan.m_state == ScanOp::Next) { - jam(); - scanNext(signal, scanPtr); - } - if (scan.m_state == ScanOp::Locked) { - jam(); - const PagePos& pos = scan.m_scanPos; - NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend(); - conf->scanPtr = scan.m_userPtr; - conf->accOperationPtr = (Uint32)-1; // no lock returned - conf->fragId = frag.fragmentId | pos.m_fragBit; - conf->localKey[0] = (pos.m_pageId << MAX_TUPLES_BITS) | - (pos.m_tupleNo << 1); - conf->localKey[1] = 0; - conf->localKeyLength = 1; - unsigned signalLength = 6; - Uint32 blockNo = refToBlock(scan.m_userRef); - EXECUTE_DIRECT(blockNo, GSN_NEXT_SCANCONF, signal, signalLength); - jamEntry(); - // next time look for next entry - scan.m_state = ScanOp::Next; - return; - } - if (scan.m_state == ScanOp::Last || - scan.m_state == ScanOp::Invalid) { - jam(); - NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend(); - conf->scanPtr = scan.m_userPtr; - conf->accOperationPtr = RNIL; - conf->fragId = RNIL; - unsigned signalLength = 3; - sendSignal(scanPtr.p->m_userRef, GSN_NEXT_SCANCONF, - signal, signalLength, JBB); - return; - } - ndbrequire(false); -} - -void -Dbtup::scanFirst(Signal* signal, ScanOpPtr scanPtr) -{ - ScanOp& scan = *scanPtr.p; - // set to first fragment, first page, first tuple - PagePos& pos = scan.m_scanPos; - pos.m_fragId = scan.m_fragId; - pos.m_fragBit = 0; - pos.m_pageId = 0; - pos.m_tupleNo = 0; - // just before - pos.m_match = false; - // let scanNext() do the work - scan.m_state = ScanOp::Next; -} - -// TODO optimize this + index build -void -Dbtup::scanNext(Signal* signal, ScanOpPtr scanPtr) -{ - ScanOp& scan = *scanPtr.p; - PagePos& pos = scan.m_scanPos; - TablerecPtr tablePtr; - tablePtr.i = scan.m_tableId; - ptrCheckGuard(tablePtr, cnoOfTablerec, tablerec); - while (true) { - // TODO time-slice here after X loops - jam(); - // get fragment - if (pos.m_fragBit == 2) { - jam(); - scan.m_state = ScanOp::Last; - break; - } - ndbrequire(pos.m_fragBit <= 1); - FragrecordPtr fragPtr; - fragPtr.i = scan.m_fragPtrI[pos.m_fragBit]; - ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); - Fragrecord& frag = *fragPtr.p; - // get page - PagePtr pagePtr; - if (pos.m_pageId >= frag.noOfPages) { - jam(); - pos.m_fragBit++; - pos.m_pageId = 0; - pos.m_tupleNo = 0; - pos.m_match = false; - continue; - } - Uint32 realPageId = getRealpid(fragPtr.p, pos.m_pageId); - pagePtr.i = realPageId; - ptrCheckGuard(pagePtr, cnoOfPage, page); - const Uint32 pageState = pagePtr.p->pageWord[ZPAGE_STATE_POS]; - if (pageState != ZTH_MM_FREE && - pageState != ZTH_MM_FULL) { - jam(); - pos.m_pageId++; - pos.m_tupleNo = 0; - pos.m_match = false; - continue; - } - // get next tuple - if (pos.m_match) - pos.m_tupleNo++; - pos.m_match = true; - const Uint32 tupheadsize = tablePtr.p->tupheadsize; - Uint32 pageOffset = ZPAGE_HEADER_SIZE + pos.m_tupleNo * tupheadsize; - if (pageOffset + tupheadsize > ZWORDS_ON_PAGE) { - jam(); - pos.m_pageId++; - pos.m_tupleNo = 0; - pos.m_match = false; - continue; - } - // skip over free tuple - bool isFree = false; - if (pageState == ZTH_MM_FREE) { - jam(); - if ((pagePtr.p->pageWord[pageOffset] >> 16) == tupheadsize) { - Uint32 nextTuple = pagePtr.p->pageWord[ZFREELIST_HEADER_POS] >> 16; - while (nextTuple != 0) { - jam(); - if (nextTuple == pageOffset) { - jam(); - isFree = true; - break; - } - nextTuple = pagePtr.p->pageWord[nextTuple] & 0xffff; - } - } - } - if (isFree) { - jam(); - continue; - } - // TODO check for operation and return latest in own tx - scan.m_state = ScanOp::Locked; - break; - } -} - -void -Dbtup::scanClose(Signal* signal, ScanOpPtr scanPtr) -{ - NextScanConf* const conf = (NextScanConf*)signal->getDataPtrSend(); - conf->scanPtr = scanPtr.p->m_userPtr; - conf->accOperationPtr = RNIL; - conf->fragId = RNIL; - unsigned signalLength = 3; - sendSignal(scanPtr.p->m_userRef, GSN_NEXT_SCANCONF, - signal, signalLength, JBB); - releaseScanOp(scanPtr); -} - -void -Dbtup::releaseScanOp(ScanOpPtr& scanPtr) -{ - FragrecordPtr fragPtr; - fragPtr.i = scanPtr.p->m_fragPtrI[0]; - ptrCheckGuard(fragPtr, cnoOfFragrec, fragrecord); - fragPtr.p->m_scanList.release(scanPtr); -} diff --git a/ndb/src/kernel/vm/SuperPool.cpp b/ndb/src/kernel/vm/SuperPool.cpp deleted file mode 100644 index 65e5dd99629..00000000000 --- a/ndb/src/kernel/vm/SuperPool.cpp +++ /dev/null @@ -1,442 +0,0 @@ -/* 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 */ - -#include <ndb_global.h> -#include "SuperPool.hpp" - -// SuperPool - -SuperPool::SuperPool(Uint32 pageSize, Uint32 pageBits) : - m_pageSize(SP_ALIGN_SIZE(pageSize, SP_ALIGN)), - m_pageBits(pageBits), - m_memRoot(0), - m_pageEnt(0), - m_typeCheck(0), - m_typeSeq(0), - m_pageList(), - m_totalSize(0), - m_initSize(0), - m_incrSize(0), - m_maxSize(0) -{ - assert(5 <= pageBits <= 30); -} - -bool -SuperPool::init() -{ - return true; -} - -SuperPool::~SuperPool() -{ -} - -SuperPool::PageEnt::PageEnt() : - m_pageType(0), - m_freeRecI(RNIL), - m_useCount(0), - m_nextPageI(RNIL), - m_prevPageI(RNIL) -{ -} - -SuperPool::PageList::PageList() : - m_headPageI(RNIL), - m_tailPageI(RNIL), - m_pageCount(0) -{ -} - -SuperPool::PageList::PageList(PtrI pageI) : - m_headPageI(pageI), - m_tailPageI(pageI), - m_pageCount(1) -{ -} - -SuperPool::RecInfo::RecInfo(Uint32 recType, Uint32 recSize) : - m_recType(recType), - m_recSize(recSize), - m_maxUseCount(0), - m_currPageI(RNIL), - m_currFreeRecI(RNIL), - m_currUseCount(0), - m_totalUseCount(0), - m_totalRecCount(0), - m_freeList(), - m_activeList(), - m_fullList() -{ -} - -SuperPool::PtrI -SuperPool::getPageI(void* pageP) -{ - const Uint32 pageSize = m_pageSize; - const Uint32 pageBits = m_pageBits; - const Uint32 recBits = 32 - pageBits; - void* const memRoot = m_memRoot; - assert(pageP == SP_ALIGN_PTR(pageP, memRoot, pageSize)); - my_ptrdiff_t ipL = ((Uint8*)pageP - (Uint8*)memRoot) / pageSize; - Int32 ip = (Int32)ipL; - Int32 lim = 1 << (pageBits - 1); - assert(ip == ipL && -lim <= ip && ip < lim && ip != -1); - PtrI pageI = ip << recBits; - assert(pageP == getPageP(pageI)); - return pageI; -} - -void -SuperPool::movePages(PageList& pl1, PageList& pl2) -{ - const Uint32 recBits = 32 - m_pageBits; - if (pl1.m_pageCount != 0) { - if (pl2.m_pageCount != 0) { - PtrI pageI1 = pl1.m_tailPageI; - PtrI pageI2 = pl2.m_headPageI; - PageEnt& pe1 = getPageEnt(pageI1); - PageEnt& pe2 = getPageEnt(pageI2); - pe1.m_nextPageI = pageI2; - pe2.m_prevPageI = pageI1; - pl1.m_pageCount += pl2.m_pageCount; - } - } else { - pl1 = pl2; - } - pl2.m_headPageI = pl2.m_tailPageI = RNIL; - pl2.m_pageCount = 0; -} - -void -SuperPool::addHeadPage(PageList& pl, PtrI pageI) -{ - PageList pl2(pageI); - movePages(pl2, pl); - pl = pl2; -} - -void -SuperPool::addTailPage(PageList& pl, PtrI pageI) -{ - PageList pl2(pageI); - movePages(pl, pl2); -} - -void -SuperPool::removePage(PageList& pl, PtrI pageI) -{ - PageEnt& pe = getPageEnt(pageI); - PtrI pageI1 = pe.m_prevPageI; - PtrI pageI2 = pe.m_nextPageI; - if (pageI1 != RNIL) { - PageEnt& pe1 = getPageEnt(pageI1); - pe1.m_nextPageI = pageI2; - if (pageI2 != RNIL) { - PageEnt& pe2 = getPageEnt(pageI2); - pe2.m_prevPageI = pageI1; - } else { - pl.m_tailPageI = pageI1; - } - } else { - if (pageI2 != RNIL) { - PageEnt& pe2 = getPageEnt(pageI2); - pe2.m_prevPageI = pageI1; - pl.m_headPageI = pageI2; - } else { - pl.m_headPageI = pl.m_tailPageI = RNIL; - } - } - pe.m_prevPageI = pe.m_nextPageI = RNIL; - assert(pl.m_pageCount != 0); - pl.m_pageCount--; -} - -void -SuperPool::setCurrPage(RecInfo& ri, PtrI newPageI) -{ - PtrI oldPageI = ri.m_currPageI; - if (oldPageI != RNIL) { - // copy from cache - PageEnt& pe = getPageEnt(oldPageI); - pe.m_freeRecI = ri.m_currFreeRecI; - pe.m_useCount = ri.m_currUseCount; - // add to right list according to "pp2" policy - if (pe.m_useCount == 0) { - pe.m_pageType = 0; - addHeadPage(m_pageList, oldPageI); - ri.m_totalRecCount -= ri.m_maxUseCount; - } else if (pe.m_useCount < ri.m_maxUseCount) { - addHeadPage(ri.m_activeList, oldPageI); - } else { - addHeadPage(ri.m_fullList, oldPageI); - } - } - if (newPageI != RNIL) { - PageEnt& pe = getPageEnt(newPageI); - // copy to cache - ri.m_currPageI = newPageI; - ri.m_currFreeRecI = pe.m_freeRecI; - ri.m_currUseCount = pe.m_useCount; - // remove from right list - if (pe.m_useCount == 0) { - removePage(ri.m_freeList, newPageI); - } else if (pe.m_useCount < ri.m_maxUseCount) { - removePage(ri.m_activeList, newPageI); - } else { - removePage(ri.m_fullList, newPageI); - } - } else { - ri.m_currPageI = RNIL; - ri.m_currFreeRecI = RNIL; - ri.m_currUseCount = 0; - } -} - -bool -SuperPool::getAvailPage(RecInfo& ri) -{ - PtrI pageI; - if ((pageI = ri.m_activeList.m_headPageI) != RNIL || - (pageI = ri.m_freeList.m_headPageI) != RNIL || - (pageI = getFreePage(ri)) != RNIL) { - setCurrPage(ri, pageI); - return true; - } - return false; -} - -SuperPool::PtrI -SuperPool::getFreePage(RecInfo& ri) -{ - PtrI pageI; - if (m_pageList.m_pageCount != 0) { - pageI = m_pageList.m_headPageI; - removePage(m_pageList, pageI); - } else { - pageI = getNewPage(); - if (pageI == RNIL) - return RNIL; - } - void* pageP = getPageP(pageI); - // set up free record list - Uint32 maxUseCount = ri.m_maxUseCount; - Uint32 recSize = ri.m_recSize; - void* recP = (Uint8*)pageP; - Uint32 irNext = 1; - while (irNext < maxUseCount) { - *(Uint32*)recP = pageI | irNext; - recP = (Uint8*)recP + recSize; - irNext++; - } - *(Uint32*)recP = RNIL; - // add to total record count - ri.m_totalRecCount += maxUseCount; - // set up new page entry - PageEnt& pe = getPageEnt(pageI); - new (&pe) PageEnt(); - pe.m_pageType = ri.m_recType; - pe.m_freeRecI = pageI | 0; - pe.m_useCount = 0; - // set type check bits - setCheckBits(pageI, ri.m_recType); - // add to record pool free list - addHeadPage(ri.m_freeList, pageI); - return pageI; -} - -void -SuperPool::setSizes(size_t initSize, size_t incrSize, size_t maxSize) -{ - const Uint32 pageSize = m_pageSize; - m_initSize = SP_ALIGN_SIZE(initSize, pageSize); - m_incrSize = SP_ALIGN_SIZE(incrSize, pageSize); - m_maxSize = SP_ALIGN_SIZE(maxSize, pageSize); -} - -void -SuperPool::verify(RecInfo& ri) -{ - PageList* plList[3] = { &ri.m_freeList, &ri.m_activeList, &ri.m_fullList }; - for (int i = 0; i < 3; i++) { - PageList& pl = *plList[i]; - unsigned count = 0; - PtrI pageI = pl.m_headPageI; - while (pageI != RNIL) { - PageEnt& pe = getPageEnt(pageI); - PtrI pageI1 = pe.m_prevPageI; - PtrI pageI2 = pe.m_nextPageI; - if (count == 0) { - assert(pageI1 == RNIL); - } else { - assert(pageI1 != RNIL); - PageEnt& pe1 = getPageEnt(pageI1); - assert(pe1.m_nextPageI == pageI); - if (pageI2 != RNIL) { - PageEnt& pe2 = getPageEnt(pageI2); - assert(pe2.m_prevPageI == pageI); - } - } - pageI = pageI2; - count++; - } - assert(pl.m_pageCount == count); - } -} - -// HeapPool - -HeapPool::HeapPool(Uint32 pageSize, Uint32 pageBits) : - SuperPool(pageSize, pageBits), - m_areaHead(), - m_currArea(&m_areaHead), - m_lastArea(&m_areaHead), - m_mallocPart(4) -{ -} - -bool -HeapPool::init() -{ - const Uint32 pageBits = m_pageBits; - if (! SuperPool::init()) - return false;; - // allocate page entry array - Uint32 peBytes = (1 << pageBits) * sizeof(PageEnt); - m_pageEnt = static_cast<PageEnt*>(malloc(peBytes)); - if (m_pageEnt == 0) - return false; - memset(m_pageEnt, 0, peBytes); - // allocate type check array - Uint32 tcWords = 1 << (pageBits - (5 - SP_CHECK_LOG2)); - m_typeCheck = static_cast<Uint32*>(malloc(tcWords << 2)); - if (m_typeCheck == 0) - return false; - memset(m_typeCheck, 0, tcWords << 2); - // allocate initial data - assert(m_totalSize == 0); - if (! allocMoreData(m_initSize)) - return false; - return true; -} - -HeapPool::~HeapPool() -{ - free(m_pageEnt); - free(m_typeCheck); - Area* ap; - while ((ap = m_areaHead.m_nextArea) != 0) { - m_areaHead.m_nextArea = ap->m_nextArea; - free(ap->m_memory); - free(ap); - } -} - -HeapPool::Area::Area() : - m_nextArea(0), - m_firstPageI(RNIL), - m_currPage(0), - m_numPages(0), - m_memory(0) -{ -} - -SuperPool::PtrI -HeapPool::getNewPage() -{ - const Uint32 pageSize = m_pageSize; - const Uint32 pageBits = m_pageBits; - const Uint32 recBits= 32 - pageBits; - Area* ap = m_currArea; - if (ap->m_currPage == ap->m_numPages) { - // area is used up - if (ap->m_nextArea == 0) { - // todo dynamic increase - assert(m_incrSize == 0); - return RNIL; - } - ap = m_currArea = ap->m_nextArea; - } - assert(ap->m_currPage < ap->m_numPages); - PtrI pageI = ap->m_firstPageI; - Int32 ip = (Int32)pageI >> recBits; - ip += ap->m_currPage; - pageI = ip << recBits; - ap->m_currPage++; - return pageI; -} - -bool -HeapPool::allocMoreData(size_t size) -{ - const Uint32 pageSize = m_pageSize; - const Uint32 pageBits = m_pageBits; - const Uint32 recBits = 32 - pageBits; - const Uint32 incrSize = m_incrSize; - const Uint32 incrPages = incrSize / pageSize; - const Uint32 mallocPart = m_mallocPart; - size = SP_ALIGN_SIZE(size, pageSize); - if (incrSize != 0) - size = SP_ALIGN_SIZE(size, incrSize); - Uint32 needPages = size / pageSize; - while (needPages != 0) { - Uint32 wantPages = needPages; - if (incrPages != 0 && wantPages > incrPages) - wantPages = incrPages; - Uint32 tryPages = 0; - void* p1 = 0; - for (Uint32 i = mallocPart; i > 0 && p1 == 0; i--) { - // one page is usually wasted due to alignment to memory root - tryPages = ((wantPages + 1) * i) / mallocPart; - if (tryPages < 2) - break; - p1 = malloc(pageSize * tryPages); - } - if (p1 == 0) - return false; - if (m_memRoot == 0) { - // set memory root at first "big" alloc - // assume malloc header makes later ip = -1 impossible - m_memRoot = p1; - } - void* p2 = SP_ALIGN_PTR(p1, m_memRoot, pageSize); - Uint32 numPages = tryPages - (p1 != p2); - my_ptrdiff_t ipL = ((Uint8*)p2 - (Uint8*)m_memRoot) / pageSize; - Int32 ip = (Int32)ipL; - Int32 lim = 1 << (pageBits - 1); - if (! (ip == ipL && -lim <= ip && ip + numPages < lim)) { - free(p1); - return false; - } - assert(ip != -1); - PtrI pageI = ip << recBits; - needPages = (needPages >= numPages ? needPages - numPages : 0); - m_totalSize += numPages * pageSize; - // allocate new area - Area* ap = static_cast<Area*>(malloc(sizeof(Area))); - if (ap == 0) { - free(p1); - return false; - } - new (ap) Area(); - ap->m_firstPageI = pageI; - ap->m_numPages = numPages; - ap->m_memory = p1; - m_lastArea->m_nextArea = ap; - m_lastArea = ap; - } - return true; -} diff --git a/ndb/src/kernel/vm/SuperPool.hpp b/ndb/src/kernel/vm/SuperPool.hpp deleted file mode 100644 index 157c75aa0d5..00000000000 --- a/ndb/src/kernel/vm/SuperPool.hpp +++ /dev/null @@ -1,561 +0,0 @@ -/* 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 */ - -#ifndef SUPER_POOL_HPP -#define SUPER_POOL_HPP - -#include <ndb_global.h> - -#include <pc.hpp> -#include <ErrorReporter.hpp> - -#define NDB_SP_VERIFY_LEVEL 1 - -/* - * SuperPool - super pool for record pools (abstract class) - * - * Documents SuperPool and RecordPool<T>. - * - * GENERAL - * - * A "super pool" is a shared pool of pages of fixed size. A "record - * pool" is a pool of records of fixed size. One super pool instance is - * used by any number of record pools to allocate their memory. - * A special case is a "page pool" where a record is a simple page, - * possibly smaller than super pool page. - * - * A record pool allocates memory in pages. Thus each used page is - * associated with one record pool and one record type. The records on - * a page form an array starting at start of page. Thus each record has - * an index within the page. Any last partial record which does not fit - * on the page is disregarded. - * - * I-VALUE - * - * The old "i-p" principle is kept. A reference to a super pool page or - * record is stored as an "i-value" from which the record pointer "p" is - * computed. In super pool the i-value is a Uint32 with two parts: - * - * - "ip" index of page within super pool (high pageBits) - * - "ir" index of record within page (low recBits) - * - * The translation between "ip" and page address is described in next - * section. Once page address is known, the record address is found - * from "ir" in the obvious way. - * - * The main advantage with i-value is that it can be verified. The - * level of verification depends on compile type (release, debug). - * - * - "v0" minimal sanity check - * - "v1" check record type matches page type, see below - * - "v2" check record is in use (not yet implemented) - * - * Another advantage of a 32-bit i-value is that it extends the space of - * 32-bit addressable records on a 64-bit platform. - * - * RNIL is 0xffffff00 and indicates NULL i-value. To avoid hitting RNIL - * it is required that pageBits <= 30 and that the maximum value of the - * range (2^pageBits-1) is not used. - * - * MEMORY ROOT - * - * This super pool requires a "memory root" i.e. a memory address such - * that the index of a page "ip" satisfies - * - * page address = memory root + (signed)ip * page size - * - * This is possible on most platforms, provided that the memory root and - * all pages are either on the heap or on the stack, in order to keep - * the size of "ip" reasonably small. - * - * The cast (signed)ip is done as integer of pageBits bits. "ip" has - * same sign bit as i-value "i" so (signed)ip = (Int32)i >> recBits. - * The RNIL restriction can be expressed as (signed)ip != -1. - * - * PAGE ENTRIES - * - * Each super pool page has a "page entry". It contains: - * - * - page type - * - i-value of first free record on page - * - page use count, to see if page can be freed - * - pointers (as i-values) to next and previous page in list - * - * Page entry cannot be stored on the page itself since this prevents - * aligning pages to OS block size and the use of BATs (don't ask) for - * page pools in NDB. For now the implementation provides an array of - * page entries with place for all (2^pageBits) entries. - * - * PAGE TYPE - * - * Page type is (in principle) unique to the record pool using the super - * pool. It is assigned in record pool constructor. Page type zero - * means that the page is free i.e. not allocated to a record pool. - * - * Each "i-p" conversion checks ("v1") that the record belongs to same - * pool as the page. This check is much more common than page or record - * allocation. To make it cache effective, there is a separate array of - * reduced "type bits" (computed from real type). - * - * FREE LISTS - * - * A record is either used or on the free list of the record pool. - * A page has a use count i.e. number of used records. When use count - * drops to zero the page can be returned to the super pool. This is - * not necessarily done at once, or ever. - * - * To make freeing pages feasible, the record pool free list has two - * levels. There are available pages (some free) and a singly linked - * free list within the page. A page allocated to record pool is on one - * of 4 lists: - * - * - free page list (all free, available) - * - active page list (some free, some used, available) - * - full page list (none free) - * - current page (list of 1), see below - * - * Some usage types (temporary pools) may never free records. They pay - * a small penalty for the extra overhead. - * - * RECORD POOL - * - * A pool of records which allocates its memory from a super pool - * instance specified in the constructor. There are 3 basic operations: - * - * - getPtr - translate i-value to pointer-to-record p - * - seize - allocate record - * - release - free record - * - * CURRENT PAGE - * - * getPtr is a fast computation which does not touch the page. For - * seize and release there is an optimization: - * - * Define "current page" as page of latest seize or release. Its page - * entry is cached under record pool instance. The page is removed from - * its normal list. Seize and release on current page are fast and - * avoid touching the page. The current page is used until - * - * - seize and current page is full - * - release and the page is not current page - * - * Then the real page entry is updated and the page is added to the - * appropriate list, and a new page is made current. - * - * PAGE POLICY - * - * Allocating new page to record pool is expensive. Therefore record - * pool should not always return empty pages to super pool. There are - * two trivial policies, each with problems: - * - * - "pp1" never return empty page to super pool - * - "pp2" always return empty page to super pool - * - * This implementation uses "pp2" for now. A real policy is implemented - * in next version. - * - * OPEN ISSUES AND LIMITATIONS - * - * - smarter (virtual) placement of check bits & page entries - * - should getPtr etc be inlined? (too much code) - * - real page policy - * - other implementations (only HeapPool is done) - * - super pool list of all record pools, for statistics etc - * - access by multiple threads is not supported - */ - -// align size -#define SP_ALIGN_SIZE(sz, al) \ - (((sz) + (al) - 1) & ~((al) - 1)) - -// align pointer relative to base -#define SP_ALIGN_PTR(p, base, al) \ - (void*)((Uint8*)(base) + SP_ALIGN_SIZE((Uint8*)(p) - (Uint8*)(base), (al))) - -class SuperPool { -public: - // Type of i-value, used to reference both pages and records. Page - // index "ip" occupies the high bits. The i-value of a page is same - // as i-value of record 0 on the page. - typedef Uint32 PtrI; - - // Size and address alignment given as number of bytes (power of 2). - STATIC_CONST( SP_ALIGN = 8 ); - - // Page entry. Current|y allocated as array of (2^pageBits). - struct PageEnt { - PageEnt(); - Uint32 m_pageType; - Uint32 m_freeRecI; - Uint32 m_useCount; - PtrI m_nextPageI; - PtrI m_prevPageI; - }; - - // Number of bits for cache effective type check given as log of 2. - // Example: 2 means 4 bits and uses 32k for 2g of 32k pages. - STATIC_CONST( SP_CHECK_LOG2 = 2 ); - - // Doubly-linked list of pages. There is one free list in super pool - // and free, active, full list in each record pool. - struct PageList { - PageList(); - PageList(PtrI pageI); - PtrI m_headPageI; - PtrI m_tailPageI; - Uint32 m_pageCount; - }; - - // Record pool information. Each record pool instance contains one. - struct RecInfo { - RecInfo(Uint32 recType, Uint32 recSize); - const Uint32 m_recType; - const Uint32 m_recSize; - Uint32 m_maxUseCount; // could be computed - Uint32 m_currPageI; // current page - Uint32 m_currFreeRecI; - Uint32 m_currUseCount; - Uint32 m_totalUseCount; // total per pool - Uint32 m_totalRecCount; - PageList m_freeList; - PageList m_activeList; - PageList m_fullList; - }; - - // Constructor. Gives page size in bytes (excluding page header) and - // number of bits to use for page index "ip" in i-value. - SuperPool(Uint32 pageSize, Uint32 pageBits); - - // Initialize. Must be called after setting sizes or other parameters - // and before the pool is used. - virtual bool init(); - - // Destructor. - virtual ~SuperPool() = 0; - - // Translate i-value to page entry. - PageEnt& getPageEnt(PtrI pageI); - - // Translate i-value to page address. - void* getPageP(PtrI pageI); - - // Translate page address to i-value (unused). - PtrI getPageI(void* pageP); - - // Given type, return non-zero reduced type check bits. - Uint32 makeCheckBits(Uint32 type); - - // Get type check bits from type check array. - Uint32 getCheckBits(PtrI pageI); - - // Set type check bits in type check array. - void setCheckBits(PtrI pageI, Uint32 type); - - // Translate i-value to record address. - void* getRecP(PtrI recI, RecInfo& ri); - - // Move all pages from second list to end of first list. - void movePages(PageList& pl1, PageList& pl2); - - // Add page to beginning of page list. - void addHeadPage(PageList& pl, PtrI pageI); - - // Add page to end of page list. - void addTailPage(PageList& pl, PtrI pageI); - - // Remove any page from page list. - void removePage(PageList& pl, PtrI pageI); - - // Set current page. Previous current page is updated and added to - // appropriate list. - void setCurrPage(RecInfo& ri, PtrI pageI); - - // Get page with some free records and make it current. Takes head of - // active or free list, or else gets free page from super pool. - bool getAvailPage(RecInfo& ri); - - // Get free page from super pool and add it to record pool free list. - // This is an expensive subroutine of getAvailPage(). - PtrI getFreePage(RecInfo& ri); - - // Get new free page from the implementation. - virtual PtrI getNewPage() = 0; - - // Set 3 size parameters, rounded to page size. If called before - // init() then init() allocates the initial size. - void setSizes(size_t initSize = 0, size_t incrSize = 0, size_t maxSize = 0); - - const Uint32 m_pageSize; - const Uint32 m_pageBits; - // implementation must set up these pointers - void* m_memRoot; - PageEnt* m_pageEnt; - Uint32* m_typeCheck; - Uint32 m_typeSeq; - PageList m_pageList; - size_t m_totalSize; - size_t m_initSize; - size_t m_incrSize; - size_t m_maxSize; - - // Debugging. - void verify(RecInfo& ri); -}; - -inline SuperPool::PageEnt& -SuperPool::getPageEnt(PtrI pageI) -{ - Uint32 ip = pageI >> (32 - m_pageBits); - return m_pageEnt[ip]; -} - -inline void* -SuperPool::getPageP(PtrI ptrI) -{ - Int32 ip = (Int32)ptrI >> (32 - m_pageBits); - my_ptrdiff_t sz = m_pageSize; - void* pageP = (Uint8*)m_memRoot + ip * sz; - return pageP; -} - -inline Uint32 -SuperPool::makeCheckBits(Uint32 type) -{ - Uint32 shift = 1 << SP_CHECK_LOG2; - Uint32 mask = (1 << shift) - 1; - return 1 + type % mask; -} - -inline Uint32 -SuperPool::getCheckBits(PtrI pageI) -{ - Uint32 ip = pageI >> (32 - m_pageBits); - Uint32 xp = ip >> (5 - SP_CHECK_LOG2); - Uint32 yp = ip & (1 << (5 - SP_CHECK_LOG2)) - 1; - Uint32& w = m_typeCheck[xp]; - Uint32 shift = 1 << SP_CHECK_LOG2; - Uint32 mask = (1 << shift) - 1; - // get - Uint32 bits = (w >> yp * shift) & mask; - return bits; -} - -inline void -SuperPool::setCheckBits(PtrI pageI, Uint32 type) -{ - Uint32 ip = pageI >> (32 - m_pageBits); - Uint32 xp = ip >> (5 - SP_CHECK_LOG2); - Uint32 yp = ip & (1 << (5 - SP_CHECK_LOG2)) - 1; - Uint32& w = m_typeCheck[xp]; - Uint32 shift = 1 << SP_CHECK_LOG2; - Uint32 mask = (1 << shift) - 1; - // set - Uint32 bits = makeCheckBits(type); - w &= ~(mask << yp * shift); - w |= (bits << yp * shift); -} - -inline void* -SuperPool::getRecP(PtrI ptrI, RecInfo& ri) -{ - const Uint32 recMask = (1 << (32 - m_pageBits)) - 1; - PtrI pageI = ptrI & ~recMask; -#if NDB_SP_VERIFY_LEVEL >= 1 - Uint32 bits1 = getCheckBits(pageI); - Uint32 bits2 = makeCheckBits(ri.m_recType); - assert(bits1 == bits2); -#endif - void* pageP = getPageP(pageI); - Uint32 ir = ptrI & recMask; - void* recP = (Uint8*)pageP + ir * ri.m_recSize; - return recP; -} - -/* - * HeapPool - SuperPool on heap (concrete class) - * - * A super pool based on malloc with memory root on the heap. This - * pool type has 2 realistic uses: - * - * - a small pool with only initial malloc and pageBits set to match - * - the big pool from which all heap allocations are done - * - * A "smart" malloc may break "ip" limit by using different VM areas for - * different sized requests. For this reason malloc is done in units of - * increment size if possible. Memory root is set to start of first - * malloc. - */ - -class HeapPool : public SuperPool { -public: - // Describes malloc area. The areas are kept in singly linked list. - // There is a list head and pointers to current and last area. - struct Area { - Area(); - Area* m_nextArea; - PtrI m_firstPageI; - Uint32 m_currPage; - Uint32 m_numPages; - void* m_memory; - }; - - // Constructor. - HeapPool(Uint32 pageSize, Uint32 pageBits); - - // Initialize. - virtual bool init(); - - // Destructor. - virtual ~HeapPool(); - - // Use malloc to allocate more. - bool allocMoreData(size_t size); - - // Get new page from current area. - virtual PtrI getNewPage(); - - // List of malloc areas. - Area m_areaHead; - Area* m_currArea; - Area* m_lastArea; - - // Fraction of malloc size to try if cannot get all in one. - Uint32 m_mallocPart; -}; - -/* - * RecordPool - record pool using one super pool instance (template) - * - * Documented under SuperPool. Satisfies ArrayPool interface. - */ - -template <class T> -class RecordPool { -public: - // Constructor. - RecordPool(SuperPool& superPool); - - // Destructor. - ~RecordPool(); - - // Update pointer ptr.p according to i-value ptr.i. - void getPtr(Ptr<T>& ptr); - - // Allocate record from the pool. - bool seize(Ptr<T>& ptr); - - // Return record to the pool. - void release(Ptr<T>& ptr); - - // todo variants of basic methods - - // Return all pages to super pool. The force flag is required if - // there are any used records. - void free(bool force); - - SuperPool& m_superPool; - SuperPool::RecInfo m_recInfo; -}; - -template <class T> -inline -RecordPool<T>::RecordPool(SuperPool& superPool) : - m_superPool(superPool), - m_recInfo(1 + superPool.m_typeSeq++, sizeof(T)) -{ - SuperPool::RecInfo& ri = m_recInfo; - assert(sizeof(T) == SP_ALIGN_SIZE(sizeof(T), sizeof(Uint32))); - Uint32 maxUseCount = superPool.m_pageSize / sizeof(T); - Uint32 sizeLimit = 1 << (32 - superPool.m_pageBits); - if (maxUseCount >= sizeLimit) - maxUseCount = sizeLimit; - ri.m_maxUseCount = maxUseCount; -} - -template <class T> -inline -RecordPool<T>::~RecordPool() -{ - free(true); -} - -template <class T> -inline void -RecordPool<T>::getPtr(Ptr<T>& ptr) -{ - void* recP = m_superPool.getRecP(ptr.i, m_recInfo); - ptr.p = static_cast<T*>(recP); -} - -template <class T> -inline bool -RecordPool<T>::seize(Ptr<T>& ptr) -{ - SuperPool& sp = m_superPool; - SuperPool::RecInfo& ri = m_recInfo; - if (ri.m_currFreeRecI != RNIL || sp.getAvailPage(ri)) { - SuperPool::PtrI recI = ri.m_currFreeRecI; - void* recP = sp.getRecP(recI, ri); - ri.m_currFreeRecI = *(Uint32*)recP; - Uint32 useCount = ri.m_currUseCount; - assert(useCount < ri.m_maxUseCount); - ri.m_currUseCount = useCount + 1; - ri.m_totalUseCount++; - ptr.i = recI; - ptr.p = static_cast<T*>(recP); - return true; - } - return false; -} - -template <class T> -inline void -RecordPool<T>::release(Ptr<T>& ptr) -{ - SuperPool& sp = m_superPool; - SuperPool::RecInfo& ri = m_recInfo; - const Uint32 recMask = (1 << (32 - sp.m_pageBits)) - 1; - SuperPool::PtrI recI = ptr.i; - SuperPool::PtrI pageI = recI & ~recMask; - if (pageI != ri.m_currPageI) { - sp.setCurrPage(ri, pageI); - } - void* recP = sp.getRecP(recI, ri); - *(Uint32*)recP = ri.m_currFreeRecI; - ri.m_currFreeRecI = recI; - Uint32 useCount = ri.m_currUseCount; - assert(useCount != 0); - ri.m_currUseCount = useCount - 1; - ri.m_totalUseCount--; - ptr.i = RNIL; - ptr.p = 0; -} - -template <class T> -inline void -RecordPool<T>::free(bool force) -{ - SuperPool& sp = m_superPool; - SuperPool::RecInfo& ri = m_recInfo; - sp.setCurrPage(ri, RNIL); - assert(force || ri.m_totalUseCount == 0); - sp.movePages(sp.m_pageList, ri.m_freeList); - sp.movePages(sp.m_pageList, ri.m_activeList); - sp.movePages(sp.m_pageList, ri.m_fullList); - ri.m_totalRecCount = 0; -} - -#endif diff --git a/ndb/src/kernel/vm/testSuperPool.cpp b/ndb/src/kernel/vm/testSuperPool.cpp deleted file mode 100644 index 194b3a43fa0..00000000000 --- a/ndb/src/kernel/vm/testSuperPool.cpp +++ /dev/null @@ -1,220 +0,0 @@ -#if 0 -make -f Makefile -f - testSuperPool <<'_eof_' -testSuperPool: testSuperPool.cpp libkernel.a - $(CXXCOMPILE) -o $@ $@.cpp libkernel.a -L../../common/util/.libs -lgeneral -_eof_ -exit $? -#endif - -/* 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 */ - -#include "SuperPool.hpp" -#include <NdbOut.hpp> - -template <Uint32 sz> -struct A { - Uint32 a[sz]; - void fill() { - Uint32 c = 0; - for (Uint32 i = 0; i + 1 < sz; i++) { - a[i] = random(); - c = (c << 1) ^ a[i]; - } - a[sz - 1] = c; - } - void check() { - Uint32 c = 0; - for (Uint32 i = 0; i + 1 < sz; i++) { - c = (c << 1) ^ a[i]; - } - assert(a[sz - 1] == c); - } -}; - -static Uint32 -urandom(Uint32 n) -{ - return (Uint32)random() % n; -} - -static Uint32 -random_coprime(Uint32 n) -{ - Uint32 prime[] = { 101, 211, 307, 401, 503, 601, 701, 809, 907 }; - Uint32 count = sizeof(prime) / sizeof(prime[0]); - while (1) { - Uint32 i = urandom(count); - if (n % prime[i] != 0) - return prime[i]; - } -} - -static int -cmpPtrI(const void* a, const void* b) -{ - Ptr<const void> u = *(Ptr<const void>*)a; - Ptr<const void> v = *(Ptr<const void>*)b; - return u.i < v.i ? -1 : u.i > v.i ? +1 : 0; -} - -static int -cmpPtrP(const void* a, const void* b) -{ - Ptr<const void> u = *(Ptr<const void>*)a; - Ptr<const void> v = *(Ptr<const void>*)b; - return u.p < v.p ? -1 : u.p > v.p ? +1 : 0; -} - -static Uint32 loopcount = 3; - -template <Uint32 sz> -void -sp_test(SuperPool& sp) -{ - typedef A<sz> T; - RecordPool<T> rp(sp); - SuperPool::RecInfo& ri = rp.m_recInfo; - Uint32 pageCount = sp.m_totalSize / sp.m_pageSize; - Uint32 perPage = rp.m_recInfo.m_maxUseCount; - Uint32 perPool = perPage * pageCount; - ndbout << "pages=" << pageCount << " perpage=" << perPage << " perpool=" << perPool << endl; - Ptr<T>* ptrList = new Ptr<T> [perPool]; - memset(ptrList, 0x1f, perPool * sizeof(Ptr<T>)); - Uint32 loop; - for (loop = 0; loop < loopcount; loop++) { - ndbout << "loop " << loop << endl; - Uint32 i, j; - // seize all - ndbout << "seize all" << endl; - for (i = 0; i < perPool + 1; i++) { - j = i; - sp.verify(ri); - Ptr<T> ptr1 = { 0, RNIL }; - if (! rp.seize(ptr1)) - break; - // write value - ptr1.p->fill(); - ptr1.p->check(); - // verify getPtr - Ptr<T> ptr2 = { 0, ptr1.i }; - rp.getPtr(ptr2); - assert(ptr1.i == ptr2.i && ptr1.p == ptr2.p); - // save - ptrList[j] = ptr1; - } - assert(i == perPool); - assert(ri.m_totalUseCount == perPool && ri.m_totalRecCount == perPool); - sp.verify(ri); - // check duplicates - { - Ptr<T>* ptrList2 = new Ptr<T> [perPool]; - memcpy(ptrList2, ptrList, perPool * sizeof(Ptr<T>)); - qsort(ptrList2, perPool, sizeof(Ptr<T>), cmpPtrI); - for (i = 1; i < perPool; i++) - assert(ptrList2[i - 1].i != ptrList2[i].i); - qsort(ptrList2, perPool, sizeof(Ptr<T>), cmpPtrP); - for (i = 1; i < perPool; i++) - assert(ptrList2[i - 1].p != ptrList2[i].p); - delete [] ptrList2; - } - // release all in various orders - ndbout << "release all" << endl; - Uint32 coprime = random_coprime(perPool); - for (i = 0; i < perPool; i++) { - sp.verify(ri); - switch (loop % 3) { - case 0: // ascending - j = i; - break; - case 1: // descending - j = perPool - 1 - i; - break; - case 2: // pseudo-random - j = (coprime * i) % perPool; - break; - } - Ptr<T>& ptr = ptrList[j]; - assert(ptr.i != RNIL && ptr.p != 0); - ptr.p->check(); - rp.release(ptr); - assert(ptr.i == RNIL && ptr.p == 0); - } - sp.setCurrPage(ri, RNIL); - assert(ri.m_totalUseCount == 0 && ri.m_totalRecCount == 0); - sp.verify(ri); - // seize/release at random - ndbout << "seize/release at random" << endl; - for (i = 0; i < loopcount * perPool; i++) { - j = urandom(perPool); - Ptr<T>& ptr = ptrList[j]; - if (ptr.i == RNIL) { - rp.seize(ptr); - ptr.p->fill(); - } else { - ptr.p->check(); - rp.release(ptr); - } - } - ndbout << "used " << ri.m_totalUseCount << endl; - sp.verify(ri); - // release all - ndbout << "release all" << endl; - for (i = 0; i < perPool; i++) { - j = i; - Ptr<T>& ptr = ptrList[j]; - if (ptr.i != RNIL) { - ptr.p->check(); - rp.release(ptr); - } - } - sp.setCurrPage(ri, RNIL); - assert(ri.m_totalUseCount == 0 && ri.m_totalRecCount == 0); - sp.verify(ri); - } - // done - delete [] ptrList; -} - -static Uint32 pageCount = 99; -static Uint32 pageSize = 32768; -static Uint32 pageBits = 15; - -const Uint32 sz1 = 3, sz2 = 4, sz3 = 53, sz4 = 424, sz5 = 5353; - -template void sp_test<sz1>(SuperPool& sp); -template void sp_test<sz2>(SuperPool& sp); -template void sp_test<sz3>(SuperPool& sp); -template void sp_test<sz4>(SuperPool& sp); -template void sp_test<sz5>(SuperPool& sp); - -int -main() -{ - HeapPool sp(pageSize, pageBits); - sp.setSizes(pageCount * pageSize); - if (! sp.init()) - assert(false); - Uint16 s = (Uint16)getpid(); - srandom(s); - ndbout << "rand " << s << endl; - sp_test<sz1>(sp); - sp_test<sz2>(sp); - sp_test<sz3>(sp); - sp_test<sz4>(sp); - sp_test<sz5>(sp); - return 0; -} |