vitastor/allocator.cpp

128 lines
2.5 KiB
C++
Raw Permalink Normal View History

2019-11-27 00:50:57 +03:00
#include <stdexcept>
2019-10-28 01:22:01 +03:00
#include "allocator.h"
#include <stdlib.h>
#include <malloc.h>
2019-11-27 00:50:57 +03:00
allocator::allocator(uint64_t blocks)
2019-10-28 01:22:01 +03:00
{
if (blocks >= 0x80000000 || blocks <= 1)
{
2019-11-27 00:50:57 +03:00
throw std::invalid_argument("blocks");
2019-10-28 01:22:01 +03:00
}
uint64_t p2 = 1, total = 1;
while (p2 * 64 < blocks)
{
p2 = p2 * 64;
total += p2;
}
total -= p2;
total += (blocks+63) / 64;
2019-11-27 00:50:57 +03:00
mask = new uint64_t[2 + total];
size = free = blocks;
2019-11-27 00:50:57 +03:00
last_one_mask = (blocks % 64) == 0
? UINT64_MAX
: ~(UINT64_MAX << (64 - blocks % 64));
for (uint64_t i = 0; i < total; i++)
2019-10-28 01:22:01 +03:00
{
2019-11-27 00:50:57 +03:00
mask[i] = 0;
2019-10-28 01:22:01 +03:00
}
}
2019-11-27 00:50:57 +03:00
allocator::~allocator()
2019-10-28 01:22:01 +03:00
{
2019-11-27 00:50:57 +03:00
delete[] mask;
2019-10-28 01:22:01 +03:00
}
2019-11-27 00:50:57 +03:00
void allocator::set(uint64_t addr, bool value)
2019-10-28 01:22:01 +03:00
{
2019-11-27 00:50:57 +03:00
if (addr >= size)
2019-10-28 01:22:01 +03:00
{
return;
}
uint64_t p2 = 1, offset = 0;
2019-11-27 00:50:57 +03:00
while (p2 * 64 < size)
2019-10-28 01:22:01 +03:00
{
offset += p2;
p2 = p2 * 64;
}
uint64_t cur_addr = addr;
bool is_last = true;
uint64_t value64 = value ? 1 : 0;
while (1)
{
uint64_t last = offset + cur_addr/64;
uint64_t bit = cur_addr % 64;
2019-11-27 00:50:57 +03:00
if (((mask[last] >> bit) & 1) != value64)
2019-10-28 01:22:01 +03:00
{
if (is_last)
{
free += value ? -1 : 1;
}
2019-10-28 01:22:01 +03:00
if (value)
{
2019-11-27 01:12:25 +03:00
mask[last] = mask[last] | (1l << bit);
2019-11-27 00:50:57 +03:00
if (mask[last] != (!is_last || cur_addr/64 < size/64
? UINT64_MAX : last_one_mask))
2019-10-28 01:22:01 +03:00
{
break;
}
}
else
{
2019-11-27 01:12:25 +03:00
mask[last] = mask[last] & ~(1l << bit);
2019-10-28 01:22:01 +03:00
}
is_last = false;
if (p2 > 1)
{
p2 = p2 / 64;
offset -= p2;
cur_addr /= 64;
}
else
{
break;
}
}
else
{
break;
}
}
}
2019-11-27 00:50:57 +03:00
uint64_t allocator::find_free()
2019-10-28 01:22:01 +03:00
{
uint64_t p2 = 1, offset = 0, addr = 0, f, i;
2019-11-27 00:50:57 +03:00
while (p2 < size)
2019-10-28 01:22:01 +03:00
{
2019-11-27 00:50:57 +03:00
uint64_t m = mask[offset + addr];
2019-10-28 01:22:01 +03:00
for (i = 0, f = 1; i < 64; i++, f <<= 1)
{
2019-11-27 00:50:57 +03:00
if (!(m & f))
2019-10-28 01:22:01 +03:00
{
break;
}
}
if (i == 64)
{
// No space
return UINT64_MAX;
2019-10-28 01:22:01 +03:00
}
addr = (addr * 64) | i;
2019-11-27 00:50:57 +03:00
if (addr >= size)
2019-10-28 01:22:01 +03:00
{
// No space
return UINT64_MAX;
2019-10-28 01:22:01 +03:00
}
offset += p2;
p2 = p2 * 64;
}
return addr;
}
uint64_t allocator::get_free_count()
{
return free;
}