in src/Trinity.C/src/Storage/MemoryTrunk/MemoryTrunk.DefragTwoRegion.cpp [10:224]
void MemoryTrunk::DefragmentTwoRegion(AddressTableEntry* addressTable, int32_t addressTableLength, AddressTableEndPoint endpoint)
{
/// Backward index in the address table.
int32_t bwd_index = endpoint.bwd_index;
/// Forward index in the address table.
int32_t fwd_index = endpoint.fwd_index;
int32_t AddressTableHead = bwd_index;
uint32_t hole_right_offset = addressTable[bwd_index].offset;
int32_t bwd_cell_entry_index = 0;
int32_t fwd_cell_entry_index = 0;
uint32_t hole_size;
bool done = false;
while (true)
{
/************ Termination : bwd_index meets fwd_index ***************/
if (bwd_index == fwd_index)
{
bwd_cell_entry_index = addressTable[bwd_index].index;
if (hashtable->TryGetEntryLockForDefragment(bwd_cell_entry_index))
{
cellid_t _bwd_cell_id = hashtable->MTEntries[bwd_cell_entry_index].Key;
uint32_t _bwd_cell_size = (uint32_t)hashtable->CellSize(bwd_cell_entry_index);
int32_t _bwd_cell_offset = hashtable->CellEntries[bwd_cell_entry_index].offset;
if ((int32_t)_bwd_cell_size <= 0 /*removed*/ || _bwd_cell_offset != addressTable[bwd_index].offset/*moved*/)
{
addressTable[fwd_index].offset = hole_right_offset;
addressTable[fwd_index].offset = addressTable[fwd_index].offset % TrunkLength;
}
else if (
(hole_right_offset >= (uint32_t)_bwd_cell_offset && (hole_right_offset - _bwd_cell_offset - _bwd_cell_size > 0)) ||
(hole_right_offset < (uint32_t)_bwd_cell_offset && hole_right_offset >= _bwd_cell_size)
)
{
if (_bwd_cell_size > 0)
{
memmove(trunkPtr + (hole_right_offset - _bwd_cell_size), trunkPtr + _bwd_cell_offset, (uint64_t)_bwd_cell_size);
hashtable->CellEntries[bwd_cell_entry_index].offset = (int32_t)(hole_right_offset - _bwd_cell_size);
}
addressTable[fwd_index].offset = hole_right_offset - _bwd_cell_size;
}
hashtable->ResetSizeEntryUnsafe(bwd_cell_entry_index);
hashtable->ReleaseEntryLock(bwd_cell_entry_index);
}
goto Defragment_Unlock_And_Exit;
}
////////////////////////////////////////////////////////////////////////////
bwd_cell_entry_index = addressTable[bwd_index].index;
//! First get the bwd cell entry lock
if (!hashtable->TryGetEntryLockForDefragment(bwd_cell_entry_index))
goto Defragment_Unlock_And_Exit;
cellid_t bwd_cell_id = hashtable->MTEntries[bwd_cell_entry_index].Key;
uint32_t bwd_cell_size = (uint32_t)hashtable->CellSize(bwd_cell_entry_index);
int32_t bwd_cell_offset = hashtable->CellEntries[bwd_cell_entry_index].offset;
/***** Skip the cells that have been removed or moved after taking the address table snapshot ******/
if ((int32_t)bwd_cell_size <= 0 /* removed */ || bwd_cell_offset != addressTable[bwd_index].offset /* moved */)
{
hashtable->ReleaseEntryLock(bwd_cell_entry_index); //! Release the entry lock before continuing
if (--bwd_index < 0)
{
bwd_index += addressTableLength; //warped to the back
}
continue;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
/************** Skip the first bwd cell *****************/
if (bwd_index == AddressTableHead)
{
hashtable->ReleaseEntryLock(bwd_cell_entry_index); //! Release the entry lock before continuing
if (--bwd_index < 0)
{
bwd_index += addressTableLength;//warped to the back
}
continue;
}
//////////////////////////////////////////////////////////
// Not AddressTableHead and not removed or moved
if (hole_right_offset >= (uint32_t)bwd_cell_offset) // on the same side
{
hole_size = hole_right_offset - (uint32_t)bwd_cell_offset - bwd_cell_size;
}
else // memory hole and bwd_cell are on two sides
{
hole_size = hole_right_offset;
if (hole_size == 0)
{
hole_right_offset = TrunkLength;
hole_size = hole_right_offset - (uint32_t)bwd_cell_offset - bwd_cell_size;
}
}
if (hole_size == 0)
{
hashtable->ResetSizeEntryUnsafe(bwd_cell_entry_index);
hashtable->ReleaseEntryLock(bwd_cell_entry_index);
hole_right_offset -= bwd_cell_size;
if (hole_right_offset == 0)
{
hole_right_offset = TrunkLength;
}
if (--bwd_index < 0)
{
bwd_index += addressTableLength;//warped to the back
}
continue;
}
fwd_cell_entry_index = addressTable[fwd_index].index;
if (hashtable->TryGetEntryLockForDefragment(fwd_cell_entry_index))
{
cellid_t fwd_cell_id = hashtable->MTEntries[fwd_cell_entry_index].Key;
uint32_t fwd_cell_size = (uint32_t)hashtable->CellSize(fwd_cell_entry_index);
int32_t fwd_cell_offset = hashtable->CellEntries[fwd_cell_entry_index].offset;
if ((int32_t)fwd_cell_size <= 0 || fwd_cell_offset != addressTable[fwd_index].offset)
{
fwd_index = (fwd_index + 1) % addressTableLength;
if (fwd_index == bwd_index)
done = true;
}
else if (fwd_cell_size <= hole_size)
{
if (fwd_cell_size > 0)
{
memmove(trunkPtr + (hole_right_offset - fwd_cell_size), trunkPtr + fwd_cell_offset, (uint64_t)fwd_cell_size);
hashtable->CellEntries[fwd_cell_entry_index].offset = (int32_t)(hole_right_offset - fwd_cell_size);
hashtable->ResetSizeEntryUnsafe(fwd_cell_entry_index); //! Reset size array
hole_right_offset -= (uint32_t)fwd_cell_size;
if (hole_right_offset == 0)
hole_right_offset = TrunkLength;
}
fwd_index = (fwd_index + 1) % addressTableLength;
if (fwd_index == bwd_index)
done = true;
}
hashtable->ReleaseEntryLock(fwd_cell_entry_index); //! Release fwd cell entry lock
}
if ((uint32_t)bwd_cell_offset > hole_right_offset)//bwd_cell is in front region , hole is in back region
{
//so that [0..hole_r_offset] is the hole
//length == hole_r_offset
if (bwd_cell_size > hole_right_offset)//the hole cannot hold the bwd_cell
{
hole_right_offset = TrunkLength;
hole_size = hole_right_offset - (uint32_t)bwd_cell_offset - bwd_cell_size;
}
else
{
hole_size = hole_right_offset;
}
}
else//bwd_cell and hole is in the same region
{
hole_size = hole_right_offset - (uint32_t)bwd_cell_offset - bwd_cell_size;
}
if (hole_size > 0 && bwd_cell_size > 0)
{
memmove(trunkPtr + (hole_right_offset - bwd_cell_size), trunkPtr + bwd_cell_offset, (uint64_t)bwd_cell_size);
hashtable->CellEntries[bwd_cell_entry_index].offset = (int32_t)(hole_right_offset - bwd_cell_size);
}
hole_right_offset -= bwd_cell_size;
if (hole_right_offset == 0)
hole_right_offset = TrunkLength;
hashtable->ResetSizeEntryUnsafe(bwd_cell_entry_index);
hashtable->ReleaseEntryLock(bwd_cell_entry_index);
if (done)
{
addressTable[fwd_index].offset = hole_right_offset % TrunkLength;
break;
}
if (--bwd_index < 0)
bwd_index += addressTableLength;
}
/******************************************* Epilog ****************************************************/
Defragment_Unlock_And_Exit:
uint64_t mem_to_decommit = 0;
if (addressTable[fwd_index].offset >= committed_tail)
{
mem_to_decommit = (uint64_t)(addressTable[fwd_index].offset - committed_tail) & Memory::PAGE_MASK_32;
if (mem_to_decommit > 0 && committed_tail < TrunkLength)
BufferedDecommitMemory(trunkPtr + committed_tail, mem_to_decommit);
}
else
{
mem_to_decommit = (TrunkLength - committed_tail) & Memory::PAGE_MASK_32;
if (mem_to_decommit > 0)
BufferedDecommitMemory(trunkPtr + committed_tail, mem_to_decommit);
//Console::WriteLine("Two Region Decommitted {0}", mem_to_decommit);
mem_to_decommit = (uint64_t)(addressTable[fwd_index].offset & Memory::PAGE_MASK_32);
if (mem_to_decommit > 0)
BufferedDecommitMemory(trunkPtr, mem_to_decommit);
//Console::WriteLine("Two Region Decommitted {0}", mem_to_decommit);
}
committed_tail = addressTable[fwd_index].offset & Memory::PAGE_MASK_32;
/////////////////////////////////////////////////////////////////////////////////////////////////////////
}