unordered_map mvcc
This commit is contained in:
@@ -857,33 +857,43 @@ heap_object_t *blockstore_heap_t::lock_and_read_entry(object_id oid, uint64_t &
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
auto mvcc_it = object_mvcc.lower_bound({ .oid = { .inode = oid.inode, .stripe = oid.stripe+1 }, .lsn = 0 });
|
||||
copy_id = 1;
|
||||
if (mvcc_it != object_mvcc.begin())
|
||||
heap_mvcc_copy_id_t mvcc_id = { .oid = { .inode = oid.inode, .stripe = oid.stripe }, .copy_id = 1 };
|
||||
auto mvcc_it = object_mvcc.find(mvcc_id);
|
||||
if (mvcc_it != object_mvcc.end())
|
||||
{
|
||||
mvcc_it--;
|
||||
if (mvcc_it->first.oid == oid)
|
||||
while (true)
|
||||
{
|
||||
if (mvcc_it->second.entry_copy)
|
||||
mvcc_id.copy_id++;
|
||||
auto next_it = object_mvcc.find(mvcc_id);
|
||||
if (next_it == object_mvcc.end())
|
||||
{
|
||||
// Already modified, need to create another copy
|
||||
copy_id = mvcc_it->first.lsn+1;
|
||||
}
|
||||
else
|
||||
{
|
||||
copy_id = mvcc_it->first.lsn;
|
||||
mvcc_it->second.readers++;
|
||||
return obj;
|
||||
mvcc_id.copy_id--;
|
||||
break;
|
||||
}
|
||||
mvcc_it = next_it;
|
||||
}
|
||||
if (mvcc_it->second.entry_copy)
|
||||
{
|
||||
// Already modified, need to create another copy
|
||||
mvcc_id.copy_id++;
|
||||
object_mvcc[mvcc_id] = (heap_object_mvcc_t){ .readers = 1 };
|
||||
}
|
||||
else
|
||||
{
|
||||
mvcc_it->second.readers++;
|
||||
}
|
||||
}
|
||||
object_mvcc[(heap_object_lsn_t){ .oid = oid, .lsn = copy_id }] = (heap_object_mvcc_t){ .readers = 1 };
|
||||
else
|
||||
{
|
||||
object_mvcc[mvcc_id] = (heap_object_mvcc_t){ .readers = 1 };
|
||||
}
|
||||
copy_id = mvcc_id.copy_id;
|
||||
return obj;
|
||||
}
|
||||
|
||||
heap_object_t *blockstore_heap_t::read_locked_entry(object_id oid, uint64_t copy_id)
|
||||
{
|
||||
auto mvcc_it = object_mvcc.find((heap_object_lsn_t){ .oid = oid, .lsn = copy_id });
|
||||
auto mvcc_it = object_mvcc.find((heap_mvcc_copy_id_t){ .oid = oid, .copy_id = copy_id });
|
||||
if (mvcc_it == object_mvcc.end())
|
||||
{
|
||||
return NULL;
|
||||
@@ -895,9 +905,22 @@ heap_object_t *blockstore_heap_t::read_locked_entry(object_id oid, uint64_t copy
|
||||
return read_entry(oid, NULL);
|
||||
}
|
||||
|
||||
void blockstore_heap_t::free_mvcc(std::unordered_map<heap_mvcc_copy_id_t, heap_object_mvcc_t>::iterator mvcc_it)
|
||||
{
|
||||
if (mvcc_it->second.entry_copy)
|
||||
{
|
||||
// Free refcounted data & buffer blocks
|
||||
heap_object_t *obj = (heap_object_t*)mvcc_it->second.entry_copy;
|
||||
free_object_space(obj->inode, obj->get_writes(), NULL, BS_HEAP_FREE_MVCC);
|
||||
free(mvcc_it->second.entry_copy);
|
||||
}
|
||||
object_mvcc.erase(mvcc_it);
|
||||
}
|
||||
|
||||
bool blockstore_heap_t::unlock_entry(object_id oid, uint64_t copy_id)
|
||||
{
|
||||
auto mvcc_it = object_mvcc.find((heap_object_lsn_t){ .oid = oid, .lsn = copy_id });
|
||||
auto mvcc_id = (heap_mvcc_copy_id_t){ .oid = oid, .copy_id = copy_id };
|
||||
auto mvcc_it = object_mvcc.find(mvcc_id);
|
||||
if (mvcc_it == object_mvcc.end())
|
||||
{
|
||||
return false;
|
||||
@@ -905,37 +928,37 @@ bool blockstore_heap_t::unlock_entry(object_id oid, uint64_t copy_id)
|
||||
mvcc_it->second.readers--;
|
||||
if (!mvcc_it->second.readers)
|
||||
{
|
||||
if (mvcc_it->second.entry_copy)
|
||||
mvcc_id.copy_id++;
|
||||
if (object_mvcc.find(mvcc_id) != object_mvcc.end())
|
||||
{
|
||||
// Free refcounted data & buffer blocks
|
||||
heap_object_t *obj = (heap_object_t*)mvcc_it->second.entry_copy;
|
||||
free_object_space(obj->inode, obj->get_writes(), NULL, BS_HEAP_FREE_MVCC);
|
||||
bool is_last_mvcc = true;
|
||||
if (mvcc_it != object_mvcc.end())
|
||||
{
|
||||
// object_mvcc may contain multiple copied entries, but always in a whole sequence
|
||||
auto next_it = std::next(mvcc_it);
|
||||
if (next_it->first.oid == oid && next_it->second.entry_copy)
|
||||
is_last_mvcc = false;
|
||||
}
|
||||
if (is_last_mvcc && mvcc_it != object_mvcc.begin())
|
||||
{
|
||||
auto prev_it = std::prev(mvcc_it);
|
||||
if (prev_it->first.oid == oid && prev_it->second.entry_copy)
|
||||
is_last_mvcc = false;
|
||||
}
|
||||
if (is_last_mvcc)
|
||||
{
|
||||
// Free data references from the newest object version when the last MVCC is freed
|
||||
heap_object_t *new_obj = read_entry(oid, NULL);
|
||||
if (new_obj)
|
||||
{
|
||||
free_object_space(new_obj->inode, new_obj->get_writes(), NULL, BS_HEAP_FREE_MAIN);
|
||||
}
|
||||
}
|
||||
free(mvcc_it->second.entry_copy);
|
||||
// Next entry isn't freed yet
|
||||
return true;
|
||||
}
|
||||
mvcc_id.copy_id--;
|
||||
// Free this entry
|
||||
free_mvcc(mvcc_it);
|
||||
// Free all previous entries with 0 refcount
|
||||
while (mvcc_id.copy_id > 1)
|
||||
{
|
||||
mvcc_id.copy_id--;
|
||||
mvcc_it = object_mvcc.find(mvcc_id);
|
||||
assert(mvcc_it != object_mvcc.end());
|
||||
if (mvcc_it->second.readers)
|
||||
{
|
||||
mvcc_id.copy_id++;
|
||||
break;
|
||||
}
|
||||
free_mvcc(mvcc_it);
|
||||
}
|
||||
if (mvcc_id.copy_id == 1)
|
||||
{
|
||||
// Free data references from the newest object version when the last MVCC is freed
|
||||
heap_object_t *new_obj = read_entry(oid, NULL);
|
||||
if (new_obj)
|
||||
{
|
||||
free_object_space(new_obj->inode, new_obj->get_writes(), NULL, BS_HEAP_FREE_MAIN);
|
||||
}
|
||||
}
|
||||
object_mvcc.erase(mvcc_it);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -1306,13 +1329,13 @@ int blockstore_heap_t::add_object(object_id oid, heap_write_t *wr, uint32_t *mod
|
||||
|
||||
bool blockstore_heap_t::mvcc_check_tracking(object_id oid)
|
||||
{
|
||||
auto mvcc_it = object_mvcc.lower_bound({ .oid = { .inode = oid.inode, .stripe = oid.stripe }, .lsn = 0 });
|
||||
auto mvcc_it = object_mvcc.find((heap_mvcc_copy_id_t){ .oid = oid, .copy_id = 1 });
|
||||
if (mvcc_it == object_mvcc.end())
|
||||
{
|
||||
// no copies
|
||||
return false;
|
||||
}
|
||||
return (mvcc_it->first.oid == oid && mvcc_it->second.entry_copy);
|
||||
return mvcc_it->second.entry_copy;
|
||||
}
|
||||
|
||||
void blockstore_heap_t::copy_full_object(uint8_t *dst, heap_object_t *obj)
|
||||
@@ -1335,17 +1358,23 @@ void blockstore_heap_t::copy_full_object(uint8_t *dst, heap_object_t *obj)
|
||||
bool blockstore_heap_t::mvcc_save_copy(heap_object_t *obj)
|
||||
{
|
||||
auto oid = (object_id){ .inode = obj->inode, .stripe = obj->stripe };
|
||||
auto mvcc_it = object_mvcc.lower_bound({ .oid = { .inode = oid.inode, .stripe = oid.stripe+1 }, .lsn = 0 });
|
||||
if (mvcc_it == object_mvcc.begin())
|
||||
auto mvcc_id = (heap_mvcc_copy_id_t){ .oid = oid, .copy_id = 1 };
|
||||
auto mvcc_it = object_mvcc.find(mvcc_id);
|
||||
if (mvcc_it == object_mvcc.end())
|
||||
{
|
||||
// no copies
|
||||
return false;
|
||||
}
|
||||
mvcc_it--;
|
||||
if (mvcc_it->first.oid != oid)
|
||||
while (true)
|
||||
{
|
||||
// no copies :-)
|
||||
return false;
|
||||
mvcc_id.copy_id++;
|
||||
auto next_it = object_mvcc.find(mvcc_id);
|
||||
if (next_it == object_mvcc.end())
|
||||
{
|
||||
mvcc_id.copy_id--;
|
||||
break;
|
||||
}
|
||||
mvcc_it = next_it;
|
||||
}
|
||||
if (mvcc_it->second.entry_copy)
|
||||
{
|
||||
@@ -1365,7 +1394,7 @@ bool blockstore_heap_t::mvcc_save_copy(heap_object_t *obj)
|
||||
bool for_obj = false;
|
||||
// save_copy is performed when the object is modified, so object_mvcc may only
|
||||
// contain 1 version with entry_copy == NULL
|
||||
if (mvcc_it == object_mvcc.begin() || std::prev(mvcc_it)->first.oid != oid)
|
||||
if (mvcc_id.copy_id == 1)
|
||||
{
|
||||
// Init refcounts for the copy and for the object itself, when it's the first MVCC entry
|
||||
add_ref = 2;
|
||||
|
||||
@@ -97,6 +97,31 @@ struct tmp_compact_item_t
|
||||
bool compact;
|
||||
};
|
||||
|
||||
struct heap_mvcc_copy_id_t
|
||||
{
|
||||
object_id oid;
|
||||
uint64_t copy_id;
|
||||
};
|
||||
|
||||
inline bool operator == (const heap_mvcc_copy_id_t & a, const heap_mvcc_copy_id_t & b)
|
||||
{
|
||||
return a.oid.inode == b.oid.inode && a.oid.stripe == b.oid.stripe && a.copy_id == b.copy_id;
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<> struct hash<heap_mvcc_copy_id_t>
|
||||
{
|
||||
inline size_t operator()(const heap_mvcc_copy_id_t &s) const
|
||||
{
|
||||
size_t seed = std::hash<object_id>()(s.oid);
|
||||
// Copy-pasted from spp::hash_combine()
|
||||
seed ^= (s.copy_id + 0xc6a4a7935bd1e995 + (seed << 6) + (seed >> 2));
|
||||
return seed;
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
struct heap_object_mvcc_t
|
||||
{
|
||||
uint32_t readers = 0;
|
||||
@@ -149,7 +174,7 @@ class blockstore_heap_t
|
||||
uint32_t meta_alloc_count = 0;
|
||||
uint64_t meta_used_space = 0;
|
||||
multilist_alloc_t *buffer_alloc = NULL;
|
||||
std::map<heap_object_lsn_t, heap_object_mvcc_t> object_mvcc;
|
||||
std::unordered_map<heap_mvcc_copy_id_t, heap_object_mvcc_t> object_mvcc;
|
||||
std::unordered_map<uint64_t, uint32_t> mvcc_data_refs;
|
||||
std::unordered_map<uint64_t, uint32_t> mvcc_buffer_refs;
|
||||
std::map<uint64_t, uint64_t> inode_space_stats;
|
||||
@@ -184,6 +209,7 @@ class blockstore_heap_t
|
||||
void copy_full_object(uint8_t *dst, heap_object_t *obj);
|
||||
bool mvcc_save_copy(heap_object_t *obj);
|
||||
bool mvcc_check_tracking(object_id oid);
|
||||
void free_mvcc(std::unordered_map<heap_mvcc_copy_id_t, heap_object_mvcc_t>::iterator mvcc_it);
|
||||
void allocate_block(heap_block_info_t & inf);
|
||||
int add_object(object_id oid, heap_write_t *wr, uint32_t *modified_block);
|
||||
void mark_overwritten(uint64_t over_lsn, uint64_t inode, heap_write_t *wr, heap_write_t *end_wr, bool tracking_active);
|
||||
|
||||
Reference in New Issue
Block a user