Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
51 changes: 34 additions & 17 deletions src/dbzero/workspace/GC0.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
namespace db0

{

std::vector<GC_Ops> GC0::m_ops;
std::unordered_map<StorageClass, GCOps_ID> GC0::m_ops_map;
bool GC0::m_initialized = false;
std::shared_ptr<GC0_SharedState>& GC0::getGlobalSharedState()
{
// Enforce singleton-like behavior. Single initialization is guaranteed by C++.
static std::shared_ptr<GC0_SharedState> global_shared_state = std::make_shared<GC0_SharedState>();
return global_shared_state;
}

template <typename T> void dropByAddr(Memspace &memspace, Address addr, const std::vector<GC_Ops> &ops)
{
Expand All @@ -15,20 +17,27 @@ namespace db0
}

GC0::GC0(db0::swine_ptr<Fixture> &fixture)
: super_t(fixture)
: super_t(fixture)
, m_shared_state(getGlobalSharedState())
, m_read_only(false)
{
}

GC0::GC0(db0::swine_ptr<Fixture> &fixture, Address address, bool read_only)
: super_t(tag_from_address(), fixture, address)
, m_shared_state(getGlobalSharedState())
, m_read_only(read_only)
{
}

GC0::~GC0()
{
}

GC0_SharedState& GC0::getSharedState()
{
return *m_shared_state;
}

bool GC0::tryRemove(void *vptr, bool is_volatile)
{
Expand All @@ -39,7 +48,7 @@ namespace db0
}

NoArgsFunction drop_op = nullptr;
auto &ops = m_ops[it->second];
auto &ops = getSharedState().m_ops[it->second];
// if type implements flush then remove it from flush map as well
if (ops.flush) {
m_flush_map.erase(vptr);
Expand Down Expand Up @@ -80,8 +89,9 @@ namespace db0
void GC0::detachAll()
{
std::unique_lock<std::mutex> lock(m_mutex);
auto &ops_list = getSharedState().m_ops;
for (auto &vptr_item : m_vptr_map) {
m_ops[vptr_item.second].detach(vptr_item.first);
ops_list[vptr_item.second].detach(vptr_item.first);
}
}

Expand All @@ -97,10 +107,11 @@ namespace db0
std::unique_lock<std::mutex> lock(m_mutex);
std::unordered_set<TypedAddress> addresses;
std::size_t count = 0;
auto &ops_list = getSharedState().m_ops;
for (auto vptr : vptrs) {
auto it = m_vptr_map.find(vptr);
if (it != m_vptr_map.end()) {
auto &ops = m_ops[it->second];
auto &ops = ops_list[it->second];
ops.commit(vptr);
if (ops.hasRefs && !ops.hasRefs(vptr)) {
addresses.insert(toTypedAddress(ops.address(vptr)));
Expand All @@ -126,8 +137,9 @@ namespace db0
void GC0::commitAll()
{
std::unique_lock<std::mutex> lock(m_mutex);
auto &ops_list = getSharedState().m_ops;
for (auto &vptr_item : m_vptr_map) {
m_ops[vptr_item.second].commit(vptr_item.first);
ops_list[vptr_item.second].commit(vptr_item.first);
}
}

Expand Down Expand Up @@ -156,8 +168,9 @@ namespace db0
lock.unlock();

// call flush where it's provided
auto &ops_list = getSharedState().m_ops;
for (auto &item : flush_ops) {
m_ops[item.second].flush(item.first, false);
ops_list[item.second].flush(item.first, false);
}
}

Expand All @@ -171,20 +184,23 @@ namespace db0
if (!fixture) {
THROWF(db0::InternalException) << "GC0::collect: cannot collect without a valid fixture";
}

auto &ops_list = getSharedState().m_ops;
auto &ops_map = getSharedState().m_ops_map;

// drop scheduled for deletion
for (auto &addr_pair: m_scheduled_for_deletion) {
auto ops_id = m_ops_map[addr_pair.second];
assert(ops_id < m_ops.size());
m_ops[ops_id].dropByAddr(fixture, addr_pair.first.getAddress());
auto ops_id = ops_map[addr_pair.second];
assert(ops_id < ops_list.size());
ops_list[ops_id].dropByAddr(fixture, addr_pair.first.getAddress());
}
m_scheduled_for_deletion.clear();

for (auto addr: *this) {
auto ops_id = m_ops_map[addr.getType()];
assert(ops_id < m_ops.size());
auto ops_id = ops_map[addr.getType()];
assert(ops_id < ops_list.size());
// object will be dropped only if it has no references
m_ops[ops_id].dropByAddr(fixture, addr.getAddress());
ops_list[ops_id].dropByAddr(fixture, addr.getAddress());
}
super_t::clear();
}
Expand Down Expand Up @@ -213,8 +229,9 @@ namespace db0
}
}
// call reverse flush where it's provided (use revert=true)
auto &ops_list = getSharedState().m_ops;
for (auto &item : m_flush_map) {
m_ops[item.second].flush(item.first, true);
ops_list[item.second].flush(item.first, true);
}
m_volatile.clear();
m_atomic = false;
Expand Down
46 changes: 33 additions & 13 deletions src/dbzero/workspace/GC0.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,23 @@ namespace db0
return m_value;
}
};

