/* 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. */ /****************************************************************************************** * $Id: we_freemgr.cpp 4450 2013-01-21 14:13:24Z rdempsey $ * ******************************************************************************************/ /** @file */ #include #include #include #include "we_freemgr.h" using namespace std; namespace WriteEngine { /** * Constructor */ FreeMgr::FreeMgr() { //memset( m_workBlock.data, 0, BYTE_PER_BLOCK ); // use 0 for old style, 1 for new without block list and 2 for new with block list initType = 2; // setDebugLevel( DEBUG_1 ); allowExtend = 1; } /** * Default Destructor */ FreeMgr::~FreeMgr() {} /** * * blank out all stats, set types and groups of null pointers in block zero */ const int FreeMgr::initBlockzero( DataBlock* blockZero) { IdxEmptyListEntry Pointer; uint64_t blankVal = 0; memset(blockZero->data, 0, sizeof(blockZero->data)); nullPtr( &Pointer ); Pointer.type = EMPTY_LIST; Pointer.group = ENTRY_BLK; setSubBlockEntry( blockZero->data, 0, calcPtrOffset(ENTRY_BLK), 8, &Pointer); Pointer.group = ENTRY_32; setSubBlockEntry( blockZero->data, 0, calcPtrOffset(ENTRY_32), 8, &Pointer); Pointer.group = ENTRY_16; setSubBlockEntry( blockZero->data, 0, calcPtrOffset(ENTRY_16), 8, &Pointer); Pointer.group = ENTRY_8; setSubBlockEntry( blockZero->data, 0, calcPtrOffset(ENTRY_8), 8, &Pointer); Pointer.group = ENTRY_4; setSubBlockEntry( blockZero->data, 0, calcPtrOffset(ENTRY_4), 8, &Pointer); Pointer.group = ENTRY_2; setSubBlockEntry( blockZero->data, 0, calcPtrOffset(ENTRY_2), 8, &Pointer); Pointer.group = ENTRY_1; setSubBlockEntry( blockZero->data, 0, calcPtrOffset(ENTRY_1+ENTRY_1), 8, &Pointer); //all stat locations are contiguous and after the pointers in block zero for (int idx = calcStatOffset( ENTRY_1 ); idx < calcStatOffset( ENTRY_32 )+1; idx++) { setSubBlockEntry( blockZero->data, 0, idx, 8, &blankVal); } return NO_ERROR; } const int FreeMgr::init(CommBlock &cb, DataBlock* blockZero, int freemgrType, IdxTreeGroupType chainType, int startBlock, int numberBlocks) { /** * Use this to allocate a group of blocks or sub blocks to a free list * startBlock is fbo NOT lbid * This allows us to use a simple for loop to traverese the full range of blocks * **/ int blkIdx, sbIdx; int rc; IdxEmptyListEntry emptyEntry; // populate the chains with pointer to empty entries FILE* indexFile; indexFile = cb.file.pFile; nullPtr(&emptyEntry); emptyEntry.type = EMPTY_PTR; if( isDebug( DEBUG_3 )) { printf("\nNew style Init v2, file: %u startBlock: %i num: %i \n", cb.file.oid, (unsigned int)startBlock, (unsigned int)numberBlocks); } int lastBlock = numberBlocks + startBlock; if (chainType == ENTRY_BLK) { emptyEntry.group = ENTRY_BLK; for ( blkIdx = lastBlock ; blkIdx > startBlock ; blkIdx-- ) { // if( isDebug( DEBUG_1 )) { printf("Initing block %u\n", blkIdx-1);} emptyEntry.fbo = mapLBID( cb, blkIdx-1, rc );// map fbo to lbid before storage if (rc != NO_ERROR ){ printf("DBG: Init 1: Error resolving LBID for OID: %u FBO: %u\n", cb.file.oid, blkIdx-1 ); return rc; } if( isDebug( DEBUG_3 )) { cout<<"DBG: Working on block "< startBlock ; blkIdx-- ) { // if( isDebug( DEBUG_1 )) { printf("Initing block %u\n", blkIdx-1);} emptyEntry.fbo = mapLBID( cb, blkIdx-1, rc );// map fbo to lbid before storage if (rc != NO_ERROR ){ printf("DBG: Init 2: Error resolving LBID for OID: %u FBO: %u\n", cb.file.oid, blkIdx-1 ); return rc; } if( isDebug( DEBUG_3 )) { cout<<"DBG: Working on block "<-1; sbIdx--) { if( isDebug( DEBUG_3 )) { printf("DBG: Working on subblock %u\n", sbIdx); } emptyEntry.sbid = sbIdx; emptyEntry.type = EMPTY_PTR; rc = releaseSubblock( cb, blockZero, freemgrType, &emptyEntry ); if (rc != NO_ERROR){ printf("Error releasing sb\n"); return rc; } } } } else { if ( isDebug( DEBUG_1 )){ printf("DBG: Invalid segment size %i (should be ENTRY_32 or ENTRY_BLK)\n", chainType); } return ERR_INVALID_PARAM; } // now write sb0 back to disk uint64_t lbid = mapLBID( cb, 0, rc); if (rc != NO_ERROR ){ return rc; } rc = writeDBFile( cb, blockZero, lbid ); if (rc != NO_ERROR) { return rc; } return NO_ERROR; } /*********************************************************** * DESCRIPTION: * Initializes free space lists in an new index file * PARAMETERS: * indexFile - file pointer for new index file * freemgr_type - type of free mgr to init * RETURN: * NO_ERROR if success * ***********************************************************/ const int FreeMgr::init( CommBlock &cb, int freemgrType) { /** * Tree has 6 chains, (1,2,4,8,16,32 entries) starting at entry 1 in sb0 of block0 * List has 3 chains (4,32,1024 entries) starting at first entry of file * * Starting at Block 1, add each subblock after sb0 to the free list in sb0 * then go back and build the smaller chains on demand. This way we make sure all SBs * are in a chain somewhere.. but this is not best behaviour when allocating blocks * **/ int rc; // return code from file ops DataBlock blockZero; DataBlock workBlock; int sbIdx; uint64_t blkIdx; IdxEmptyListEntry emptyEntry; // populate the chains with pointer to empty entries IdxEmptyListEntry nextPointer; // pointer at end of sub-block of pointers to emptyEntries uint64_t numBlocks; FILE* indexFile; indexFile = cb.file.pFile; if (!indexFile) // Make sure that we have non-null filehandle { // printf("DBG: File handle is null\n"); return ERR_INVALID_PARAM; } if (freemgrType!=TREE && freemgrType!=LIST){ // printf("DBG: Bad type in freeMgr Init\n"); return ERR_INVALID_PARAM; } numBlocks = getFileSize( indexFile )/BYTE_PER_BLOCK ; // printf ("DBG: File size: %lu Total blocks: %llu (%u)\n", getFileSize( indexFile ), numBlocks, BYTE_PER_BLOCK); // printf ("DBG: Adding sub-blocks: %llu \n", numBlocks * 32); // Clear the list of pointers in sb0 initBlockzero( &blockZero ); // initialize the non varying fields nullPtr(&emptyEntry); emptyEntry.type = EMPTY_PTR; emptyEntry.group = ENTRY_32; // nextPointer identifies next sub-block with empty pointers // initially there is no next sub-block so zero it out nullPtr(&nextPointer); nextPointer.type = EMPTY_LIST; nextPointer.group = ENTRY_32; nextPointer.entry = ENTRY_PER_SUBBLOCK-1; // last entry on the list.. think of the list as a stack if (initType == 0){ if( isDebug( DEBUG_3 )) { printf("\nOld style init\n"); } for ( blkIdx = numBlocks-1; blkIdx > 0; blkIdx-- ) { emptyEntry.fbo = blkIdx;// map fbo to lbid before storage // emptyEntry.fbo = mapLBID( cb, blkIdx, rc );// map fbo to lbid before storage // if (rc != NO_ERROR ){ printf("DBG: Error resolving LBID for OID: %u FBO: %llu\n", cb.file.oid, blkIdx-1 ); return rc; } if( isDebug( DEBUG_3 )) { cout<<"DBG: Working on block "< 0; blkIdx-- ) { emptyEntry.fbo = blkIdx;// map fbo to lbid before storage // emptyEntry.fbo = mapLBID( cb, blkIdx, rc );// map fbo to lbid before storage // if (rc != NO_ERROR ){ printf("DBG: Error resolving LBID for OID: %u FBO: %llu\n", cb.file.oid, blkIdx-1 ); return rc; } if( isDebug( DEBUG_3 )) { cout<<"DBG: Working on block "<-1; sbIdx--) { if( isDebug( DEBUG_3 )) { printf("DBG: Working on subblock %u\n", sbIdx); } emptyEntry.sbid = sbIdx; emptyEntry.type = EMPTY_PTR; // store pointer in sb0 - replace this with a releaseSubblock call rc = releaseSubblock( cb, &blockZero, freemgrType, &emptyEntry ); if (rc != NO_ERROR){ printf("Error releasing sb\n"); return rc; } } } /** * the next algorithm uses the release sub-block method and does not layout the map on particular boundaries. * It also allows pieces to be allocated **/ } else if (initType == 2){ /** The following calls to init accept FBO not LBID.. * This makes it easier to work on a range of blocks **/ // use the first block of the new range for sub-block chain // and the rest for block chain rc = init( cb, &blockZero, freemgrType, ENTRY_32, 1, 50); if ( rc != NO_ERROR ) { return rc; } rc = init( cb, &blockZero, freemgrType, ENTRY_BLK, 51, numBlocks-52); if ( rc != NO_ERROR ) { return rc; } } // now write sb0 back to disk if ( isDebug( DEBUG_2 )) { printf("Writing SB0 back to disk\n"); printMemSubBlock( &blockZero, 0 ); } uint64_t lbid = mapLBID( cb, 0, rc); if (rc != NO_ERROR ){ return rc; } rc = writeDBFile( cb, blockZero.data, lbid ); if (rc != NO_ERROR) { return rc; } return NO_ERROR; } /** * DESCRIPTION: * Assign segment- public method used to get a free segment for use * PARAMETERS: * indexFile - file pointer * blockZero - in memory copy of blockZero * freemgr_type - either TREE or LIST * segmentType - group type * assignPtr - the assigned ptr * * RETURN: * NO_ERROR if success * error no if fail **/ const int FreeMgr::assignSegment( CommBlock &cb, DataBlock* blockZero, const int freemgr_type, const IdxTreeGroupType segmentType, IdxEmptyListEntry* assignPtr ) { int rc; // return code from file ops DataBlock workBlock; int listOffset; // entry in block zero of head pointer IdxEmptyListEntry emptyEntry; IdxEmptyListEntry emptyPtr; IdxEmptyListEntry emptyMap; uint64_t numBlocks; IdxEmptyListEntry newSb; FILE* indexFile; indexFile = cb.file.pFile; if( isDebug( DEBUG_3 )) { printf("DBG: Assign ENTRY_%i segment in %s\n", 1<<(unsigned int)segmentType,(freemgr_type==LIST)?"LIST":"TREE"); } /* Check all input parameters are ok */ if (!blockZero){ if( isDebug( DEBUG_1 )) { printf ("DBG: Bad pointer: blockZero is zero\n"); } return ERR_INVALID_PARAM; } if (!assignPtr) { if( isDebug( DEBUG_1 )) { printf ("DBG: Bad pointer: assignPtr is zero\n"); } return ERR_INVALID_PARAM; } if (freemgr_type != TREE && freemgr_type!= LIST) { if( isDebug( DEBUG_0 )) { printf ("DBG: assignSegment: Must be TREE or LIST\n");} return ERR_INVALID_PARAM; } numBlocks = getFileSize( indexFile )/BYTE_PER_BLOCK ; //find the start of the chain if (segmentType == ENTRY_32) { rc = assignSubblock( cb, blockZero, freemgr_type, assignPtr); if (rc != NO_ERROR) { if( isDebug( DEBUG_1 )) { printf("DBG: Error assigning sb (rc=%i)\n", rc); } } return rc; } listOffset = calcPtrOffset( segmentType ); if (freemgr_type==LIST && !(segmentType== ENTRY_4 || segmentType== ENTRY_BLK)) { if( isDebug( DEBUG_1 )) { printf("DBG: Assign segment size illegal %i\n", (unsigned int)segmentType); } return ERR_INVALID_PARAM; // should not have got here so quit with error } // read Empty Map in sb0 getSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr ); if( isDebug( DEBUG_2 )) { cout<<"DBG: Empty map ENTRY_"<<(1< numBlocks) { printf("DBG: Weirdness in assignSegment.. emptyPtr.fbo > numBlocks\n"); return ERR_FM_BAD_FBO; }*/ // check to see if queue has been built // if not then assign a container block, add LLP in entry 0 pointing to nothing if (emptyPtr.fbo == 0){ if( isDebug( DEBUG_3 )) { printf("DBG: Need to add sb to chain and entries to sb\n"); } // cannot assign more space to block list from a smaller list.. need to extend the file if ( segmentType == ENTRY_BLK ) { if ( isDebug( DEBUG_1 )){ printf("Out of space in BLOCK list, quitting\n"); } rc = extendFreespace( cb, blockZero, freemgr_type ); if (rc != NO_ERROR){ if (isDebug( DEBUG_3 )){ printf("DBG: Error extending file\n"); } return rc; } } rc = assignSubblock( cb, blockZero, freemgr_type, &emptyPtr); if (rc != NO_ERROR){ printf("DBG: Error extending chain\n"); return rc; } rc = readDBFile( cb, workBlock.data, emptyPtr.fbo ); if (rc != NO_ERROR){ /*printf("DBG: Error reading newly allocated sb\n");*/ return rc; } // update map to point to new bucket setSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr); nullPtr(&emptyEntry); emptyEntry.type = EMPTY_LIST; emptyEntry.group = segmentType; setSubBlockEntry( workBlock.data, emptyPtr.sbid, 0, 8, &emptyEntry); // store head ptr rc = writeDBFile( cb, workBlock.data, emptyPtr.fbo ); if (rc != NO_ERROR){ return rc; } if( isDebug( DEBUG_2 )) { cout<<"DBG: Added fbo "<dirty = 1; setSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr ); if( isDebug( DEBUG_3 )) { printf("DBG: Empty entry is now %u\n",(unsigned int)emptyPtr.entry); } if( isDebug( DEBUG_2 )) { cout<<"DBG: Assigned fbo "< numBlocks) // { // if( isDebug( DEBUG_1 )) { printf("DBG: Weirdness in assignSubblock.. emptyPtr.fbo > numBlocks\n"); } // return ERR_FM_BAD_FBO; // } // follow the chain to the empty entry rc = readDBFile( cb, workBlock.data, emptyPtr.fbo ); if (rc != NO_ERROR) { // printf("DBG: RC Weirdness: rc is %i", rc); return rc; } getSubBlockEntry( &workBlock, emptyPtr.sbid, emptyPtr.entry, 8, &emptyEntry ); if( isDebug( DEBUG_2 )) { cout<<"DBG: Next avail sb fbo "<0; sbIdx--) { if( isDebug( DEBUG_3 )) { cout<<"DBG: Working on fbo "<0) printf("\nWTF!! %i\n", (unsigned int) emptyPtr.entry); // reached end of this bucket (should release it for re-use) // this is not the typical case.. if( isDebug( DEBUG_3 )) { cout<<"DBG: Drained bucket sb fbo "<type = EMPTY_PTR; if( isDebug( DEBUG_2 )) { cout<<"DBG: Change head pointer to fbo "<fbo, (unsigned int)assignPtr->sbid, (unsigned int)assignPtr->entry); getSubBlockEntry( blockZero, 0, listOffset, 8, &emptyMap ); if(isDebug(DEBUG_3)){ cout<<"DBG: EM (sb assign 1) sb fbo "<dirty = 1; uint64_t count; getSubBlockEntry( blockZero, 0, calcStatOffset(ENTRY_32) , 8, &count ); count--; setSubBlockEntry( blockZero, 0, calcStatOffset(ENTRY_32) , 8, &count ); // -- workblock may have changed on disk since it was read.. making the writeDBfile dangerous without a readDBfile first nullPtr(&emptyMap); // zero out the entry readDBFile( cb, &workBlock, emptyPtr.fbo ); setSubBlockEntry( workBlock.data, emptyPtr.sbid, emptyPtr.entry+1, 8, &emptyMap ); rc = writeDBFile( cb, &workBlock, emptyPtr.fbo ); // -- // if( isDebug( DEBUG_3 )) { printf("DBG: Assign subblock -- all done\n"); } return NO_ERROR; } /** * DESCRIPTION: * Release a segment back to the list * PARAMETERS: * indexFile - file pointer * blockZero - in memory copy of blockZero * freemgr_type - either TREE or LIST * segmentType - group type * assignPtr - the assigned ptr * * RETURN: * NO_ERROR if success * error no if fail **/ const int FreeMgr::releaseSegment( CommBlock &cb, DataBlock* blockZero, const int freemgr_type, const IdxTreeGroupType segmentType, IdxEmptyListEntry* assignPtr ) { int rc; // return code from file ops DataBlock workBlock; DataBlock extraBlock; int listOffset; // entry in block zero of head pointer IdxEmptyListEntry emptyPtr; IdxEmptyListEntry newSb; uint64_t numBlocks; FILE* indexFile; indexFile = cb.file.pFile; if (!assignPtr){ // printf ("DBG: Bad pointer: assignPtr is zero\n"); return ERR_INVALID_PARAM; } if (!blockZero){ // printf ("DBG: Bad pointer: blockZero is zero\n"); return ERR_INVALID_PARAM; } if( isDebug( DEBUG_3 )) { printf("DBG: release ENTRY_%i segment \n", 1<<(unsigned int)segmentType); } if( isDebug( DEBUG_2 )) { cout<<"DBG: releasing fbo "<fbo<<" sbid "<sbid<<" entry "<entry<<" from "<<((freemgr_type==LIST)?"LIST":"TREE")<<" chain ENTRY_"<<(1<type==EMPTY_PTR)?"EMPTY_PTR":"Not EMPTY_PTR")<<")\n"; } numBlocks = getFileSize( indexFile )/BYTE_PER_BLOCK ; /* if (assignPtr->fbo > numBlocks) { if( isDebug( DEBUG_1 )) { printf("DBG: Weirdness in releaseSegment.. assignPtr.fbo > numBlocks (%llu %llu)\n", assignPtr->fbo, numBlocks );}; return ERR_FM_BAD_FBO; }*/ if (assignPtr->type != EMPTY_PTR) { // printf("DBG: Weirdness in releaseSegment.. tried to return a pointer with type %i (expected %i)\n", (unsigned int)assignPtr->type, EMPTY_PTR ); assignPtr->type = EMPTY_PTR; // return ERR_FM_BAD_TYPE; // do not exit } if ( assignPtr->group != (uint64_t)segmentType ) { // printf("DBG: Weirdness in releaseSegment.. tried to return a pointer from group %i to group %i\n", (unsigned int)assignPtr->group, segmentType ); return ERR_FM_RELEASE_ERR; } //find the start of the chain if (segmentType == ENTRY_32) { rc = releaseSubblock( cb, blockZero, freemgr_type, assignPtr); if (rc != NO_ERROR) { // printf("DBG: Error releasing sb\n"); } return rc; } listOffset = calcPtrOffset( segmentType ); if (freemgr_type==LIST && !(segmentType== ENTRY_4 || segmentType== ENTRY_BLK)) { printf("DBG: Assign segment size illegal %i\n", (unsigned int)segmentType); return ERR_INVALID_PARAM; // should not have got here so quit with error } getSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr ); /* if (emptyPtr.fbo > numBlocks) { if( isDebug( DEBUG_1 )) { printf("DBG: Weirdness in releaseSegment.. emptyPtr.fbo > numBlocks (%llu %llu)\n", emptyPtr.fbo, numBlocks );} return ERR_FM_BAD_FBO; }*/ //sub block is full or chain never started if (emptyPtr.entry == ENTRY_PER_SUBBLOCK-1 || emptyPtr.fbo==0) { if( isDebug( DEBUG_3 )) { printf("DBG: No room in chain %i - need to add a sub-block\n", (unsigned int)segmentType); } if( isDebug( DEBUG_2 )) { cout<<"DBG: Empty ptr fbo "<dirty = 1; uint64_t count; getSubBlockEntry( blockZero, 0, calcStatOffset(segmentType) , 8, &count ); count++; setSubBlockEntry( blockZero, 0, calcStatOffset(segmentType) , 8, &count ); return NO_ERROR ; } else { // emptyPtr.entry++; rc = readDBFile( cb, workBlock.data, emptyPtr.fbo ); if (rc != NO_ERROR){ if (isDebug( DEBUG_1 )){ printf("DBG: File error during releaseSegment\n"); } return rc; } if( isDebug( DEBUG_2 )) { cout<<"DBG: Empty map ENTRY_"<<( 1<dirty = 1;//sub block is full or chain never started } uint64_t count; getSubBlockEntry( blockZero, 0, calcStatOffset(segmentType) , 8, &count ); count++; setSubBlockEntry( blockZero, 0, calcStatOffset(segmentType) , 8, &count ); return NO_ERROR; } const int FreeMgr::releaseSubblock( CommBlock &cb, DataBlock* blockZero, const int freemgr_type, IdxEmptyListEntry* assignPtr ) { int rc; // return code from file ops DataBlock workBlock; DataBlock extraBlock; int listOffset; // entry in block zero of head pointer IdxEmptyListEntry emptyPtr, emptyMap ; uint64_t numBlocks; FILE* indexFile; indexFile = cb.file.pFile; /** * Release sub-block - handle de-allocation of only sub-blocks * This makes the assign/release code for smaller segments simpler and * separates the tasks of handling the list containers and the list contents * When called, we look at the bucket indicated as head of chain and if it full * or not present (no room left in chain) then insert the returned SB as a bucket and * move the head pointer **/ //if( isDebug( DEBUG_1 )) { printf("DBG: releaseSubblock\n"); } if( isDebug( DEBUG_2 )) { cout<<"DBG: releasing sb fbo "<fbo<<" sbid "<sbid<<" entry "<entry<<" from "<<((freemgr_type==LIST)?"LIST":"TREE")<<" (type is "<<((assignPtr->type==EMPTY_PTR)?"EMPTY_PTR":"Not EMPTY_PTR")<<")\n"; } if (!assignPtr){ // printf ("DBG: Bad pointer: assignPtr is zero\n"); return ERR_INVALID_PARAM; } if (!blockZero){ printf ("DBG: Bad pointer: pointer for blockZero is zero\n"); return ERR_INVALID_PARAM; } numBlocks = getFileSize( indexFile )/BYTE_PER_BLOCK ; /* if (assignPtr->fbo > numBlocks) { if( isDebug( DEBUG_1 )) { printf("DBG: Weirdness in releaseSubblock.. assignPtr.fbo > numBlocks (%llu %llu)\n", assignPtr->fbo, numBlocks );} return ERR_FM_BAD_FBO; }*/ if (assignPtr->type != EMPTY_PTR) { printf("DBG: Weirdness in releaseSubblock.. tried to return a pointer with type %i (expected %i)\n", (unsigned int)assignPtr->type, EMPTY_PTR ); return ERR_FM_BAD_TYPE; } if ( assignPtr->group != ENTRY_32 ) { printf("DBG: Weirdness in releaseSubblock.. tried to return a pointer from group %i to subblock group\n", (unsigned int)assignPtr->group ); return ERR_INVALID_PARAM; } //find the start of the chain listOffset = calcPtrOffset( ENTRY_32 ); getSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr ); if( isDebug( DEBUG_2 )) { cout<<"DBG: EM (sb release 1) sb fbo "<type = EMPTY_LIST; //if( isDebug( DEBUG_1 )) { printf("DBG: No room in subblock chain - need to add a sub-block\n"); } if( isDebug( DEBUG_2 )) { cout<<"DBG: Change head pointer to fbo "<fbo<<" sbid "<sbid<<" entry "<entry<<"\n"; } // change head pointer to released segment setSubBlockEntry( blockZero, 0, listOffset, 8, assignPtr ); blockZero->dirty = 1; // read in released segment to set llp of new block to point to current head of chain rc = readDBFile( cb, extraBlock.data, assignPtr->fbo ); if (rc != NO_ERROR){ if (isDebug( DEBUG_1 )){ cout<<"DBG: File error during releaseSegment (2), rc: "<fbo<<"\n"; } return rc; } if( isDebug( DEBUG_2 )) { cout<<"DBG: Set LLP for fbo "<fbo<<" sbid "<sbid<<" entry "<entry<<"to fbo "<sbid ); } emptyPtr.type = EMPTY_LIST; //memset( extraBlock.data, 0, BYTE_PER_SUBBLOCK); setSubBlockEntry( extraBlock.data, assignPtr->sbid, 0, 8, &emptyPtr ); rc = writeDBFile( cb, &extraBlock, assignPtr->fbo ); if (rc != NO_ERROR){ return rc; } if( isDebug( DEBUG_2 )) { getSubBlockEntry( blockZero, 0, listOffset, 8, &emptyMap ); cout<<"DBG: EM (sb release 2) sb fbo "<sbid ); } } else { // emptyPtr.entry++; rc = readDBFile( cb, workBlock.data, emptyPtr.fbo ); if (rc != NO_ERROR) { if (isDebug( DEBUG_1 )) { printf("DBG: File error during releaseSubblock\n"); } return rc; } if( isDebug( DEBUG_3)){ printf("Before\n"); printMemSubBlock( &workBlock, emptyPtr.sbid ); } setSubBlockEntry( workBlock.data, emptyPtr.sbid, emptyPtr.entry, 8, assignPtr ); rc = writeDBFile( cb, &workBlock, emptyPtr.fbo ); if (rc != NO_ERROR){ return rc; } if( isDebug( DEBUG_2 )) { cout<<"DBG: setting emptyPtr sb fbo "<dirty = 1; } uint64_t count; getSubBlockEntry( blockZero, 0, calcStatOffset(ENTRY_32) , 8, &count ); count++; setSubBlockEntry( blockZero, 0, calcStatOffset(ENTRY_32) , 8, &count ); return NO_ERROR; } const void FreeMgr::nullPtr(WriteEngine::IdxEmptyListEntry* assignPtr ) const { assignPtr->fbo = 0; assignPtr->sbid = 0; assignPtr->entry = 0; assignPtr->type = 0; assignPtr->group = 0; assignPtr->spare = 0; assignPtr->spare2 = 0; } /** * extendFreeSpace - Having reached the end of the available freespace or exhausted the block/subblock chain * add extra space by extending the file and calling the Init function for the new space * * @param indexFile * @param blockZero * @param freemgrType * @return */ const int FreeMgr::extendFreespace( CommBlock &cb, DataBlock* blockZero, int freemgrType ) { DataBlock workBlock; int rc = NO_ERROR; // result code from file ops FILE* indexFile; int allocSize = 0; indexFile = cb.file.pFile; if( isDebug( DEBUG_1 )){ printf ("Extending File\n");} int numBlocks = 1024; // default number - should ask BRM for extentsize int currSize = getFileSize( indexFile )/BYTE_PER_BLOCK ; if (!allowExtend){ if( isDebug( DEBUG_1 )){ printf("DBG: Extension denied\n");} return ERR_FM_EXTEND; } if( isDebug( DEBUG_1 )){ printf("DBG: Extending free space in file\n"); } if( isDebug( DEBUG_1 )){ printf("DBG: File is currently: %i blocks Asking for: %i blocks\n", currSize, numBlocks); } #ifdef BROKEN_BY_MULTIPLE_FILES_PER_OID rc = extendFile( indexFile, cb.file.oid, numBlocks, allocSize, 0, 8, false ); #endif if (rc != NO_ERROR) { return rc; } if( isDebug( DEBUG_1 )){ printf("DBG: Extended file by %i blocks\n", allocSize); } rc = init( cb, blockZero, freemgrType, ENTRY_32, currSize, 50 ); if ( rc != NO_ERROR ) { return rc; } rc = init( cb, blockZero, freemgrType, ENTRY_BLK, currSize +50, allocSize-50 ); if ( rc != NO_ERROR ) { return rc; } return NO_ERROR; } /** * Quick utility function to map LBID if BRM in use, return original FBO otherwise * @param cb * @param fbo * @return */ const uint64_t FreeMgr::mapLBID( CommBlock &cb, const uint64_t fbo, int &rc ) { uint64_t lbid = 0; rc = NO_ERROR; #ifdef BROKEN_BY_MULTIPLE_FILES_PER_OID rc = BRMWrapper::getInstance()->getBrmInfo( cb.file.oid, fbo, lbid ); #endif if (rc != NO_ERROR) { if (isDebug( DEBUG_0 )) { cout<<"BRM Failure looking up lbid for oid: "<data + BYTE_PER_SUBBLOCK * sbid; printf( "\n======================== sbid: %i", sbid ); for( int i = 0; i < ENTRY_PER_SUBBLOCK; i++ ) { memcpy( &curEntry, curPos, MAX_COLUMN_BOUNDARY ); off = memcmp( &testZero, &curEntry, MAX_COLUMN_BOUNDARY ); // if( /*bNoZero &&*/ off == 0 ) // continue; printf( "\n Entry %2d : ", i ); for( int j = 0; j < MAX_COLUMN_BOUNDARY; j++ ) printf( " %2X", *(curPos + j) ); cout<<" fbo="<