Move prev/next/block_num to struct heap_list_item_t
This commit is contained in:
@@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
@@ -23,9 +24,15 @@
|
|||||||
#define HEAP_INFLIGHT_COMPACTED 4
|
#define HEAP_INFLIGHT_COMPACTED 4
|
||||||
#define HEAP_INFLIGHT_GC 8
|
#define HEAP_INFLIGHT_GC 8
|
||||||
|
|
||||||
|
static inline heap_list_item_t *list_item(heap_entry_t *wr)
|
||||||
|
{
|
||||||
|
return (heap_list_item_t*)((uint8_t*)wr - offsetof(struct heap_list_item_t, entry));
|
||||||
|
}
|
||||||
|
|
||||||
heap_entry_t *blockstore_heap_t::prev(heap_entry_t *wr)
|
heap_entry_t *blockstore_heap_t::prev(heap_entry_t *wr)
|
||||||
{
|
{
|
||||||
return wr->prev == (heap_entry_t*)1 ? NULL : wr->prev;
|
auto li = list_item(wr);
|
||||||
|
return li->prev ? &li->prev->entry : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t blockstore_heap_t::get_simple_entry_size()
|
uint32_t blockstore_heap_t::get_simple_entry_size()
|
||||||
@@ -168,17 +175,8 @@ void heap_entry_t::set_big_location(blockstore_heap_t *heap, uint64_t location)
|
|||||||
uint32_t heap_entry_t::calc_crc32c()
|
uint32_t heap_entry_t::calc_crc32c()
|
||||||
{
|
{
|
||||||
auto old_crc32c = crc32c;
|
auto old_crc32c = crc32c;
|
||||||
auto old_block = block_num;
|
|
||||||
auto old_prev = prev;
|
|
||||||
auto old_next = next;
|
|
||||||
block_num = 0;
|
|
||||||
prev = NULL;
|
|
||||||
next = NULL;
|
|
||||||
crc32c = 0;
|
crc32c = 0;
|
||||||
uint32_t res = ::crc32c(0, (uint8_t*)this, size);
|
uint32_t res = ::crc32c(0, (uint8_t*)this, size);
|
||||||
block_num = old_block;
|
|
||||||
prev = old_prev;
|
|
||||||
next = old_next;
|
|
||||||
crc32c = old_crc32c;
|
crc32c = old_crc32c;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@@ -230,7 +228,7 @@ blockstore_heap_t::~blockstore_heap_t()
|
|||||||
}
|
}
|
||||||
|
|
||||||
int blockstore_heap_t::read_blocks(uint64_t disk_offset, uint64_t disk_size, uint8_t *buf,
|
int blockstore_heap_t::read_blocks(uint64_t disk_offset, uint64_t disk_size, uint8_t *buf,
|
||||||
std::function<void(heap_entry_t*)> handle_write, std::function<void(uint32_t, uint32_t, uint8_t*)> handle_block)
|
std::function<void(uint32_t block_num, heap_entry_t* wr)> handle_write, std::function<void(uint32_t, uint32_t, uint8_t*)> handle_block)
|
||||||
{
|
{
|
||||||
for (uint64_t buf_offset = 0; buf_offset < disk_size; buf_offset += dsk->meta_block_size)
|
for (uint64_t buf_offset = 0; buf_offset < disk_size; buf_offset += dsk->meta_block_size)
|
||||||
{
|
{
|
||||||
@@ -286,10 +284,7 @@ int blockstore_heap_t::read_blocks(uint64_t disk_offset, uint64_t disk_size, uin
|
|||||||
block_num, block_offset, expected_crc32c, wr->crc32c);
|
block_num, block_offset, expected_crc32c, wr->crc32c);
|
||||||
return EDOM;
|
return EDOM;
|
||||||
}
|
}
|
||||||
wr->prev = NULL;
|
handle_write(block_num, wr);
|
||||||
wr->next = NULL;
|
|
||||||
wr->block_num = block_num;
|
|
||||||
handle_write(wr);
|
|
||||||
block_offset += wr->size;
|
block_offset += wr->size;
|
||||||
}
|
}
|
||||||
handle_block(block_num, block_offset, buf+buf_offset);
|
handle_block(block_num, block_offset, buf+buf_offset);
|
||||||
@@ -301,10 +296,13 @@ int blockstore_heap_t::load_blocks(uint64_t disk_offset, uint64_t size, uint8_t
|
|||||||
{
|
{
|
||||||
entries_loaded = 0;
|
entries_loaded = 0;
|
||||||
uint32_t used_space = 0;
|
uint32_t used_space = 0;
|
||||||
return read_blocks(disk_offset, size, buf, [&](heap_entry_t *wr_orig)
|
return read_blocks(disk_offset, size, buf, [&](uint32_t block_num, heap_entry_t *wr_orig)
|
||||||
{
|
{
|
||||||
heap_entry_t *wr = (heap_entry_t*)malloc_or_die(wr_orig->size);
|
heap_list_item_t *li = (heap_list_item_t*)malloc_or_die(wr_orig->size + sizeof(heap_list_item_t) - sizeof(heap_entry_t));
|
||||||
memcpy(wr, wr_orig, wr_orig->size);
|
li->block_num = block_num;
|
||||||
|
li->prev = li->next = NULL;
|
||||||
|
memcpy(&li->entry, wr_orig, wr_orig->size);
|
||||||
|
auto wr = &li->entry;
|
||||||
if (wr->lsn > next_lsn)
|
if (wr->lsn > next_lsn)
|
||||||
{
|
{
|
||||||
next_lsn = wr->lsn;
|
next_lsn = wr->lsn;
|
||||||
@@ -314,67 +312,66 @@ int blockstore_heap_t::load_blocks(uint64_t disk_offset, uint64_t size, uint8_t
|
|||||||
auto & idx = inode_idx[wr->stripe];
|
auto & idx = inode_idx[wr->stripe];
|
||||||
if (!idx.ptr)
|
if (!idx.ptr)
|
||||||
{
|
{
|
||||||
idx.ptr = wr;
|
idx.ptr = li;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto prev_wr = idx.ptr;
|
auto prev_li = idx.ptr;
|
||||||
if (!prev_wr || prev_wr->is_before(wr))
|
if (!prev_li || prev_li->entry.is_before(wr))
|
||||||
{
|
{
|
||||||
wr->prev = prev_wr;
|
li->prev = prev_li;
|
||||||
if (prev_wr)
|
if (prev_li)
|
||||||
{
|
{
|
||||||
prev_wr->next = wr;
|
prev_li->next = li;
|
||||||
}
|
}
|
||||||
if (wr->is_overwrite())
|
if (wr->is_overwrite())
|
||||||
{
|
{
|
||||||
// Mark all previous entries as garbage
|
// Mark all previous entries as garbage
|
||||||
while (prev_wr)
|
while (prev_li)
|
||||||
{
|
{
|
||||||
auto prev_prev = prev(wr);
|
prev_li->entry.set_garbage();
|
||||||
prev_wr->set_garbage();
|
block_info[prev_li->block_num].has_garbage = true; // FIXME modify_alloc
|
||||||
block_info[prev_wr->block_num].has_garbage = true; // FIXME modify_alloc
|
prev_li = prev_li->prev;
|
||||||
prev_wr = prev_prev;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Insert <wr> on top
|
// Insert <wr> on top
|
||||||
idx.ptr = wr;
|
idx.ptr = li;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
auto prev_prev = prev(prev_wr);
|
auto prev_prev = prev_li->prev;
|
||||||
if (!prev_prev || prev_prev->is_before(wr))
|
if (!prev_prev || prev_prev->entry.is_before(wr))
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
prev_wr = prev_prev;
|
prev_li = prev_prev;
|
||||||
}
|
}
|
||||||
if (prev_wr->is_overwrite())
|
if (prev_li->entry.is_overwrite())
|
||||||
{
|
{
|
||||||
// Mark <wr> as garbage
|
// Mark <wr> as garbage
|
||||||
wr->set_garbage();
|
wr->set_garbage();
|
||||||
block_info[wr->block_num].has_garbage = true;
|
block_info[li->block_num].has_garbage = true;
|
||||||
}
|
}
|
||||||
// Insert <wr> before <prev_wr>
|
// Insert <wr> before <prev_wr>
|
||||||
wr->prev = prev_wr->prev;
|
li->prev = prev_li->prev;
|
||||||
if (prev_wr->prev)
|
if (prev_li->prev)
|
||||||
prev_wr->prev->next = wr;
|
prev_li->prev->next = li;
|
||||||
prev_wr->prev = wr;
|
prev_li->prev = li;
|
||||||
wr->next = prev_wr;
|
li->next = prev_li;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!wr->is_garbage())
|
if (!wr->is_garbage())
|
||||||
{
|
{
|
||||||
used_space += wr->size;
|
used_space += wr->size;
|
||||||
}
|
}
|
||||||
auto & inf = block_info[wr->block_num];
|
auto & inf = block_info[li->block_num];
|
||||||
if (!inf.entries.size())
|
if (!inf.entries.size())
|
||||||
{
|
{
|
||||||
inf.entries.reserve(dsk->meta_block_size / sizeof(heap_entry_t));
|
inf.entries.reserve(dsk->meta_block_size / sizeof(heap_entry_t));
|
||||||
}
|
}
|
||||||
inf.entries.push_back(wr);
|
inf.entries.push_back(li);
|
||||||
}, [&](uint32_t block_num, uint32_t last_offset, uint8_t *buf)
|
}, [&](uint32_t block_num, uint32_t last_offset, uint8_t *buf)
|
||||||
{
|
{
|
||||||
modify_alloc(block_num, [&](heap_block_info_t & inf)
|
modify_alloc(block_num, [&](heap_block_info_t & inf)
|
||||||
@@ -393,7 +390,7 @@ void blockstore_heap_t::fill_recheck_queue()
|
|||||||
{
|
{
|
||||||
for (auto & op: ip.second)
|
for (auto & op: ip.second)
|
||||||
{
|
{
|
||||||
auto wr = op.second.ptr;
|
auto wr = &op.second.ptr->entry;
|
||||||
bool prev_intent = false;
|
bool prev_intent = false;
|
||||||
while (wr)
|
while (wr)
|
||||||
{
|
{
|
||||||
@@ -418,7 +415,7 @@ void blockstore_heap_t::mark_used_blocks()
|
|||||||
for (auto & op: ip.second)
|
for (auto & op: ip.second)
|
||||||
{
|
{
|
||||||
bool added = false;
|
bool added = false;
|
||||||
auto wr = op.second.ptr;
|
auto wr = &op.second.ptr->entry;
|
||||||
while (wr)
|
while (wr)
|
||||||
{
|
{
|
||||||
if (wr->type() == BS_HEAP_SMALL_WRITE)
|
if (wr->type() == BS_HEAP_SMALL_WRITE)
|
||||||
@@ -452,20 +449,20 @@ void blockstore_heap_t::recheck_buffer(heap_entry_t *cwr, uint8_t *buf)
|
|||||||
{
|
{
|
||||||
// write entry is invalid, erase it and all newer entries
|
// write entry is invalid, erase it and all newer entries
|
||||||
auto & inode_idx = block_index[get_pg_id(cwr->inode, cwr->stripe)][cwr->inode];
|
auto & inode_idx = block_index[get_pg_id(cwr->inode, cwr->stripe)][cwr->inode];
|
||||||
auto wr = inode_idx[cwr->stripe].ptr;
|
auto li = inode_idx[cwr->stripe].ptr;
|
||||||
int rolled_back = 0;
|
int rolled_back = 0;
|
||||||
auto free_entry = [&]()
|
auto free_entry = [&]()
|
||||||
{
|
{
|
||||||
uint32_t block_num = wr->block_num;
|
uint32_t block_num = li->block_num;
|
||||||
auto prev = wr->prev;
|
auto prev = li->prev;
|
||||||
auto wr_size = wr->size;
|
auto wr_size = li->entry.size;
|
||||||
free(wr);
|
free(li);
|
||||||
modify_alloc(block_num, [&](heap_block_info_t & inf)
|
modify_alloc(block_num, [&](heap_block_info_t & inf)
|
||||||
{
|
{
|
||||||
inf.used_space -= wr_size;
|
inf.used_space -= wr_size;
|
||||||
for (auto it = inf.entries.begin(); it != inf.entries.end(); it++)
|
for (auto it = inf.entries.begin(); it != inf.entries.end(); it++)
|
||||||
{
|
{
|
||||||
if (*it == wr)
|
if (*it == li)
|
||||||
{
|
{
|
||||||
inf.entries.erase(it);
|
inf.entries.erase(it);
|
||||||
break;
|
break;
|
||||||
@@ -473,25 +470,26 @@ void blockstore_heap_t::recheck_buffer(heap_entry_t *cwr, uint8_t *buf)
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
recheck_modified_blocks.insert(block_num);
|
recheck_modified_blocks.insert(block_num);
|
||||||
wr = prev;
|
li = prev;
|
||||||
rolled_back++;
|
rolled_back++;
|
||||||
};
|
};
|
||||||
while (wr && wr != cwr)
|
while (li && cwr != &li->entry)
|
||||||
{
|
{
|
||||||
free_entry();
|
free_entry();
|
||||||
}
|
}
|
||||||
assert(wr == cwr);
|
assert(li);
|
||||||
if (wr->prev)
|
if (li->prev)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Notice: %u unfinished writes to %jx:%jx v%jx since lsn %ju, rolling back\n",
|
fprintf(stderr, "Notice: %u unfinished writes to %jx:%jx v%jx since lsn %ju, rolling back\n",
|
||||||
rolled_back+1, wr->inode, wr->stripe, prev(wr)->version, prev(wr)->lsn);
|
rolled_back+1, cwr->inode, cwr->stripe, prev(cwr)->version, prev(cwr)->lsn);
|
||||||
inode_idx[wr->stripe].ptr = wr->prev;
|
inode_idx[cwr->stripe].ptr = li->prev;
|
||||||
|
li->prev->next = NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
fprintf(stderr, "Notice: the whole object %jx:%jx only has unfinished writes, rolling back\n",
|
fprintf(stderr, "Notice: the whole object %jx:%jx only has unfinished writes, rolling back\n",
|
||||||
wr->inode, wr->stripe);
|
cwr->inode, cwr->stripe);
|
||||||
inode_idx.erase(wr->stripe);
|
inode_idx.erase(cwr->stripe);
|
||||||
}
|
}
|
||||||
free_entry();
|
free_entry();
|
||||||
}
|
}
|
||||||
@@ -808,10 +806,10 @@ heap_entry_t *blockstore_heap_t::read_entry(object_id oid)
|
|||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
return stripe_it->second.ptr;
|
return &stripe_it->second.ptr->entry;
|
||||||
}
|
}
|
||||||
|
|
||||||
int blockstore_heap_t::allocate_entry(uint32_t entry_size, uint32_t *block_num, heap_entry_t **entry, bool allow_last_free)
|
int blockstore_heap_t::allocate_entry(uint32_t entry_size, uint32_t *block_num, bool allow_last_free)
|
||||||
{
|
{
|
||||||
if (last_allocated_block != UINT32_MAX)
|
if (last_allocated_block != UINT32_MAX)
|
||||||
{
|
{
|
||||||
@@ -882,7 +880,7 @@ int blockstore_heap_t::allocate_entry(uint32_t entry_size, uint32_t *block_num,
|
|||||||
size_t i = 0, j = 0;
|
size_t i = 0, j = 0;
|
||||||
for (; i < inf.entries.size(); i++)
|
for (; i < inf.entries.size(); i++)
|
||||||
{
|
{
|
||||||
if (inf.entries[i]->is_garbage())
|
if (inf.entries[i]->entry.is_garbage())
|
||||||
{
|
{
|
||||||
// old entry invalidated by a newer one, mark it as freeable on block write
|
// old entry invalidated by a newer one, mark it as freeable on block write
|
||||||
// assign a 'virtual' LSN to track GC completion
|
// assign a 'virtual' LSN to track GC completion
|
||||||
@@ -890,7 +888,7 @@ int blockstore_heap_t::allocate_entry(uint32_t entry_size, uint32_t *block_num,
|
|||||||
uint64_t gc_lsn = ++next_lsn;
|
uint64_t gc_lsn = ++next_lsn;
|
||||||
inf.mod_lsn = inf.mod_lsn ? inf.mod_lsn : gc_lsn;
|
inf.mod_lsn = inf.mod_lsn ? inf.mod_lsn : gc_lsn;
|
||||||
inf.mod_lsn_to = gc_lsn;
|
inf.mod_lsn_to = gc_lsn;
|
||||||
push_inflight_lsn(gc_lsn, inf.entries[i], HEAP_INFLIGHT_GC);
|
push_inflight_lsn(gc_lsn, &inf.entries[i]->entry, HEAP_INFLIGHT_GC);
|
||||||
}
|
}
|
||||||
else if (j != i)
|
else if (j != i)
|
||||||
{
|
{
|
||||||
@@ -901,10 +899,6 @@ int blockstore_heap_t::allocate_entry(uint32_t entry_size, uint32_t *block_num,
|
|||||||
inf.has_garbage = false;
|
inf.has_garbage = false;
|
||||||
}
|
}
|
||||||
*block_num = last_allocated_block;
|
*block_num = last_allocated_block;
|
||||||
*entry = (heap_entry_t*)malloc_or_die(entry_size);
|
|
||||||
if (!inf.entries.size())
|
|
||||||
inf.entries.reserve(dsk->meta_block_size / sizeof(heap_entry_t));
|
|
||||||
inf.entries.push_back(*entry);
|
|
||||||
modify_alloc(last_allocated_block, [&](heap_block_info_t & inf)
|
modify_alloc(last_allocated_block, [&](heap_block_info_t & inf)
|
||||||
{
|
{
|
||||||
inf.used_space += entry_size;
|
inf.used_space += entry_size;
|
||||||
@@ -912,12 +906,11 @@ int blockstore_heap_t::allocate_entry(uint32_t entry_size, uint32_t *block_num,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int blockstore_heap_t::add_entry(uint32_t wr_size, heap_entry_t *old_head, uint32_t *modified_block,
|
int blockstore_heap_t::add_entry(uint32_t wr_size, uint32_t *modified_block,
|
||||||
bool allow_last_free, std::function<void(heap_entry_t *wr)> fill_entry)
|
bool allow_last_free, std::function<void(heap_entry_t *wr)> fill_entry)
|
||||||
{
|
{
|
||||||
heap_entry_t *new_wr = NULL;
|
|
||||||
uint32_t block_num;
|
uint32_t block_num;
|
||||||
int res = allocate_entry(wr_size, &block_num, &new_wr, allow_last_free);
|
int res = allocate_entry(wr_size, &block_num, allow_last_free);
|
||||||
if (res != 0)
|
if (res != 0)
|
||||||
{
|
{
|
||||||
return res;
|
return res;
|
||||||
@@ -926,7 +919,12 @@ int blockstore_heap_t::add_entry(uint32_t wr_size, heap_entry_t *old_head, uint3
|
|||||||
{
|
{
|
||||||
*modified_block = block_num;
|
*modified_block = block_num;
|
||||||
}
|
}
|
||||||
|
auto li = (heap_list_item_t*)malloc_or_die(wr_size + sizeof(heap_list_item_t) - sizeof(heap_entry_t));
|
||||||
|
auto new_wr = &li->entry;
|
||||||
auto & inf = block_info.at(block_num);
|
auto & inf = block_info.at(block_num);
|
||||||
|
if (!inf.entries.size())
|
||||||
|
inf.entries.reserve(dsk->meta_block_size / sizeof(heap_entry_t));
|
||||||
|
inf.entries.push_back(li);
|
||||||
assert(!inf.mod_lsn_to || inf.mod_lsn_to == next_lsn);
|
assert(!inf.mod_lsn_to || inf.mod_lsn_to == next_lsn);
|
||||||
new_wr->lsn = ++next_lsn;
|
new_wr->lsn = ++next_lsn;
|
||||||
fill_entry(new_wr);
|
fill_entry(new_wr);
|
||||||
@@ -938,40 +936,39 @@ int blockstore_heap_t::add_entry(uint32_t wr_size, heap_entry_t *old_head, uint3
|
|||||||
(new_wr->is_overwrite() ? HEAP_INFLIGHT_COMPACTED : 0) |
|
(new_wr->is_overwrite() ? HEAP_INFLIGHT_COMPACTED : 0) |
|
||||||
(new_wr->is_compactable() ? HEAP_INFLIGHT_COMPACTABLE : 0));
|
(new_wr->is_compactable() ? HEAP_INFLIGHT_COMPACTABLE : 0));
|
||||||
auto & idx = block_index[get_pg_id(oid.inode, oid.stripe)][oid.inode][oid.stripe];
|
auto & idx = block_index[get_pg_id(oid.inode, oid.stripe)][oid.inode][oid.stripe];
|
||||||
old_head = idx.ptr;
|
auto old_head = idx.ptr;
|
||||||
if (old_head && !old_head->is_before(new_wr))
|
if (old_head && !old_head->entry.is_before(new_wr))
|
||||||
{
|
{
|
||||||
// BIG_WRITE may be inserted into the middle of the sequence during compaction
|
// BIG_WRITE may be inserted into the middle of the sequence during compaction
|
||||||
// and it overrides SMALL_WRITEs and COMMITs with the same LSN
|
// and it overrides SMALL_WRITEs and COMMITs with the same LSN
|
||||||
// However, all entries of other types (say DELETE) override previous ones
|
// However, all entries of other types (say DELETE) override previous ones
|
||||||
auto next_wr = old_head;
|
auto next_li = old_head;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
auto nn = prev(next_wr);
|
if (!next_li->prev || next_li->prev->entry.is_before(new_wr))
|
||||||
if (!nn || nn->is_before(new_wr))
|
|
||||||
break;
|
break;
|
||||||
next_wr = nn;
|
next_li = next_li->prev;
|
||||||
}
|
}
|
||||||
auto prev_wr = prev(next_wr);
|
auto prev_wr = &next_li->prev->entry;
|
||||||
// <prev_wr> may be an identical big_write entry when we "punch holes" in the bitmap
|
// <prev_wr> may be an identical big_write entry when we "punch holes" in the bitmap
|
||||||
assert(prev_wr && prev_wr->type() != BS_HEAP_DELETE &&
|
assert(prev_wr && prev_wr->type() != BS_HEAP_DELETE &&
|
||||||
(prev_wr->type() != BS_HEAP_BIG_WRITE || prev_wr->version == new_wr->version));
|
(prev_wr->type() != BS_HEAP_BIG_WRITE || prev_wr->version == new_wr->version));
|
||||||
// Insert <new_wr> between <next_wr> and <prev_wr>
|
// Insert <new_wr> between <next_wr> and <prev_wr>
|
||||||
new_wr->prev = next_wr->prev;
|
li->prev = next_li->prev;
|
||||||
if (next_wr->prev)
|
if (next_li->prev)
|
||||||
next_wr->prev->next = new_wr;
|
next_li->prev->next = li;
|
||||||
next_wr->prev = new_wr;
|
next_li->prev = li;
|
||||||
new_wr->next = next_wr;
|
li->next = next_li;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
new_wr->prev = idx.ptr;
|
li->prev = idx.ptr;
|
||||||
new_wr->next = NULL;
|
li->next = NULL;
|
||||||
if (idx.ptr)
|
if (idx.ptr)
|
||||||
idx.ptr->next = new_wr;
|
idx.ptr->next = li;
|
||||||
idx.ptr = new_wr;
|
idx.ptr = li;
|
||||||
}
|
}
|
||||||
new_wr->block_num = block_num;
|
li->block_num = block_num;
|
||||||
new_wr->size = wr_size;
|
new_wr->size = wr_size;
|
||||||
new_wr->crc32c = new_wr->calc_crc32c();
|
new_wr->crc32c = new_wr->calc_crc32c();
|
||||||
return 0;
|
return 0;
|
||||||
@@ -989,7 +986,7 @@ int blockstore_heap_t::add_small_write(object_id oid, heap_entry_t *old_head, ui
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
uint32_t wr_size = get_small_entry_size(offset, len);
|
uint32_t wr_size = get_small_entry_size(offset, len);
|
||||||
return add_entry(wr_size, old_head, modified_block, false, [&](heap_entry_t *wr)
|
return add_entry(wr_size, modified_block, false, [&](heap_entry_t *wr)
|
||||||
{
|
{
|
||||||
wr->entry_type = type;
|
wr->entry_type = type;
|
||||||
wr->inode = oid.inode;
|
wr->inode = oid.inode;
|
||||||
@@ -1019,7 +1016,7 @@ int blockstore_heap_t::add_big_write(object_id oid, heap_entry_t *old_head, bool
|
|||||||
return EINVAL;
|
return EINVAL;
|
||||||
}
|
}
|
||||||
uint32_t wr_size = get_big_entry_size();
|
uint32_t wr_size = get_big_entry_size();
|
||||||
return add_entry(wr_size, old_head, modified_block, false, [&](heap_entry_t *wr)
|
return add_entry(wr_size, modified_block, false, [&](heap_entry_t *wr)
|
||||||
{
|
{
|
||||||
wr->entry_type = BS_HEAP_BIG_WRITE | (stable ? BS_HEAP_STABLE : 0);
|
wr->entry_type = BS_HEAP_BIG_WRITE | (stable ? BS_HEAP_STABLE : 0);
|
||||||
wr->inode = oid.inode;
|
wr->inode = oid.inode;
|
||||||
@@ -1061,7 +1058,7 @@ int blockstore_heap_t::add_compact(heap_entry_t *obj, uint64_t to_lsn, uint32_t
|
|||||||
if (!has_entry)
|
if (!has_entry)
|
||||||
{
|
{
|
||||||
uint64_t compact_lsn = obj->lsn;
|
uint64_t compact_lsn = obj->lsn;
|
||||||
return add_entry(get_simple_entry_size(), obj, modified_block, false, [&](heap_entry_t *wr)
|
return add_entry(get_simple_entry_size(), modified_block, false, [&](heap_entry_t *wr)
|
||||||
{
|
{
|
||||||
wr->entry_type = BS_HEAP_DELETE|BS_HEAP_STABLE;
|
wr->entry_type = BS_HEAP_DELETE|BS_HEAP_STABLE;
|
||||||
wr->inode = obj->inode;
|
wr->inode = obj->inode;
|
||||||
@@ -1078,7 +1075,7 @@ int blockstore_heap_t::add_compact(heap_entry_t *obj, uint64_t to_lsn, uint32_t
|
|||||||
}
|
}
|
||||||
auto oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
|
auto oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
|
||||||
uint32_t wr_size = get_big_entry_size();
|
uint32_t wr_size = get_big_entry_size();
|
||||||
return add_entry(wr_size, obj, modified_block, true, [&](heap_entry_t *new_wr)
|
return add_entry(wr_size, modified_block, true, [&](heap_entry_t *new_wr)
|
||||||
{
|
{
|
||||||
// obj and old_wr are invalid, re-read them - the block could have been compacted
|
// obj and old_wr are invalid, re-read them - the block could have been compacted
|
||||||
obj = read_entry(oid);
|
obj = read_entry(oid);
|
||||||
@@ -1187,7 +1184,7 @@ int blockstore_heap_t::add_punch_holes(heap_entry_t *obj, uint64_t to_lsn, uint6
|
|||||||
int blockstore_heap_t::add_simple(heap_entry_t *obj, uint64_t version, uint32_t *modified_block, uint32_t entry_type)
|
int blockstore_heap_t::add_simple(heap_entry_t *obj, uint64_t version, uint32_t *modified_block, uint32_t entry_type)
|
||||||
{
|
{
|
||||||
uint32_t wr_size = get_simple_entry_size();
|
uint32_t wr_size = get_simple_entry_size();
|
||||||
return add_entry(wr_size, obj, modified_block, false, [&](heap_entry_t *wr)
|
return add_entry(wr_size, modified_block, false, [&](heap_entry_t *wr)
|
||||||
{
|
{
|
||||||
wr->entry_type = entry_type;
|
wr->entry_type = entry_type;
|
||||||
wr->inode = obj->inode;
|
wr->inode = obj->inode;
|
||||||
@@ -1391,7 +1388,7 @@ void blockstore_heap_t::mark_garbage_up_to(heap_entry_t *wr)
|
|||||||
while (wr && !wr->is_garbage())
|
while (wr && !wr->is_garbage())
|
||||||
{
|
{
|
||||||
auto prev_wr = prev(wr);
|
auto prev_wr = prev(wr);
|
||||||
mark_garbage(wr->block_num, wr, used_big);
|
mark_garbage(list_item(wr)->block_num, wr, used_big);
|
||||||
wr = prev_wr;
|
wr = prev_wr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1586,7 +1583,7 @@ int blockstore_heap_t::list_objects(uint32_t pg_num, object_id min_oid, object_i
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
heap_entry_t *obj = stripe_pair.second.ptr;
|
heap_entry_t *obj = &stripe_pair.second.ptr->entry;
|
||||||
assert(obj->inode == oid.inode && obj->stripe == oid.stripe);
|
assert(obj->inode == oid.inode && obj->stripe == oid.stripe);
|
||||||
uint64_t stable_version = 0;
|
uint64_t stable_version = 0;
|
||||||
auto first_wr = obj;
|
auto first_wr = obj;
|
||||||
@@ -1710,10 +1707,10 @@ void blockstore_heap_t::get_meta_block(uint32_t block_num, uint8_t *buffer)
|
|||||||
{
|
{
|
||||||
auto & inf = block_info.at(block_num);
|
auto & inf = block_info.at(block_num);
|
||||||
size_t pos = 0;
|
size_t pos = 0;
|
||||||
for (auto entry: inf.entries)
|
for (auto li: inf.entries)
|
||||||
{
|
{
|
||||||
memcpy(buffer+pos, entry, entry->size);
|
memcpy(buffer+pos, &li->entry, li->entry.size);
|
||||||
pos += entry->size;
|
pos += li->entry.size;
|
||||||
}
|
}
|
||||||
memset(buffer+pos, 0, dsk->meta_block_size-pos);
|
memset(buffer+pos, 0, dsk->meta_block_size-pos);
|
||||||
}
|
}
|
||||||
@@ -1845,8 +1842,8 @@ void blockstore_heap_t::apply_inflight(heap_inflight_lsn_t & inflight)
|
|||||||
else if (inflight.flags & HEAP_INFLIGHT_GC)
|
else if (inflight.flags & HEAP_INFLIGHT_GC)
|
||||||
{
|
{
|
||||||
// Remove entry
|
// Remove entry
|
||||||
auto prev = wr->prev;
|
auto prev = list_item(wr)->prev;
|
||||||
auto next = wr->next;
|
auto next = list_item(wr)->next;
|
||||||
if (prev)
|
if (prev)
|
||||||
{
|
{
|
||||||
prev->next = next;
|
prev->next = next;
|
||||||
@@ -1858,13 +1855,13 @@ void blockstore_heap_t::apply_inflight(heap_inflight_lsn_t & inflight)
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
next->prev = prev;
|
next->prev = prev;
|
||||||
if (!prev && next->entry_type == (BS_HEAP_DELETE|BS_HEAP_STABLE))
|
if (!prev && next->entry.entry_type == (BS_HEAP_DELETE|BS_HEAP_STABLE))
|
||||||
{
|
{
|
||||||
// free BS_HEAP_DELETEs when their refcount becomes 1
|
// free BS_HEAP_DELETEs when their refcount becomes 1
|
||||||
mark_garbage(next->block_num, next, UINT32_MAX);
|
mark_garbage(next->block_num, &next->entry, UINT32_MAX);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
free(wr);
|
free(list_item(wr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,9 +45,6 @@ struct __attribute__((__packed__)) heap_entry_t
|
|||||||
uint64_t inode;
|
uint64_t inode;
|
||||||
uint64_t stripe;
|
uint64_t stripe;
|
||||||
uint64_t version;
|
uint64_t version;
|
||||||
uint32_t block_num; // FIXME this shit
|
|
||||||
heap_entry_t *prev; // FIXME and this shit too should be moved into a separate structure
|
|
||||||
heap_entry_t *next; // FIXME and this shit too
|
|
||||||
|
|
||||||
// uint8_t[] external_bitmap
|
// uint8_t[] external_bitmap
|
||||||
// uint8_t[] internal_bitmap
|
// uint8_t[] internal_bitmap
|
||||||
@@ -87,6 +84,14 @@ struct __attribute__((__packed__)) heap_big_write_t
|
|||||||
uint32_t block_num;
|
uint32_t block_num;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct __attribute__((__packed__)) heap_list_item_t
|
||||||
|
{
|
||||||
|
heap_list_item_t *prev;
|
||||||
|
heap_list_item_t *next;
|
||||||
|
uint32_t block_num;
|
||||||
|
heap_entry_t entry;
|
||||||
|
};
|
||||||
|
|
||||||
struct heap_object_mvcc_t
|
struct heap_object_mvcc_t
|
||||||
{
|
{
|
||||||
uint32_t readers = 0;
|
uint32_t readers = 0;
|
||||||
@@ -99,7 +104,7 @@ struct heap_block_info_t
|
|||||||
uint64_t mod_lsn = 0, mod_lsn_to = 0; // only 1 block write of LSN sequence is allowed at a moment
|
uint64_t mod_lsn = 0, mod_lsn_to = 0; // only 1 block write of LSN sequence is allowed at a moment
|
||||||
bool is_writing: 1;
|
bool is_writing: 1;
|
||||||
bool has_garbage: 1;
|
bool has_garbage: 1;
|
||||||
std::vector<heap_entry_t*> entries;
|
std::vector<heap_list_item_t*> entries;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct heap_inflight_lsn_t
|
struct heap_inflight_lsn_t
|
||||||
@@ -116,7 +121,7 @@ struct heap_compact_t
|
|||||||
|
|
||||||
struct heap_idx_t
|
struct heap_idx_t
|
||||||
{
|
{
|
||||||
heap_entry_t *ptr;
|
heap_list_item_t *ptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
using i64hash_t = robin_hood::hash<uint64_t>;
|
using i64hash_t = robin_hood::hash<uint64_t>;
|
||||||
@@ -174,8 +179,8 @@ class blockstore_heap_t
|
|||||||
void recheck_buffer(heap_entry_t *cwr, uint8_t *buf);
|
void recheck_buffer(heap_entry_t *cwr, uint8_t *buf);
|
||||||
void defragment_block(uint32_t block_num);
|
void defragment_block(uint32_t block_num);
|
||||||
|
|
||||||
int allocate_entry(uint32_t entry_size, uint32_t *block_num, heap_entry_t **entry, bool allow_last_free);
|
int allocate_entry(uint32_t entry_size, uint32_t *block_num, bool allow_last_free);
|
||||||
int add_entry(uint32_t wr_size, heap_entry_t *old_head, uint32_t *modified_block, bool allow_last_free,
|
int add_entry(uint32_t wr_size, uint32_t *modified_block, bool allow_last_free,
|
||||||
std::function<void(heap_entry_t *wr)> fill_entry);
|
std::function<void(heap_entry_t *wr)> fill_entry);
|
||||||
int add_simple(heap_entry_t *obj, uint64_t version, uint32_t *modified_block, uint32_t entry_type);
|
int add_simple(heap_entry_t *obj, uint64_t version, uint32_t *modified_block, uint32_t entry_type);
|
||||||
uint32_t meta_alloc_pos(const heap_block_info_t & inf);
|
uint32_t meta_alloc_pos(const heap_block_info_t & inf);
|
||||||
@@ -190,7 +195,8 @@ public:
|
|||||||
~blockstore_heap_t();
|
~blockstore_heap_t();
|
||||||
// load data from the disk, returns EDOM on corruption
|
// load data from the disk, returns EDOM on corruption
|
||||||
int read_blocks(uint64_t disk_offset, uint64_t size, uint8_t *buf,
|
int read_blocks(uint64_t disk_offset, uint64_t size, uint8_t *buf,
|
||||||
std::function<void(heap_entry_t*)> handle_write, std::function<void(uint32_t, uint32_t, uint8_t*)> handle_block);
|
std::function<void(uint32_t block_num, heap_entry_t* wr)> handle_write,
|
||||||
|
std::function<void(uint32_t, uint32_t, uint8_t*)> handle_block);
|
||||||
int load_blocks(uint64_t disk_offset, uint64_t size, uint8_t *buf, uint64_t &entries_loaded);
|
int load_blocks(uint64_t disk_offset, uint64_t size, uint8_t *buf, uint64_t &entries_loaded);
|
||||||
// finish loading
|
// finish loading
|
||||||
void finish_load();
|
void finish_load();
|
||||||
|
|||||||
@@ -427,7 +427,7 @@ static void test_padded_csum_intent(bool perfect)
|
|||||||
assert(memcheck(op2.buf+32*1024, 0, 96*1024));
|
assert(memcheck(op2.buf+32*1024, 0, 96*1024));
|
||||||
|
|
||||||
obj = test.bs->heap->read_entry((object_id){ .inode = 1, .stripe = 0 });
|
obj = test.bs->heap->read_entry((object_id){ .inode = 1, .stripe = 0 });
|
||||||
assert(!test.bs->heap->prev(obj));
|
assert(test.bs->heap->prev(obj) && test.bs->heap->prev(obj)->is_garbage());
|
||||||
|
|
||||||
free(op.buf);
|
free(op.buf);
|
||||||
free(op2.buf);
|
free(op2.buf);
|
||||||
|
|||||||
+18
-13
@@ -25,21 +25,26 @@ static int count_writes(blockstore_heap_t & heap, heap_entry_t *obj)
|
|||||||
|
|
||||||
bool check_used_space(blockstore_heap_t & heap, blockstore_disk_t & dsk, uint32_t block_num)
|
bool check_used_space(blockstore_heap_t & heap, blockstore_disk_t & dsk, uint32_t block_num)
|
||||||
{
|
{
|
||||||
// FIXME
|
uint8_t *buf = (uint8_t*)malloc_or_die(dsk.meta_block_size);
|
||||||
return true;
|
heap.get_meta_block(block_num, buf);
|
||||||
/* uint8_t *data = heap.get_meta_block(block_num);
|
uint8_t *data = buf;
|
||||||
uint8_t *end = data+dsk.meta_block_size;
|
uint8_t *end = data+dsk.meta_block_size;
|
||||||
uint32_t used = 0;
|
uint32_t used = 0;
|
||||||
while (data < end)
|
while (data < end)
|
||||||
{
|
{
|
||||||
heap_entry_t *wr = ((heap_entry_t*)data);
|
heap_entry_t *wr = ((heap_entry_t*)data);
|
||||||
if (!(wr->size & FREE_SPACE_BIT) && !(wr->prev_pos & GARBAGE_BIT))
|
if (!(wr->size & FREE_SPACE_BIT) && !wr->is_garbage())
|
||||||
{
|
{
|
||||||
used += wr->size;
|
used += wr->size;
|
||||||
}
|
}
|
||||||
|
if (!wr->size)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
data += (wr->size & ~FREE_SPACE_BIT);
|
data += (wr->size & ~FREE_SPACE_BIT);
|
||||||
}
|
}
|
||||||
return used == heap.get_meta_block_used_space(block_num);*/
|
free(buf);
|
||||||
|
return used == heap.get_meta_block_used_space(block_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
int _test_do_big_write(blockstore_heap_t & heap, blockstore_disk_t & dsk, uint64_t inode, uint64_t stripe, uint64_t version, uint64_t location,
|
int _test_do_big_write(blockstore_heap_t & heap, blockstore_disk_t & dsk, uint64_t inode, uint64_t stripe, uint64_t version, uint64_t location,
|
||||||
@@ -163,8 +168,8 @@ void test_mvcc(bool csum)
|
|||||||
|
|
||||||
assert(count_writes(heap, heap.read_entry(oid)) == 3); // MVCC prevents GC of old entries
|
assert(count_writes(heap, heap.read_entry(oid)) == 3); // MVCC prevents GC of old entries
|
||||||
|
|
||||||
//assert(heap.unlock_entry(oid));
|
assert(heap.unlock_entry(oid));
|
||||||
//assert(count_writes(heap, heap.read_entry(oid)) == 1); // Now we unlock it and old entries are GCed
|
assert(count_writes(heap, heap.read_entry(oid)) == 3); // Now we unlock it and old entries are GCed, but left in the list
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("OK test_mvcc %s\n", csum ? "csum" : "no_csum");
|
printf("OK test_mvcc %s\n", csum ? "csum" : "no_csum");
|
||||||
@@ -279,8 +284,8 @@ void test_defrag_block()
|
|||||||
|
|
||||||
uint32_t big_write_size = heap.get_big_entry_size();
|
uint32_t big_write_size = heap.get_big_entry_size();
|
||||||
uint32_t small_write_size = heap.get_small_entry_size(0, 4096);
|
uint32_t small_write_size = heap.get_small_entry_size(0, 4096);
|
||||||
assert(big_write_size == 200);
|
assert(big_write_size == 180);
|
||||||
assert(small_write_size == 84);
|
assert(small_write_size == 64);
|
||||||
uint32_t nwr = 0;
|
uint32_t nwr = 0;
|
||||||
bool add = false;
|
bool add = false;
|
||||||
if ((dsk.meta_block_size % (big_write_size+small_write_size)) >= big_write_size)
|
if ((dsk.meta_block_size % (big_write_size+small_write_size)) >= big_write_size)
|
||||||
@@ -437,7 +442,7 @@ void test_compact(bool csum, bool stable)
|
|||||||
|
|
||||||
obj = heap.read_entry(oid);
|
obj = heap.read_entry(oid);
|
||||||
assert(obj);
|
assert(obj);
|
||||||
assert(count_writes(heap, obj) == 1);
|
assert(count_writes(heap, obj) == (stable ? 3 : 4));
|
||||||
assert(obj->version == 3);
|
assert(obj->version == 3);
|
||||||
bitmap_set(ref_int_bitmap, 8192, 4096, 4096);
|
bitmap_set(ref_int_bitmap, 8192, 4096, 4096);
|
||||||
assert(!memcmp(obj->get_int_bitmap(&heap), ref_int_bitmap, dsk.clean_entry_bitmap_size));
|
assert(!memcmp(obj->get_int_bitmap(&heap), ref_int_bitmap, dsk.clean_entry_bitmap_size));
|
||||||
@@ -933,7 +938,7 @@ void test_rollback()
|
|||||||
|
|
||||||
obj = heap.read_entry(oid);
|
obj = heap.read_entry(oid);
|
||||||
assert(obj);
|
assert(obj);
|
||||||
assert(count_writes(heap, obj) == 4);
|
assert(count_writes(heap, obj) == 6);
|
||||||
|
|
||||||
assert(heap.get_to_compact_count() == 1);
|
assert(heap.get_to_compact_count() == 1);
|
||||||
|
|
||||||
@@ -1070,8 +1075,8 @@ void test_full_alloc()
|
|||||||
|
|
||||||
uint32_t big_write_size = heap.get_big_entry_size();
|
uint32_t big_write_size = heap.get_big_entry_size();
|
||||||
uint32_t small_write_size = heap.get_small_entry_size(0, 4096);
|
uint32_t small_write_size = heap.get_small_entry_size(0, 4096);
|
||||||
assert(big_write_size == 192);
|
assert(big_write_size == 180);
|
||||||
assert(small_write_size == 76);
|
assert(small_write_size == 64);
|
||||||
uint32_t epb = dsk.meta_block_size/big_write_size;
|
uint32_t epb = dsk.meta_block_size/big_write_size;
|
||||||
for (int j = 0; j < 4; j++)
|
for (int j = 0; j < 4; j++)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user