#include "ExtentManager.h"
void
ExtentManager::Init(uint32_t theBlockSize, uint32_t theNativeBlockSize, off_t theTotalBytes)
{
blockSize = theBlockSize;
nativeBlockSize = theNativeBlockSize;
totalBytes = theTotalBytes;
totalBlocks = howmany(totalBytes, blockSize);
AddBlockRangeExtent(0, 0);
AddBlockRangeExtent(totalBlocks, 0);
}
void
ExtentManager::MergeExtent(const ExtentInfo &a, const ExtentInfo &b, ExtentInfo *c)
{
c->blockAddr = min(a.blockAddr, b.blockAddr);
c->numBlocks = max(a.blockAddr + a.numBlocks, b.blockAddr + b.numBlocks) - c->blockAddr;
}
void
ExtentManager::AddBlockRangeExtent(off_t blockAddr, off_t numBlocks)
{
struct ExtentInfo ext, newExt;
ListExtIt curIt, newIt;
bool merged = false;
if ((blockAddr > totalBlocks) || (blockAddr + numBlocks < 0)) { return;
}
if (blockAddr < 0) {
numBlocks = blockAddr + numBlocks;
blockAddr = 0;
}
if (blockAddr + numBlocks > totalBlocks) {
numBlocks = totalBlocks - blockAddr;
}
ext.blockAddr = blockAddr;
ext.numBlocks = numBlocks;
for (curIt = extentList.begin(); curIt != extentList.end(); curIt++) {
if (BeforeExtent(ext, *curIt))
break;
if (!BeforeExtent(*curIt, ext)) { MergeExtent(ext, *curIt, &newExt);
*curIt = newExt;
merged = true;
break;
}
}
if (!merged) {
curIt = extentList.insert(curIt, ext); }
newIt = curIt;
curIt = extentList.begin();
while (curIt != extentList.end()) {
if (curIt == newIt || BeforeExtent(*curIt, *newIt)) { curIt++;
continue;
}
if (BeforeExtent(*newIt, *curIt)) { break;
}
MergeExtent(*curIt, *newIt, &newExt);
*newIt = newExt;
curIt = extentList.erase(curIt);
}
}
void
ExtentManager::RemoveBlockRangeExtent(off_t blockAddr, off_t numBlocks)
{
struct ExtentInfo ext, newExt;
ListExtIt curIt;
ext.blockAddr = blockAddr;
ext.numBlocks = numBlocks;
curIt = extentList.begin();
while (curIt != extentList.end()) {
if (BeforeExtent(*curIt, ext)) {
curIt++;
continue;
}
if (BeforeExtent(ext, *curIt)) break;
if (curIt->blockAddr >= ext.blockAddr &&
curIt->blockAddr + curIt->numBlocks <= ext.blockAddr + ext.numBlocks) {
curIt = extentList.erase(curIt);
} else if (curIt->blockAddr < ext.blockAddr &&
curIt->blockAddr + curIt->numBlocks > ext.blockAddr + ext.numBlocks) {
newExt.blockAddr = ext.blockAddr + ext.numBlocks;
newExt.numBlocks = curIt->blockAddr + curIt->numBlocks - newExt.blockAddr;
curIt->numBlocks = ext.blockAddr - curIt->blockAddr;
curIt++;
extentList.insert(curIt, newExt); curIt++;
} else {
if (curIt->blockAddr >= ext.blockAddr) {
assert(curIt->blockAddr + curIt->numBlocks > ext.blockAddr + ext.numBlocks);
newExt.blockAddr = ext.blockAddr + ext.numBlocks;
newExt.numBlocks = curIt->blockAddr + curIt->numBlocks - newExt.blockAddr;
*curIt = newExt;
} else {
curIt->numBlocks = ext.blockAddr - curIt->blockAddr;
}
curIt++;
}
}
}
void
ExtentManager::AddByteRangeExtent(off_t byteAddr, off_t numBytes)
{
off_t blockAddr = byteAddr / blockSize;
off_t blockAddrOfLastByte = (byteAddr + numBytes - 1) / blockSize;
off_t numBlocks = blockAddrOfLastByte - blockAddr + 1;
AddBlockRangeExtent(blockAddr, numBlocks);
}
void
ExtentManager::DebugPrint()
{
ListExtIt it;
for (it = extentList.begin(); it != extentList.end(); it++) {
printf("[%lld, %lld] ", it->blockAddr, it->numBlocks);
}
printf("\n");
}
#if UNIT_TEST
#include <cstdio>
#include <cstdlib>
const char *DebugDescription(class ExtentManager *extMan)
{
char *result = strdup("");
char *temp;
ListExtIt it;
for (it = extMan->extentList.begin(); it != extMan->extentList.end(); it++) {
temp = result;
asprintf(&result, "%s[%lld, %lld] ", temp, it->blockAddr, it->numBlocks);
free(temp);
}
return result;
}
int SimpleTestCase(off_t addAddr, off_t addBlocks, off_t removeAddr, off_t removeBlocks, const char *expectedResult)
{
class ExtentManager extMan;
const char *actualResult;
int result = 0;
extMan.Init(512, 512, 512*999);
extMan.AddBlockRangeExtent(addAddr, addBlocks);
extMan.RemoveBlockRangeExtent(removeAddr, removeBlocks);
actualResult = DebugDescription(&extMan);
if (strcmp(actualResult, expectedResult))
{
fprintf(stderr,
"SimpleTestCase(%lld, %lld, %lld, %lld) failed.\n"
" Expected result: %s\n"
" Actual result: %s\n",
addAddr, addBlocks, removeAddr, removeBlocks,
expectedResult, actualResult);
result = 1;
}
free((void *)actualResult);
return result;
}
int main(void)
{
int failed = 0;
class ExtentManager *extMan;
failed |= SimpleTestCase(10, 10, 12, 6, "[0, 0] [10, 2] [18, 2] [999, 0] ");
failed |= SimpleTestCase(10, 10, 10, 10, "[0, 0] [999, 0] ");
failed |= SimpleTestCase(10, 10, 10, 6, "[0, 0] [16, 4] [999, 0] ");
failed |= SimpleTestCase(10, 10, 14, 6, "[0, 0] [10, 4] [999, 0] ");
failed |= SimpleTestCase(10, 10, 6, 10, "[0, 0] [16, 4] [999, 0] ");
failed |= SimpleTestCase(10, 10, 14, 10, "[0, 0] [10, 4] [999, 0] ");
failed |= SimpleTestCase(10, 10, 6, 18, "[0, 0] [999, 0] ");
failed |= SimpleTestCase(10, 10, 2, 5, "[0, 0] [10, 10] [999, 0] ");
failed |= SimpleTestCase(10, 10, 22, 5, "[0, 0] [10, 10] [999, 0] ");
if (failed)
printf("FAIL!\n");
else
printf("Success.\n");
return failed;
}
#endif