struct GC0_SharedState
{
std::vector<GC_Ops> m_ops;
// GC-ops by storage class
std::unordered_map<StorageClass, GCOps_ID> m_ops_map;
// flag indicating if static bindings were initialized
bool m_initialized;

GC0_SharedState() = default;
// We don't want accidental copy
GC0_SharedState(const GC0_SharedState&) = delete;
GC0_SharedState(GC0_SharedState&&) = delete;
GC0_SharedState& operator=(const GC0_SharedState&) = delete;
GC0_SharedState& operator=(GC0_SharedState&) = delete;
};


#define GC0_Declare protected: \
friend class db0::GC0; \
Expand Down Expand Up @@ -130,11 +147,11 @@ namespace db0
std::optional<unsigned int> erase(void *vptr);

private:
static std::vector<GC_Ops> m_ops;
// GC-ops by storage class
static std::unordered_map<StorageClass, GCOps_ID> m_ops_map;
// flag indicating if static bindings were initialized
static bool m_initialized;
// Keep shared state 'alive' until it isn't needed anymore
std::shared_ptr<GC0_SharedState> m_shared_state;
static std::shared_ptr<GC0_SharedState>& getGlobalSharedState();
GC0_SharedState& getSharedState();

const bool m_read_only;
// type / ops_id
std::unordered_map<void*, unsigned int> m_vptr_map;
Expand All @@ -153,9 +170,10 @@ namespace db0

template <typename T> static void registerSingleType()
{
T::m_gc_ops_id = GCOps_ID(m_ops.size());
m_ops.push_back(T::getGC_Ops());
m_ops_map[T::storageClass()] = T::m_gc_ops_id;
auto &state = getGlobalSharedState();
T::m_gc_ops_id = GCOps_ID(state->m_ops.size());
state->m_ops.push_back(T::getGC_Ops());
state->m_ops_map[T::storageClass()] = T::m_gc_ops_id;
}
};

Expand All @@ -165,11 +183,12 @@ namespace db0
assert(vptr);
std::unique_lock<std::mutex> lock(m_mutex);
// detach function must always be provided
assert(m_ops[T::m_gc_ops_id].detach);
assert(m_ops[T::m_gc_ops_id].address);
auto &ops_list = getSharedState().m_ops;
assert(ops_list[T::m_gc_ops_id].detach);
assert(ops_list[T::m_gc_ops_id].address);
m_vptr_map[vptr] = T::m_gc_ops_id;
// if the type implements flush then also add it to the flush map
if (m_ops[T::m_gc_ops_id].flush) {
if (ops_list[T::m_gc_ops_id].flush) {
m_flush_map[vptr] = T::m_gc_ops_id;
}
if (m_atomic) {
Expand All @@ -193,12 +212,13 @@ namespace db0

template <typename... T> void GC0::registerTypes()
{
if (m_initialized) {
auto &state = getGlobalSharedState();
if (state->m_initialized) {
return;
}

(registerSingleType<T>(), ...);
m_initialized = true;
state->m_initialized = true;
}

}
Loading