mirror of
https://github.com/mariadb-corporation/mariadb-columnstore-engine.git
synced 2025-04-21 19:45:56 +03:00
1265 lines
50 KiB
C++
1265 lines
50 KiB
C++
/* 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <iostream>
|
|
#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 "<<emptyEntry.fbo<<"\n"; }
|
|
|
|
emptyEntry.sbid = 0;
|
|
emptyEntry.type = EMPTY_PTR;
|
|
rc = releaseSegment( cb, blockZero, freemgrType, chainType, &emptyEntry );
|
|
if (rc != NO_ERROR){ printf("Error releasing sb\n"); return rc; }
|
|
}
|
|
|
|
} else if (chainType == ENTRY_32 ){
|
|
|
|
emptyEntry.group = ENTRY_32;
|
|
|
|
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 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 "<<emptyEntry.fbo<<"\n"; }
|
|
|
|
for (sbIdx=BYTE_PER_BLOCK/BYTE_PER_SUBBLOCK-1; sbIdx >-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 "<<emptyEntry.fbo<<"\n"; }
|
|
memset(workBlock.data, 0, sizeof(workBlock.data));
|
|
|
|
/**
|
|
* each block after zeroth block uses sb0 to store entry list
|
|
* first entry (#0) is the llp to additional sblks with entries
|
|
* entries 1-31 are pointers
|
|
**/
|
|
|
|
// sb0 is used for initial map, so start at sb1
|
|
for (sbIdx=1; sbIdx < BYTE_PER_BLOCK/BYTE_PER_SUBBLOCK; 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
|
|
setSubBlockEntry( workBlock.data, 0, sbIdx, 8, &emptyEntry);
|
|
if( isDebug( DEBUG_2 )) {
|
|
cout<<"DBG: Init sb fbo "<<emptyEntry.fbo<<" sbid "<<emptyEntry.sbid<<" entry "<<emptyEntry.entry<<"\n";
|
|
}
|
|
}
|
|
// having stored all pointers, store linkptr
|
|
setSubBlockEntry( workBlock.data, 0, 0, 8, &nextPointer);
|
|
// nextPointer.fbo = mapLBID( cb, blkIdx, rc ); // remember this block ID
|
|
nextPointer.fbo = blkIdx; // remember this block ID
|
|
// if (rc != NO_ERROR ){ printf("DBG: Error resolving LBID for OID: %u FBO: %llu\n", cb.file.oid, blkIdx-1 ); return rc; }
|
|
|
|
rc = writeDBFile( cb, workBlock.data, emptyEntry.fbo );
|
|
if (rc != NO_ERROR){ return rc; }
|
|
|
|
}
|
|
|
|
// chain for segments of sub block size
|
|
setSubBlockEntry( blockZero.data, 0, calcPtrOffset(ENTRY_32), 8, &nextPointer);
|
|
|
|
/**
|
|
* the next algorithm uses the release sub-block method and does not layout the map on particular boundaries.
|
|
**/
|
|
|
|
} else if (initType == 1) { // new style - use release
|
|
if( isDebug( DEBUG_3 )) { printf("\nNew style\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 "<<emptyEntry.fbo<<"\n"; }
|
|
memset(workBlock.data, 0, sizeof(workBlock.data));
|
|
|
|
for (sbIdx=BYTE_PER_BLOCK/BYTE_PER_SUBBLOCK-1; sbIdx >-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<<segmentType)<<" was fbo "<<emptyPtr.fbo<<" sbid "<<(unsigned int)emptyPtr.sbid<<" entry "<<(unsigned int)emptyPtr.entry<<"\n";
|
|
}
|
|
|
|
/* if (emptyPtr.fbo > 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 "<<emptyPtr.fbo<<" sbid "<<(unsigned int)emptyPtr.sbid<<" as bucket to chain ENTRY_"<<(1<<segmentType)<<"in"<<((freemgr_type==LIST)?"LIST":"TREE")<<"\n";
|
|
}
|
|
}
|
|
|
|
// follow the chain to the head container
|
|
rc = readDBFile( cb, workBlock.data, emptyPtr.fbo );
|
|
if (rc != NO_ERROR)
|
|
{
|
|
if( isDebug( DEBUG_1 )) { cout<<"DBG: Error reading block ("<<emptyPtr.fbo<<") during segmentAssign: rc is "<<rc; }
|
|
return rc;
|
|
}
|
|
|
|
getSubBlockEntry( &workBlock, emptyPtr.sbid, emptyPtr.entry, 8, &emptyEntry );
|
|
|
|
if ((emptyEntry.type != EMPTY_LIST) && (emptyEntry.type != EMPTY_PTR))
|
|
{
|
|
if( isDebug( DEBUG_0 )) {
|
|
printf("WTF: Bad entry in ENTRY_%i chain - type is %i (expected %i or %i)\n", 1<<segmentType, (unsigned int)emptyEntry.type, EMPTY_PTR, EMPTY_LIST );
|
|
printMemSubBlock( &workBlock, emptyPtr.sbid );
|
|
}
|
|
if( isDebug( DEBUG_2 )) {
|
|
cout<<"DBG: fbo "<<emptyEntry.fbo<<" sbid "<<(unsigned int)emptyEntry.sbid<<" entry "<< (unsigned int)emptyEntry.entry<<" chain ENTRY_"<<(1<<segmentType)<<"in"<<((freemgr_type==LIST)?"LIST":"TREE")<<"\n";
|
|
}
|
|
|
|
return ERR_FM_BAD_TYPE;
|
|
}
|
|
|
|
if ((emptyEntry.fbo == 0) && (emptyEntry.type == EMPTY_PTR))
|
|
{
|
|
if ( isDebug( DEBUG_0 )) {printf("DBG: Bad entry in %i list - found EMPTY_PTR but indicates block 0\n", 1<<segmentType );}
|
|
return ERR_FM_BAD_TYPE;
|
|
}
|
|
|
|
if ((emptyEntry.fbo == 0) && (emptyEntry.type == EMPTY_LIST))
|
|
{
|
|
/**
|
|
* if at the end of the rainbow, in a bucket with no entries, fill the bucket
|
|
* Allocate a sub block and split it into parts
|
|
**/
|
|
|
|
// 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("\nNeed to extend block\n");}
|
|
if ( isDebug( DEBUG_1 )){ printf("Out of space in BLOCK list\n"); }
|
|
rc = extendFreespace( cb, blockZero, freemgr_type );
|
|
if (rc != NO_ERROR){
|
|
if (isDebug( DEBUG_3 )){ printf("DBG: Error extending file\n"); }
|
|
return rc;
|
|
}
|
|
getSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr );
|
|
rc = readDBFile( cb, workBlock.data, emptyPtr.fbo );
|
|
getSubBlockEntry( &workBlock, emptyPtr.sbid, emptyPtr.entry, 8, &emptyEntry );
|
|
|
|
} else {
|
|
|
|
rc = assignSubblock( cb, blockZero, freemgr_type, &newSb);
|
|
if (rc != NO_ERROR){
|
|
// printf("DBG: Error extending chain\n");
|
|
return rc;
|
|
}
|
|
if (newSb.entry != 0){
|
|
printf("WTF: Entry should be 0 after assign from sb list, instead is %i", (unsigned int)newSb.entry);
|
|
return ERR_FM_ASSIGN_ERR;
|
|
}
|
|
if (isDebug(DEBUG_2)){
|
|
cout<<"DBG: added fbo "<<newSb.fbo<<" sbid "<<(unsigned int)newSb.sbid<<" entry "<<(unsigned) newSb.entry<<" to "<<segmentType<<" list - need to split "<<(1<<(ENTRY_32-segmentType))<<"times\n";
|
|
}
|
|
|
|
newSb.entry = 0;
|
|
newSb.group = segmentType;
|
|
newSb.type = EMPTY_PTR;
|
|
emptyEntry = newSb;
|
|
|
|
int idx, inc;
|
|
inc = 1<<segmentType;
|
|
for (idx=0; idx < ENTRY_PER_SUBBLOCK - inc; idx+= inc){
|
|
if( isDebug( DEBUG_3 )) { printf ("DBG: split..%i-%i\n", idx, idx+inc-1 );}
|
|
newSb.entry = idx;
|
|
releaseSegment( cb, blockZero, freemgr_type, segmentType, &newSb );
|
|
}
|
|
emptyEntry.entry = idx;
|
|
if( isDebug( DEBUG_3 ))
|
|
{
|
|
printf ("DBG: split and return..%i-%i\n", idx, idx+inc-1);
|
|
}
|
|
if( isDebug( DEBUG_2 ))
|
|
{
|
|
cout<<"DBG: Assigned fbo "<< emptyEntry.fbo<<" sbid "<<(unsigned int)emptyEntry.sbid<<" entry "<<(unsigned int)emptyEntry.entry<<" to chain ENTRY_"<<(1<<segmentType)<<"\n";
|
|
}
|
|
memcpy(assignPtr, &emptyEntry, 8);
|
|
|
|
uint64_t count;
|
|
getSubBlockEntry( blockZero, 0, calcStatOffset(segmentType) , 8, &count );
|
|
count--;
|
|
setSubBlockEntry( blockZero, 0, calcStatOffset(segmentType) , 8, &count );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
}
|
|
/**
|
|
* got here because we didn't need to populate a chain and did not fall into any traps
|
|
* so either we are at the end of bucket or we have a valid entry
|
|
**/
|
|
if (emptyEntry.type == EMPTY_LIST) // reached end of this segment (should release it for re-use)
|
|
{
|
|
/**
|
|
* release bucket
|
|
**/
|
|
if( isDebug( DEBUG_2 )) {
|
|
cout<<"DBG: Need to release sb fbo "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" from chain ENTRY_"<<(1<<segmentType)<<" in "<<((freemgr_type==LIST)?"LIST":"TREE")<<"\n";
|
|
}
|
|
// when we stored the ptr in the empty map, we tweaked group, must change it back
|
|
emptyPtr.type = EMPTY_PTR;
|
|
emptyPtr.group = ENTRY_32;
|
|
rc = releaseSubblock( cb, blockZero, freemgr_type, &emptyPtr );
|
|
if (rc != NO_ERROR)
|
|
{
|
|
printf("Error releasing sb\n");
|
|
return rc;
|
|
}
|
|
emptyPtr = emptyEntry;
|
|
rc = readDBFile( cb, workBlock.data, emptyPtr.fbo );
|
|
|
|
if (rc != NO_ERROR){
|
|
printf("DBG: Error following chain\n");
|
|
return rc;
|
|
}
|
|
getSubBlockEntry( &workBlock, emptyPtr.sbid, emptyPtr.entry, 8, &emptyEntry );
|
|
|
|
}
|
|
|
|
if (emptyEntry.type == EMPTY_PTR)
|
|
{
|
|
|
|
emptyPtr.entry--;
|
|
blockZero->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 "<<emptyEntry.fbo<<" sbid "<<emptyEntry.sbid<<" entry "<<emptyEntry.entry<<" from chain ENTRY_"<<(1<<segmentType)<<"\n";
|
|
cout<<"DBG: Empty map ENTRY_"<<(1<<segmentType)<<" now fbo "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" entry "<<emptyPtr.entry<<"\n";
|
|
}
|
|
memcpy(assignPtr, &emptyEntry, 8);
|
|
|
|
// -- 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 );
|
|
// --
|
|
|
|
uint64_t count;
|
|
getSubBlockEntry( blockZero, 0, calcStatOffset(segmentType) , 8, &count );
|
|
count--;
|
|
setSubBlockEntry( blockZero, 0, calcStatOffset(segmentType) , 8, &count );
|
|
|
|
return NO_ERROR;
|
|
}
|
|
|
|
return ERR_FM_ASSIGN_ERR;
|
|
}
|
|
|
|
/**
|
|
* DESCRIPTION:
|
|
* Assign sub-block - private method used to manage sub-blocks in list
|
|
* PARAMETERS:
|
|
* indexFile - file pointer
|
|
* blockZero - in memory copy of blockZero
|
|
* freemgr_type - either TREE or LIST
|
|
* assignPtr - the assigned ptr
|
|
*
|
|
* RETURN:
|
|
* NO_ERROR if success
|
|
* error no if fail
|
|
**/
|
|
|
|
const int FreeMgr::assignSubblock( CommBlock &cb, DataBlock* blockZero, const int freemgrType, IdxEmptyListEntry* assignPtr )
|
|
{
|
|
int rc; // return code from file ops
|
|
DataBlock workBlock, tempBlock;
|
|
int listOffset; // entry in block zero of head pointer
|
|
IdxEmptyListEntry emptyEntry;
|
|
IdxEmptyListEntry emptyPtr, emptyMap;
|
|
IdxEmptyListEntry newBlock;
|
|
uint64_t numBlocks;
|
|
FILE* indexFile;
|
|
|
|
indexFile = cb.file.pFile;
|
|
|
|
/**
|
|
* Separated subblock assignment out from general segment assignment
|
|
* Reduces the hoops to jump through
|
|
**/
|
|
|
|
numBlocks = getFileSize( indexFile )/BYTE_PER_BLOCK ;
|
|
if( isDebug( DEBUG_3 )) { printf("DBG: Assign subblock \n"); }
|
|
|
|
//find the start of the chain
|
|
listOffset = calcPtrOffset( ENTRY_32 );
|
|
|
|
getSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr );
|
|
if( isDebug( DEBUG_2 ))
|
|
{
|
|
cout<<"DBG: EM (start assign) sb fbo "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" entry "<<emptyPtr.entry<<"\n";
|
|
}
|
|
|
|
if (emptyPtr.type != EMPTY_LIST ){
|
|
return ERR_FM_BAD_TYPE;
|
|
}
|
|
// if (emptyPtr.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 "<<emptyEntry.fbo<<" sbid "<<" entry "<<emptyEntry.entry<<"\n";
|
|
}
|
|
|
|
if (emptyEntry.fbo == 0) // then nowhere to go.. exit
|
|
{
|
|
//if( isDebug( DEBUG_1 )) { printf("DBG: No space in subblock list\n"); }
|
|
if( isDebug( DEBUG_2 )) {
|
|
cout<<"DBG: fbo "<<emptyEntry.fbo<<" sbid "<<emptyEntry.sbid<<" entry "<<emptyEntry.entry<<"\n";
|
|
}
|
|
|
|
//-- try and assign from BLOCK list
|
|
// printf("Go ask for a block\n");
|
|
rc = assignSegment( cb, blockZero, freemgrType, ENTRY_BLK, &newBlock);
|
|
|
|
// rc = extendFreespace( indexFile, blockZero, freemgrType );
|
|
|
|
if (rc != NO_ERROR){
|
|
if( isDebug( DEBUG_1 )) { printf("DBG: Could not get block from block list\n"); }
|
|
return rc;
|
|
}
|
|
// got a block so now split it
|
|
newBlock.entry = 0;
|
|
newBlock.group = ENTRY_32;
|
|
newBlock.type = EMPTY_PTR;
|
|
emptyEntry = newBlock;
|
|
|
|
//-- assign almost all sub blocks - keep last one
|
|
int sbIdx;
|
|
for (sbIdx=BYTE_PER_BLOCK/BYTE_PER_SUBBLOCK-1; sbIdx >0; sbIdx--)
|
|
{
|
|
if( isDebug( DEBUG_3 )) { cout<<"DBG: Working on fbo "<<newBlock.fbo<<" sbid "<<sbIdx<<"\n"; }
|
|
emptyEntry.sbid = sbIdx;
|
|
emptyEntry.type = EMPTY_PTR;
|
|
rc = releaseSubblock( cb, blockZero, freemgrType, &emptyEntry );
|
|
if (rc != NO_ERROR)
|
|
{
|
|
printf("DBG: Error releasing sb\n");
|
|
return rc;
|
|
}
|
|
}
|
|
emptyEntry.sbid=0;
|
|
}
|
|
|
|
if ((emptyEntry.type != EMPTY_LIST) && (emptyEntry.type != EMPTY_PTR))
|
|
{
|
|
if( isDebug( DEBUG_0 ))
|
|
{
|
|
printf("WTF: Bad entry in in subblock list- type is %i (expected %i or %i)\n", (unsigned int)emptyEntry.type, EMPTY_PTR, EMPTY_LIST);
|
|
}
|
|
if( isDebug( DEBUG_2 ))
|
|
{
|
|
cout<<"DBG: fbo "<<emptyEntry.fbo<<" sbid "<<emptyEntry.sbid<<" entry "<<emptyEntry.entry<<"\n";
|
|
}
|
|
return ERR_FM_BAD_TYPE;
|
|
}
|
|
|
|
if (emptyEntry.type == EMPTY_PTR)
|
|
{
|
|
// this is what we expect normally
|
|
emptyPtr.entry--; // only decrement if we didn't just drain a bucket
|
|
setSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr );
|
|
memcpy(assignPtr, &emptyEntry, 8);
|
|
|
|
} else if (emptyEntry.type == EMPTY_LIST && emptyPtr.entry == 0 )
|
|
{
|
|
if (emptyPtr.entry >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 "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" entry "<<emptyPtr.entry<<"\n";
|
|
}
|
|
//blank the llp
|
|
rc = readDBFile( cb, tempBlock.data, emptyPtr.fbo );
|
|
if (rc != NO_ERROR) {
|
|
if (isDebug( DEBUG_1 )){ cout<<"DBG: File error during releaseSubblock, fbo/lbid: "<<emptyPtr.fbo<<"\n"; }
|
|
return rc;
|
|
}
|
|
|
|
nullPtr(&emptyMap); // zero out the entry
|
|
|
|
setSubBlockEntry( tempBlock.data, emptyPtr.sbid, 0, 8, &emptyMap );
|
|
rc = writeDBFile( cb, &tempBlock, emptyPtr.fbo );
|
|
if (rc != NO_ERROR){ return rc; }
|
|
|
|
memcpy(assignPtr, &emptyPtr, 8);
|
|
assignPtr->type = EMPTY_PTR;
|
|
|
|
if( isDebug( DEBUG_2 )) {
|
|
cout<<"DBG: Change head pointer to fbo "<<emptyEntry.fbo<<" sbid "<<emptyEntry.sbid<<" entry "<<emptyEntry.entry<<"\n";
|
|
}
|
|
setSubBlockEntry( blockZero, 0, listOffset, 8, &emptyEntry );
|
|
} else
|
|
{
|
|
printf("DBG: Weirdness - not list and not ptr\n");
|
|
}
|
|
// printf("DBG: Assigned sb fbo %llu sbid %u entry %u\n", assignPtr->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 "<<emptyMap.fbo<<" sbid "<<emptyMap.sbid<<" entry "<<emptyMap.entry<<"\n";
|
|
}
|
|
|
|
blockZero->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 "<<assignPtr->fbo<<" sbid "<<assignPtr->sbid<<" entry "<<assignPtr->entry<<" from "<<((freemgr_type==LIST)?"LIST":"TREE")<<" chain ENTRY_"<<(1<<segmentType)<<" (type is "<<((assignPtr->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 "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" entry "<<emptyPtr.entry<<"\n";
|
|
}
|
|
//ask for a new sb to extend chain
|
|
rc = assignSubblock( cb, blockZero, freemgr_type, &newSb);
|
|
if (rc != NO_ERROR) { printf("DBG: Error extending chain\n"); return rc; }
|
|
if( isDebug( DEBUG_2 ))
|
|
{
|
|
cout<<"DBG: release segment, new SB is fbo "<<newSb.fbo<<" sbid "<<newSb.sbid<<" entry "<<newSb.entry<<"\n";
|
|
}
|
|
rc = readDBFile( cb, extraBlock.data, newSb.fbo );
|
|
if (rc != NO_ERROR)
|
|
{
|
|
if (isDebug( DEBUG_1 )){printf("DBG: File error during releaseSegment (3)\n");}
|
|
return rc;
|
|
}
|
|
|
|
emptyPtr.type = EMPTY_LIST; // writing into the LLP field so set type accordingly
|
|
setSubBlockEntry( extraBlock.data, newSb.sbid, 0, 8, &emptyPtr );
|
|
setSubBlockEntry( extraBlock.data, newSb.sbid, 1, 8, assignPtr );
|
|
rc = writeDBFile( cb, &extraBlock, newSb.fbo );
|
|
if (rc != NO_ERROR)
|
|
{
|
|
if (isDebug( DEBUG_1 )){printf("DBG: File error during releaseSegment (4)\n");}
|
|
return rc;
|
|
}
|
|
|
|
newSb.entry = 1;
|
|
newSb.type = EMPTY_LIST;
|
|
newSb.group = segmentType;
|
|
|
|
setSubBlockEntry( blockZero, 0, listOffset, 8, &newSb );
|
|
blockZero->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<<segmentType)<<" is fbo "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" entry "<<emptyPtr.entry<<"\n";
|
|
}
|
|
setSubBlockEntry( workBlock.data, emptyPtr.sbid, emptyPtr.entry, 8, assignPtr );
|
|
rc = writeDBFile( cb, workBlock.data, emptyPtr.fbo );
|
|
if (rc != NO_ERROR){ return rc; }
|
|
|
|
emptyPtr.type = EMPTY_LIST;
|
|
emptyPtr.group = segmentType;
|
|
|
|
setSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr );
|
|
blockZero->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 "<<assignPtr->fbo<<" sbid "<<assignPtr->sbid<<" entry "<<assignPtr->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 "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" entry "<<emptyPtr.entry<<"\n";
|
|
}
|
|
|
|
//sub block is full or chain empty
|
|
if (emptyPtr.entry == ENTRY_PER_SUBBLOCK-1 || emptyPtr.fbo==0)
|
|
{
|
|
// change type from EMPTY_PTR to EMPTY_LIST
|
|
assignPtr->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 "<<assignPtr->fbo<<" sbid "<<assignPtr->sbid<<" entry "<<assignPtr->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: "<<rc<<" fbo/lbid: "<<assignPtr->fbo<<"\n";
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
if( isDebug( DEBUG_2 )) {
|
|
cout<<"DBG: Set LLP for fbo "<<assignPtr->fbo<<" sbid "<<assignPtr->sbid<<" entry "<<assignPtr->entry<<"to fbo "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" entry "<<emptyPtr.entry<<"\n";
|
|
}
|
|
if( isDebug( DEBUG_3)){
|
|
printf("Before\n");
|
|
printMemSubBlock( &extraBlock, assignPtr->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 "<<emptyMap.fbo<<" sbid "<<emptyMap.sbid<<" entry "<<emptyMap.entry<<"\n";
|
|
}
|
|
if( isDebug( DEBUG_3)){
|
|
printf("After\n");
|
|
printMemSubBlock( &extraBlock, assignPtr->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 "<<emptyPtr.fbo<<" sbid "<<emptyPtr.sbid<<" entry "<<emptyPtr.entry<<"\n";
|
|
}
|
|
if( isDebug( DEBUG_3)){
|
|
printf("After\n");
|
|
printMemSubBlock( &workBlock, emptyPtr.sbid );
|
|
}
|
|
|
|
emptyPtr.type = EMPTY_LIST;
|
|
emptyPtr.group = ENTRY_32;
|
|
|
|
setSubBlockEntry( blockZero, 0, listOffset, 8, &emptyPtr );
|
|
blockZero->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: "<<cb.file.oid<<" fbo: "<<fbo<<", returning unchanged value\n";
|
|
}
|
|
return fbo;
|
|
} else {
|
|
return lbid;
|
|
}
|
|
}
|
|
|
|
|
|
const void FreeMgr::printMemSubBlock( DataBlock* curBlock, const int sbid )
|
|
{
|
|
int off;
|
|
// DataBlock curBlock;
|
|
unsigned char* curPos;
|
|
IdxEmptyListEntry curEntry, testZero;
|
|
|
|
nullPtr( &testZero );
|
|
// readDBFile( m_pTreeFile, &curBlock, fbo );
|
|
curPos = curBlock->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="<<curEntry.fbo<<" sbid="<<curEntry.sbid<<" entry="<<curEntry.entry<<" group="<<curEntry.group<<" type="<<curEntry.type;
|
|
|
|
curPos += MAX_COLUMN_BOUNDARY;
|
|
}
|
|
printf( "\n" );
|
|
}
|
|
|
|
} //end of namespace
|
|
|