/* Copyright (C) 2014 InfiniDB, Inc. 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; version 2 of the License. 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include using namespace std; #include using namespace boost; #include #include "we_indextree.h" #include "we_freemgr.h" #include "we_indexlist.h" using namespace WriteEngine; typedef struct { IdxRidListHdr hdrRec; IdxRidListPtr listPtr; int fbo; int sbid; int entry; int sbSeqNo; int recCnt; int sbCnt; int fullSbCnt; } IdxListStat; typedef struct { int mapSize; int entryCnt; } IdxFreeSpaceStat; const int QA_FILE_TYPE_TREE = 1; const int QA_FILE_TYPE_LIST = 2; const int QA_FREEMAP_1ENTRY = 1; const int QA_FREEMAP_2ENTRY = 2; const int QA_FREEMAP_4ENTRY = 3; const int QA_FREEMAP_8ENTRY = 4; const int QA_FREEMAP_16ENTRY = 5; const int QA_FREEMAP_32ENTRY = 6; class IndexTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE( IndexTest ); /* ==================================================== Index stress test These tests will create the maxium number: 1) index key records, one row ID for each 2) row IDs for an index key ======================================================= */ //CPPUNIT_TEST( testCreateIndex ); /* ==================================================== TTest Suites ======================================================= */ CPPUNIT_TEST(qaTSCStressTestMaxRowID); //CPPUNIT_TEST(qaTSCStressTestMaxKey); //CPPUNIT_TEST(qaTSCIndexTestUpdate); //CPPUNIT_TEST(qaTSCIndexTestDelete); //CPPUNIT_TEST(qaTSCFreeSpaceMapTest); //CPPUNIT_TEST(qatestIndexList); CPPUNIT_TEST_SUITE_END(); private: IndexTree m_index; IndexList m_indexlist; FILE* curFile; public: void setUp() { } void tearDown() { } /* ========================================================== Create maximum number of row ids for key and verify all index list header records ============================================================= */ void qaTSCStressTestMaxRowID() { IdxFreeSpaceStat mapInfo; uint64_t idxKey = 1; int testCaseNo; int numOfRowID; int expSbCnt; int expFullSbCnt; char testCaseDesc[256]; int tokenLen = 1; int rc; int execMode; m_index.setUseFreeMgr( true ); m_index.setUseListMgr( true ); execMode = 0; strcpy(testCaseDesc, "8 bit key, max row stress test"); tokenLen = 8; testCaseNo = 10520; numOfRowID = 256; expSbCnt = 9; expFullSbCnt = 8; qaSupCreateMaxRowID(idxKey, tokenLen); qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); qaDspIndexListByKey(idxKey, tokenLen); strcpy(testCaseDesc, "16 bit key, max row stress test"); testCaseNo = 10521; numOfRowID = 65536; expSbCnt = 2115; expFullSbCnt = 2114; qaSupCreateMaxRowID(idxKey, tokenLen); qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); } /* ========================================================== Create maximum number key for a given key length and verify each index list header record ============================================================= */ void qaTSCStressTestMaxKey() { IdxFreeSpaceStat mapInfo; int testCaseNo; char testCaseDesc[256]; int tokenLen; int entryCnt; int execMode; execMode = 1; // qaSupCreateMaxHdrRec(tokenLen); strcpy(testCaseDesc, "8 bit key, max key stress test"); tokenLen = 8; testCaseNo = 10522; qaSupCreateMaxHdrRec(tokenLen); qaTstStressMaxKeyDriver(testCaseNo, testCaseDesc, tokenLen); // qaSupCreateMaxHdrRec(tokenLen); strcpy(testCaseDesc, "16 bit key, max key stress test"); tokenLen = 16; testCaseNo = 10523; qaSupCreateMaxHdrRec(tokenLen); qaTstStressMaxKeyDriver(testCaseNo, testCaseDesc, tokenLen); } /* ========================================================== Test cases for for updating index ============================================================= */ void qaTSCIndexTestUpdate() { uint64_t idxKey = 1; int tokenLen = 16; int testCaseNo; int startRowID = 1; int numOfRowID; int expSbCnt; int expFullSbCnt; char testCaseDesc[256]; strcpy(testCaseDesc, "Create 1 index key with one row ID, expecting no sub block and no full sub block."); testCaseNo = 10524; numOfRowID = 1; expSbCnt = 0; expFullSbCnt = 0; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); strcpy(testCaseDesc, "Create 2 index key with one row ID, expecting no sub block and no full sub block."); testCaseNo = 10525; numOfRowID = 2; expSbCnt = 0; expFullSbCnt = 0; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); strcpy(testCaseDesc, "Create 3 index key with one row ID, expecting 1 sub block and no full sub block."); testCaseNo = 10526; numOfRowID = 3; expSbCnt = 1; expFullSbCnt = 0; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); strcpy(testCaseDesc, "Create 1 index key with 32 row IDs, expecting 1 sub block and 1 full sub block."); testCaseNo =10527; numOfRowID = 32; expSbCnt = 1; expFullSbCnt = 1; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); strcpy(testCaseDesc, "Create 1 index key with 33 row IDs, expecting 2 sub block and 1 full sub block."); testCaseNo = 10528; numOfRowID = 33; expSbCnt = 2; expFullSbCnt = 1; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); strcpy(testCaseDesc, "Create 1 index key with 63 row IDs, expecting 2 sub block and 2 full sub block."); testCaseNo = 10529; numOfRowID = 63; expSbCnt = 2; expFullSbCnt = 2; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); } /* ========================================================== Test cases deleting index ============================================================= */ void qaTSCIndexTestDelete() { uint64_t idxKey = 1; int tokenLen = 16; int testCaseNo; int startRowID = 1; int numOfRowID; int expSbCnt; int expFullSbCnt; char testCaseDesc[256]; int i; int rc; //Create 1 row IDs, then remove it. //Expecting 0 row IDs, 0 sub blocks and 0 full sub blocks. strcpy(testCaseDesc, "Create 1 row ID, then remove it. Expecting 0 row ID, 0 sub block and 0 full sub block."); testCaseNo = 10530; numOfRowID = 1; expSbCnt = 0; expFullSbCnt = 0; m_index.setUseFreeMgr( true ); m_index.setUseListMgr( true ); qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); rc = m_index.openIndex( 990, 991 ); CPPUNIT_ASSERT( rc == NO_ERROR ); rc = m_index.deleteIndex(idxKey, tokenLen, startRowID ); CPPUNIT_ASSERT( rc == NO_ERROR ); m_index.closeIndex(); numOfRowID = 0; qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); // qaDspIndexListStatsByKey(idxKey, tokenLen); //Create 3 row IDs, then remove the first two. //Expecting 1 row IDs, 1 sub blocks and 0 full sub blocks. strcpy(testCaseDesc, "Create 3 row IDs, then remove the first two. Expecting 1 row ID, 1 sub block and 0 full sub block."); testCaseNo = 10531; numOfRowID = 3; expSbCnt = 1; expFullSbCnt = 0; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); rc = m_index.openIndex( 990, 991 ); CPPUNIT_ASSERT( rc == NO_ERROR ); for (i=startRowID; i 160) maxKey = 120; passed = true; for (i=0; i Addr(%d, %d, %d)\n", int(emptyMap.type), int(emptyMap.group), p_fbo, p_sbid, p_entry, (int)emptyMap.fbo, (int)emptyMap.sbid, (int)emptyMap.entry); printf("-------------------------------------------------------------------------\n"); } p_type = emptyMap.type; p_group = emptyMap.group; p_fbo = emptyMap.fbo; p_sbid = emptyMap.sbid; p_entry = emptyMap.entry; p_mapType = emptyMap.type; mapInfo.mapSize = 0; mapInfo.entryCnt = 0; done = ((p_mapType == 1) && (p_fbo == 0) && (p_sbid == 0) && (p_entry == 0)); while (not done ) { j = p_entry; mapInfo.mapSize++; for (i=j; i >= 0; i--) { m_indexlist.readSubBlockEntry( pFile, &curBlock, p_fbo, p_sbid, i, 8, &emptyMap); if (execMode == 1) // printf("EntryPtr: %d Type = %d Group = %d fbo = %d sbid = %d Entry = %d\n", i, int(emptyMap.type), int(emptyMap.group), (int)emptyMap.fbo, (int)emptyMap.sbid, (int)emptyMap.entry); printf("Entry: %d Type = %d Group = %d Addr(%d, %d, %d) ----> Addr(%d, %d, %d)\n", i, int(emptyMap.type), int(emptyMap.group), p_fbo, p_sbid, i, (int)emptyMap.fbo, (int)emptyMap.sbid, (int)emptyMap.entry); if (i != 0) mapInfo.entryCnt++; } p_fbo = emptyMap.fbo; p_sbid = emptyMap.sbid; p_entry = emptyMap.entry; p_mapType = emptyMap.type; done = ( (p_fbo == 0) && (p_sbid == 0) && (p_entry == 0)); if (not done && (execMode == 1)) { // printf("\nList Ptr: Type: %d Group: %d FBO: %d SBID: %d ENTRY: %d\n", p_type, p_group, p_fbo, p_sbid, p_entry); printf("\nList: Type = %d Group = %d Addr(%d, %d, %d) ----> Addr(%d, %d, %d)\n", int(emptyMap.type), int(emptyMap.group), p_fbo, p_sbid, p_entry, (int)emptyMap.fbo, (int)emptyMap.sbid, (int)emptyMap.entry); printf("-------------------------------------------------------------------------\n"); } } m_indexlist.closeFile(pFile); } // qaDspFreeSpaceMap /* ========================================================== Show branch list for all keys for a given key length ============================================================= */ void qaDspTreePathAll(uint64_t idxKey, int tokenLen) { uint64_t i; int maxKey; maxKey = (1 << tokenLen); for (i=0; i 160) maxKey = 160; for (i=0; ifbo, (int)((IdxEmptyListEntry*)&(indexListHdrRec.nextIdxRidListPtr))->sbid, (int)((IdxEmptyListEntry*)&(indexListHdrRec.nextIdxRidListPtr))->entry, (int)indexListHdrRec.nextIdxRidListPtr.type); } if (int(indexListHdrRec.firstIdxRidListEntry.type) == 3) idxKeyInfo.recCnt++; if (indexListHdrRec.nextIdxRidListPtr.type == 3 ) { idxKeyInfo.recCnt++; } else if (indexListHdrRec.nextIdxRidListPtr.type == 4 ) { p_fbo=((IdxEmptyListEntry*)&(indexListHdrRec.nextIdxRidListPtr))->fbo; p_sbid=((IdxEmptyListEntry*)&(indexListHdrRec.nextIdxRidListPtr))->sbid; p_entry=((IdxEmptyListEntry*)&(indexListHdrRec.nextIdxRidListPtr))->entry; while ( not endOfList ) { idxKeyInfo.sbCnt++; SBRecCnt = 0; m_indexlist.readSubBlockEntry( pFileIndexList, &indexBlock, p_fbo, p_sbid, 31, 8, &listPtr); printf("Index list subblock: #%d\n",idxKeyInfo.sbCnt); for (i=0; i<=30; i++) { m_indexlist.readSubBlockEntry( pFileIndexList, &indexBlock, p_fbo, p_sbid, i, 8, &listEntry); if (listEntry.type == 3) { SBRecCnt++; if (execMode == 1) printf("Entry %d: Addr(%d, %d, %d) RowId: %d \n", i, p_fbo, p_sbid, i, listEntry.rid); } } p_fbo=((IdxEmptyListEntry*)&(listPtr))->fbo; p_sbid=((IdxEmptyListEntry*)&(listPtr))->sbid; if ((idxKeyInfo.sbSeqNo != 0 ) && (idxKeyInfo.sbSeqNo == (idxKeyInfo.sbCnt-1))) { idxKeyInfo.fbo = p_fbo; //Save the address for the request block idxKeyInfo.sbid = p_sbid; idxKeyInfo.entry = p_entry; } if (execMode == 1 ) printf("Entry 31: Addr(%d, %d, %d) RecCnt = %d\n\n", p_fbo, p_sbid, p_entry, (int)listPtr.count); idxKeyInfo.recCnt += SBRecCnt; if (SBRecCnt == 31) idxKeyInfo.fullSbCnt++; if (SBRecCnt != listPtr.count) printf("[**ERROR**] Sub Block entry count Error: In Ptr Rec: %d In sub block: %d\n", listPtr.count, SBRecCnt); endOfList = (listPtr.type == 0); } } } m_indexlist.closeFile(pFileIndexList); } /******************************************************* . This function navigate through the tree, from the bitmap entry to the leaf. It can be used for many functions that require access to the hdr record also. *******************************************************/ void qaSupWalkIndexTree(uint64_t idxKey, int tokenLen, int execMode, int& fbo, int& sbid, int& entry, bool& exist) { DataBlock curBlock; FILE* pFile =NULL; int file_number=990; IdxBitmapPointerEntry bitmapRec; IdxBitTestEntry treeNodeRec; int p_fbo, p_sbid, p_entry, p_type, p_group,p_bitTest; int i; int maskValue = 31; //mask for 11111. int bitMapLoc, key1, shiftBits; int bitCnt; bool found; int mask[5] = {1, 3, 7, 15, 31}; int group[7] = {1, 2, 4, 8, 16, 32, 64}; memset( curBlock.data, 0, sizeof(curBlock.data)); pFile= m_indexlist.openFile( file_number ); CPPUNIT_ASSERT( pFile != NULL ); //Free Manager m_indexlist.setUseFreeMgr( true ); if (tokenLen > 5) bitMapLoc = ((idxKey >> tokenLen-5) & maskValue); else bitMapLoc = idxKey; p_fbo = 0; p_sbid = 1; p_entry = bitMapLoc; if (execMode == 1) { printf("\n---------------------------------\n"); printf("Tree branch path for key: %d\n", (int)idxKey); printf("---------------------------------\n"); } m_indexlist.readSubBlockEntry( pFile, &curBlock, p_fbo, p_sbid, p_entry, 8, &bitmapRec); shiftBits = 1; p_type = bitmapRec.type; p_fbo = bitmapRec.fbo; p_sbid = bitmapRec.sbid; p_entry = bitmapRec.entry; if (execMode == 1) // branch list printf("Bitmap: Type= %d BitTest= %d FBO= %d SBID= %d Entry= %d\n", int(p_type),int(p_bitTest), (int)p_fbo, (int)p_sbid, (int)p_entry); bitCnt = tokenLen - 5; while (bitCnt > 0) { if (bitCnt> 5) key1 = ((idxKey >> (bitCnt-5)) & maskValue); else key1 = ((idxKey) & mask[bitCnt-1]); m_indexlist.readSubBlockEntry( pFile, &curBlock, p_fbo, p_sbid, p_entry, 8, &treeNodeRec); int groupIdx = treeNodeRec.group; // printf("group: %d count: %d\n", groupIdx, group[groupIdx]); found = false; for (i=0;i #include int main( int argc, char **argv) { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry ®istry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest( registry.makeTest() ); bool wasSuccessful = runner.run( "", false ); return (wasSuccessful ? 0 : 1); }