/* 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 < startRowID + numOfRowID - 1; i++) { rc = m_index.deleteIndex(idxKey, tokenLen, i); CPPUNIT_ASSERT(rc == NO_ERROR); } m_index.closeIndex(); numOfRowID = 1; qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); // qaDspIndexListStatsByKey(idxKey, tokenLen); // Create 100 row IDs, then remove them. // Expecting 0 row IDs, 0 sub blocks and 0 full sub blocks. strcpy(testCaseDesc, "Create 100 row IDs, then remove them. Expecting 0 row ID, 0 sub block and 0 full sub block."); testCaseNo = 10532; numOfRowID = 100; expSbCnt = 0; expFullSbCnt = 0; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); rc = m_index.openIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); for (i = startRowID; i < startRowID + numOfRowID; i++) { rc = m_index.deleteIndex(idxKey, tokenLen, i); CPPUNIT_ASSERT(rc == NO_ERROR); } m_index.closeIndex(); numOfRowID = 0; qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); // qaDspIndexListStatsByKey(idxKey, tokenLen); // create 63 row ids so that two full sub blocks will be allocated. // delete all row ids, 2 to 32, in the first sub block strcpy(testCaseDesc, "Create 63 row ids, then remove all in the 2nd sub block. Verify that row id sub block gets " "released when empty."); testCaseNo = 10533; numOfRowID = 63; expSbCnt = 1; expFullSbCnt = 1; qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); rc = m_index.openIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); for (i = 2; i < 33; i++) { rc = m_index.deleteIndex(idxKey, tokenLen, i); CPPUNIT_ASSERT(rc == NO_ERROR); } m_index.closeIndex(); numOfRowID = 32; qaTstIndexListDriver(testCaseNo, testCaseDesc, idxKey, tokenLen, numOfRowID, expSbCnt, expFullSbCnt); } /* ========================================================== Test cases for empty maps ============================================================= */ void qaTSCFreeSpaceMapTest() { IdxFreeSpaceStat mapInfo; uint64_t idxKey = 1; int tokenLen = 16; int execMode = 0; int testCaseNo, startKey, numOfKey; int startRowID, numOfRowID; int i; int expMapSize, expEntryCnt; char testCaseDesc[256]; strcpy(testCaseDesc, "No keys created. There should not be a empty list for header record."); testCaseNo = 10534; startKey = 1; numOfKey = 0; expMapSize = 0; expEntryCnt = 0; qaSupCreateRangeKey(idxKey, tokenLen, startKey, numOfKey); qaDspFreeSpaceMap(QA_FILE_TYPE_LIST, QA_FREEMAP_4ENTRY, execMode, mapInfo); qaTstFreeMapDriver(testCaseNo, testCaseDesc, expMapSize, expEntryCnt, mapInfo); strcpy(testCaseDesc, "Create 1 key. There will be space left for 7 more header records."); testCaseNo = 10535; startKey = 1; numOfKey = 1; expMapSize = 1; expEntryCnt = 7; qaSupCreateRangeKey(idxKey, tokenLen, startKey, numOfKey); qaDspFreeSpaceMap(QA_FILE_TYPE_LIST, QA_FREEMAP_4ENTRY, execMode, mapInfo); qaTstFreeMapDriver(testCaseNo, testCaseDesc, expMapSize, expEntryCnt, mapInfo); strcpy(testCaseDesc, "Create 8 row ids. There will be space left for 0 more header records."); testCaseNo = 10536; startKey = 1; numOfKey = 8; expMapSize = 1; expEntryCnt = 0; qaSupCreateRangeKey(idxKey, tokenLen, startKey, numOfKey); qaDspFreeSpaceMap(QA_FILE_TYPE_LIST, QA_FREEMAP_4ENTRY, execMode, mapInfo); qaTstFreeMapDriver(testCaseNo, testCaseDesc, expMapSize, expEntryCnt, mapInfo); strcpy(testCaseDesc, "Create 9 key. There will be space left for 7 more header records."); testCaseNo = 10537; startKey = 1; numOfKey = 1; expMapSize = 1; expEntryCnt = 7; qaSupCreateRangeKey(idxKey, tokenLen, startKey, numOfKey); qaDspFreeSpaceMap(QA_FILE_TYPE_LIST, QA_FREEMAP_4ENTRY, execMode, mapInfo); qaTstFreeMapDriver(testCaseNo, testCaseDesc, expMapSize, expEntryCnt, mapInfo); /* strcpy(testCaseDesc, "Verify that a sub block holding empty list entries will be released when empty."); testCaseNo = 10538; startRowID = 1; expMapSize = 0; expEntryCnt = 0; //Create files without key records, then get number of 32-entry free blocks. numOfRowID = 0; qaSupCreateRangeKey(idxKey, tokenLen, startRowID, numOfRowID); qaDspFreeSpaceMap(QA_FILE_TYPE_LIST, QA_FREEMAP_32ENTRY, execMode, mapInfo); int initialSize = mapInfo.mapSize; int initialEntry = mapInfo.entryCnt; execMode = 1; qaDspFreeSpaceMap(QA_FILE_TYPE_LIST, QA_FREEMAP_32ENTRY, execMode, mapInfo); printf(" size: %d\n", mapInfo.mapSize); printf(" entry: %d\n", mapInfo.entryCnt); numOfRowID = 900; //There are 31 entries in a 32-entry empty list sub block. //1 ptr allocated for 4-entry free map, 1 for hdr, 29 entries remaining. //29 entriess, pointing 29 sub blocks. 29 x 31 = 899, plus 1 in hdr = 900 entries qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, numOfRowID); qaDspFreeSpaceMap(QA_FILE_TYPE_LIST, QA_FREEMAP_32ENTRY, execMode, mapInfo); expMapSize = initialSize - 1 - 1 + 1; // - 1 hdr block, -1 4-entry list, + 1 free 32-entry block. expEntryCnt = initialEntry - 29 - 1 - 1 + 1; // -29 data sub blocks, - 1 for 4-entry list ptr, 1 for hdr record ptr, +1 free 32-entry ptr expEntryCnt++ ; // add 1 for the free 32-entry sub block. qaTstFreeMapDriver(testCaseNo, testCaseDesc, expMapSize, expEntryCnt, mapInfo); qaDspIndexListByKey(idxKey, tokenLen); qaDspIndexListStatsByKey(idxKey, tokenLen); */ execMode = 1; // qaDspFreeSpaceMap(QA_FILE_TYPE_LIST, QA_FREEMAP_32ENTRY, execMode, mapInfo); // qaDspIndexListByKey(idxKey, tokenLen); // qaDspIndexListStatsByKey(idxKey, tokenLen); } /* ========================================================== verify each index list header record for a given key length ============================================================= */ void qaTstStressMaxKeyDriver(int testCaseNo, char* testCaseDesc, int tokenLen) { bool rc, passed, ; int checkMode = 2; int i, maxKey; int numOfRowID = 1; int expSbCnt = 0; int expFullSbCnt = 0; qaDspTestStatusHeader(testCaseNo, testCaseDesc); maxKey = (1 << tokenLen); if (maxKey > 160) maxKey = 120; passed = true; for (i = 0; i < maxKey; i++) { rc = qaSupVerifyIndexByKey(i, tokenLen, checkMode, numOfRowID, expSbCnt, expFullSbCnt); if (rc != NO_ERROR) passed = false; } qaDspTestStatusFooter(testCaseNo, passed); } /* ========================================================== A driver function to execution test cases for the index list. ============================================================= */ void qaTstIndexListDriver(int testCaseNo, char* testCaseDesc, uint64_t idxKey, int tokenLen, int numOfRowID, int expSbCnt, int expFullSbCnt) { bool passed; int checkMode = 2; qaDspTestStatusHeader(testCaseNo, testCaseDesc); passed = qaSupVerifyIndexByKey(idxKey, tokenLen, checkMode, numOfRowID, expSbCnt, expFullSbCnt); qaDspTestStatusFooter(testCaseNo, passed); } /* ========================================================== A driver function to verify free map list ============================================================= */ void qaTstFreeMapDriver(int testCaseNo, char* testCaseDesc, int expMapSize, int expEntryCnt, IdxFreeSpaceStat mapInfo) { int passed = true; qaDspTestStatusHeader(testCaseNo, testCaseDesc); if (mapInfo.mapSize != expMapSize) { printf(" Free map size mismatch: Expected: %d Returned: %d\n", expMapSize, (int)mapInfo.mapSize); passed = false; } if (mapInfo.entryCnt != expEntryCnt) { printf(" Free map entry mismatch: Expected: %d Returned: %d\n", expEntryCnt, (int)mapInfo.entryCnt); passed = false; } qaDspTestStatusFooter(testCaseNo, passed); } /* ========================================================== Verify index list record with it's integral components and expected values from the calling program. ============================================================= */ bool qaSupVerifyIndexByKey(uint64_t idxKey, int tokenLen, int checkMode, int expRowIDCnt, int expSbCnt, int expFullSbCnt) { IdxListStat idxKeyInfo; int execMode = 0; int passed = true; // checkMode != 1 Verify index header information only // checkMode = 2 verify header information, plus matching expected results. qaSupWalkIndexList(idxKey, tokenLen, execMode, idxKeyInfo); // verify for matching record keys if (idxKeyInfo.hdrRec.key != idxKey) { printf(" Index key mismatch: Expected: %d Returned: %d\n", (int)idxKey, (int)idxKeyInfo.hdrRec.key); passed = false; } // verify row id count in the hdr record against row id count gathered from the index list record. if (idxKeyInfo.hdrRec.idxRidListSize.size != idxKeyInfo.recCnt) { printf(" Index Hdr cnt mismatch: In Hdr : %d In SB: %d\n", idxKeyInfo.hdrRec.idxRidListSize.size, idxKeyInfo.recCnt); passed = false; } // verify that when there is not sub blocks for the row IDs, the header's link list pointer should not be // used. if ((idxKeyInfo.sbCnt == 0) && (idxKeyInfo.hdrRec.nextIdxRidListPtr.type == 4)) { printf(" Incorrect list pointer: Ptr type: %d SB Cnt: %d\n", idxKeyInfo.hdrRec.idxRidListSize.size, idxKeyInfo.recCnt); passed = false; } if (checkMode = 2) { // verify row id count in the hdr record against expected row id count if (idxKeyInfo.hdrRec.idxRidListSize.size != expRowIDCnt) { printf(" Row ID cnt mismatch: Expected: %d Returned: %d\n", expRowIDCnt, idxKeyInfo.hdrRec.idxRidListSize.size); passed = false; } // verify sub block count gathered from the index list record against the expected sub block //count if (idxKeyInfo.sbCnt != expSbCnt) { printf(" Subblock cnt mismatch: Expected: %d Returned: %d\n", expSbCnt, idxKeyInfo.sbCnt); passed = false; } // verify full sub block count gathered from the index list record against the expected full sub //block count if (idxKeyInfo.fullSbCnt != expFullSbCnt) { printf(" Full subblock cnt mismatch: Expected: %d Returned: %d\n", expFullSbCnt, idxKeyInfo.fullSbCnt); passed = false; } } return passed; } /* ========================================================== Display index record for a given key ============================================================= */ void qaGetListSubblockByKey(uint64_t idxKey, int tokenLen, int sbSeqNo, int& fbo, int& sbid, int& entry) { int p_fbo, p_sbid, p_entry; int execMode = 1; bool exist; // qaSupWalkIndexList(idxKey, tokenLen, execMode, sbSeqNo, p_fbo, p_sbid, p_entry, hdrCntMatch, //hdrRecCnt, hdrSbCnt, hdrFullSbCnt); fbo = p_fbo; sbid = p_sbid; entry = p_entry; } /* ========================================================== Display tree empty list map for a given block size ============================================================= */ void qaDspFreeSpaceMap(int fileType, int mapType, int execMode, IdxFreeSpaceStat& mapInfo) { DataBlock curBlock; FILE* pFile = NULL; int fileNum; int p_fbo, p_sbid, p_entry, p_type, p_group; int i, j; int p_mapType; bool done; IdxEmptyListEntry emptyMap; if (fileType == QA_FILE_TYPE_TREE) fileNum = 990; // index tree else fileNum = 991; // index list memset(curBlock.data, 0, sizeof(curBlock.data)); pFile = m_indexlist.openFile(fileNum); CPPUNIT_ASSERT(pFile != NULL); // Free Manager m_indexlist.setUseFreeMgr(true); p_fbo = 0; p_sbid = 0; p_entry = mapType; // Entry location in Fb 0 and SB 0; if (execMode == 1) { printf("\n------------------------------------\n"); if (fileType == 1) printf("Index Tree %d-ENTRY free space map\n", 1 << (mapType - 1)); else printf("Index list %d-ENTRY free space map\n", 1 << (mapType - 1)); printf("------------------------------------\n"); } m_indexlist.readSubBlockEntry(pFile, &curBlock, p_fbo, p_sbid, p_entry, 8, &emptyMap); if (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"); } 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 < maxKey; i++) qaDspTreePathByKey(idxKey, tokenLen); } /******************************************************* . Display branch list for a key *******************************************************/ void qaDspTreePathByKey(uint64_t idxKey, int tokenLen) { int p_fbo, p_sbid, p_entry; bool exist; int execMode = 1; qaSupWalkIndexTree(idxKey, tokenLen, execMode, p_fbo, p_sbid, p_entry, exist); } // qaDspTreePathByKey /* ========================================================== Verfiy hdr records all keys for a given key length ============================================================= */ void qaDspIndexListStatsByKey(uint64_t idxKey, int tokenLen) { IdxListStat idxKeyInfo; int execMode = 0; int sbSeqNo = 0; qaSupWalkIndexList(idxKey, tokenLen, execMode, idxKeyInfo); printf("\nINDEX STATS for key: %d\n", (int)idxKey); printf("--------------------------------------\n"); printf("Key: %d\n", (int)idxKeyInfo.hdrRec.key); printf("Hdr Record Count: %d\n", idxKeyInfo.hdrRec.idxRidListSize.size); if (idxKeyInfo.hdrRec.firstIdxRidListEntry.type == 3) printf("RowID 0 : %d\n", idxKeyInfo.hdrRec.firstIdxRidListEntry.rid); if (idxKeyInfo.hdrRec.nextIdxRidListPtr.type == 3) printf("RowID 1 : %d\n", (int)idxKeyInfo.hdrRec.nextIdxRidListPtr.llp); printf("File Block: %d\n", idxKeyInfo.fbo); printf("Sub Block: %d\n", idxKeyInfo.sbid); printf("Entry: %d\n", idxKeyInfo.entry); printf("Actual Row ID Cnt: %d\n", idxKeyInfo.recCnt); printf("Sub Block Cnt: %d\n", idxKeyInfo.sbCnt); printf("Full Sub Block Cnt: %d\n", idxKeyInfo.fullSbCnt); printf("Row ID Cnt Match?: "); if (idxKeyInfo.hdrRec.idxRidListSize.size == idxKeyInfo.recCnt) printf("Yes\n"); else printf("No\n"); } /* ========================================================== Display index record all keys for a given key length ============================================================= */ void qaDspIndexListAll(uint64_t, int tokenLen) { uint64_t i; int maxKey; maxKey = (1 << tokenLen); for (i = 0; i < maxKey; i++) qaDspIndexListByKey(i, tokenLen); } /* ========================================================== Display index record for a given key ============================================================= */ void qaDspIndexListByKey(uint64_t idxKey, int tokenLen) { IdxListStat idxKeyInfo; int p_fbo, p_sbid, p_entry; int execMode = 1; bool exist; int sbSeqNo = 0; qaSupWalkIndexList(idxKey, tokenLen, execMode, idxKeyInfo); } /* ========================================================== Display test case status header ============================================================= */ void qaDspTestStatusHeader(int testCaseNo, char* testCaseDesc) { printf("\nBEGIN IdxHdrTestCase %d\n", testCaseNo); printf(" Desc: %s\n", testCaseDesc); } /* ========================================================== Display test case status header ============================================================= */ void qaDspTestStatusFooter(int testCaseNo, bool passed) { if (passed) printf(" Status: Passed\n"); else { printf(" Status: Failed -- [**ERROR**]\n"); } printf("END IdxHdrTestCase %d\n", testCaseNo); } /* ========================================================== Populate tree with max key for a given bit length Populate tree row ID for a given bitlength ============================================================= */ void qaSupCreateMaxRowID(uint64_t idxKey, int tokenLen) { int maxKey; int startRowID = 0; maxKey = (1 << tokenLen); qaSupCreateRangeRowID(idxKey, tokenLen, startRowID, maxKey); } // qaSupCreateMaxRowID /* ========================================================== Populate tree with a range of row IDs for a key. ============================================================= */ void qaSupCreateRangeRowID(uint64_t idxKey, int tokenLen, int startRowID, int numOfRowID) { int rc; int i; int maxKey; rc = m_index.dropIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); rc = m_index.createIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); m_index.setUseFreeMgr(true); m_index.setUseListMgr(true); // here is the correct check rc = m_index.openIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); for (i = 0; i < numOfRowID; i++) { rc = m_index.updateIndex(idxKey, tokenLen, startRowID + i); // 1 key, multiple rows, multiple row ids CPPUNIT_ASSERT(rc == NO_ERROR); } m_index.closeIndex(); } // qaSupCreateMaxRowID /* ========================================================== Populate tree with max key for a given bit length Populate tree row ID for a given bitlength ============================================================= */ void qaSupCreateMaxHdrRec(int tokenLen) { int rc; uint64_t i; int maxKey; rc = m_index.dropIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); rc = m_index.createIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); m_index.setUseFreeMgr(true); m_index.setUseListMgr(true); // here is the correct check rc = m_index.openIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); maxKey = (1 << tokenLen); if (maxKey > 160) maxKey = 160; for (i = 0; i < maxKey; i++) rc = m_index.updateIndex(i, tokenLen, i); // 1 row id per key. m_index.closeIndex(); } // qaSupCreateMaxHdrRec /* ========================================================== Populate tree with range of keys ============================================================= */ void qaSupCreateRangeKey(uint64_t idxKey, int tokenLen, int startKey, int numOfKey) { int rc; uint64_t i; int maxKey; rc = m_index.dropIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); rc = m_index.createIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); m_index.setUseFreeMgr(true); m_index.setUseListMgr(true); // here is the correct check rc = m_index.openIndex(990, 991); CPPUNIT_ASSERT(rc == NO_ERROR); for (i = startKey; i < startKey + numOfKey; i++) rc = m_index.updateIndex(i, tokenLen, i); // 1 row id per key. m_index.closeIndex(); } // qaSupCreateRangeKey /******************************************************* . This function navigate through the index list record. few global variables are set relating to index list. *******************************************************/ void qaSupWalkIndexList(uint64_t idxKey, int tokenLen, int execMode, IdxListStat& idxKeyInfo) { DataBlock indexBlock; FILE* pFileIndexList = NULL; int file_indexList = 991; int p_fbo, p_sbid, p_entry; int i, ; int SBRecCnt; bool endOfList; bool exist; int tempExecMode; IdxRidListEntry listEntry; IdxRidListPtr listPtr; IdxRidListHdr indexListHdrRec; // Free Manager m_indexlist.setUseFreeMgr(true); tempExecMode = execMode; execMode = 0; qaSupWalkIndexTree(idxKey, tokenLen, execMode, p_fbo, p_sbid, p_entry, exist); execMode = tempExecMode; idxKeyInfo.fbo = p_fbo; // Save the address for the header idxKeyInfo.sbid = p_sbid; idxKeyInfo.entry = p_entry; if (not exist) printf("Tree node not found: Key = %d\n", (int)idxKey); else { // read index list header record i = 0; idxKeyInfo.sbCnt = 0; idxKeyInfo.fullSbCnt = 0; idxKeyInfo.recCnt = 0; // first entry in the hdr endOfList = false; memset(indexBlock.data, 0, sizeof(indexBlock.data)); pFileIndexList = m_indexlist.openFile(file_indexList); CPPUNIT_ASSERT(pFileIndexList != NULL); m_indexlist.readSubBlockEntry(pFileIndexList, &indexBlock, p_fbo, p_sbid, p_entry, 32, &indexListHdrRec); idxKeyInfo.hdrRec = indexListHdrRec; if (execMode == 1) { printf("\n---------------------------------\n"); printf("Index record for key: %d\n", (int)idxKey); printf("---------------------------------\n"); printf("Size: %d\n", (int)indexListHdrRec.idxRidListSize.size); printf("Key: %d\n", (int)indexListHdrRec.key); printf("RowID 1: %d Type: %d\n", (int)indexListHdrRec.firstIdxRidListEntry.rid, (int)indexListHdrRec.firstIdxRidListEntry.type); if (indexListHdrRec.nextIdxRidListPtr.type == 3) printf("RowID 2: %d Type: %d\\nn", (int)indexListHdrRec.nextIdxRidListPtr.llp, (int)indexListHdrRec.nextIdxRidListPtr.type); else if (indexListHdrRec.nextIdxRidListPtr.type == 4) printf("Ptr: Addr(%d, %d, %d) Type = %d\n\n", (int)((IdxEmptyListEntry*)&(indexListHdrRec.nextIdxRidListPtr))->fbo, (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 < group[groupIdx]; i++) { m_indexlist.readSubBlockEntry(pFile, &curBlock, p_fbo, p_sbid, p_entry + i, 8, &treeNodeRec); found = (treeNodeRec.bitTest == key1); p_type = treeNodeRec.type; // printf("key1: %d bitTest: %d\n", key1, treeNodeRec.bitTest); if (found) i = group[groupIdx]; }; // m_indexlist.readSubBlockEntry( pFile, &curBlock, p_fbo, p_sbid, p_entry, 8, //&treeNodeRec); p_type = treeNodeRec.type; p_group = treeNodeRec.group; p_bitTest = treeNodeRec.bitTest; p_fbo = treeNodeRec.fbo; p_sbid = treeNodeRec.sbid; p_entry = treeNodeRec.entry; bitCnt = bitCnt - 5; if (execMode == 1) // branch list printf("Level: Type= %d Group= %d BitTest= %d FBO= %d SBID= %d Entry= %d\n", int(p_type), int(p_group), int(p_bitTest), (int)p_fbo, (int)p_sbid, (int)p_entry); } // set global variables so that calling functions can access to the address of the index header record exist = found; fbo = p_fbo; sbid = p_sbid; entry = p_entry; m_indexlist.closeFile(pFile); } // qaSupWalkIndexTree }; CPPUNIT_TEST_SUITE_REGISTRATION(IndexTest); #include #include int main(int argc, char** argv) { CppUnit::TextUi::TestRunner runner; CppUnit::TestFactoryRegistry& registry = CppUnit::TestFactoryRegistry::getRegistry(); runner.addTest(registry.makeTest()); bool wasSuccessful = runner.run("", false); return (wasSuccessful ? 0 : 1); }