Fix O(n^2) algorithm in the GC cleanup logic

This commit is contained in:
John Sully 2022-05-18 20:00:14 +00:00
parent ba1275f653
commit 5dbf1f6bd6

View File

@ -2,6 +2,7 @@
#include <vector> #include <vector>
#include <assert.h> #include <assert.h>
#include <unordered_set> #include <unordered_set>
#include <list>
struct ICollectable struct ICollectable
{ {
@ -45,14 +46,14 @@ public:
void shutdown() void shutdown()
{ {
std::unique_lock<fastlock> lock(m_lock); std::unique_lock<fastlock> lock(m_lock);
m_vecepochs.clear(); m_listepochs.clear();
m_setepochOutstanding.clear(); m_setepochOutstanding.clear();
} }
bool empty() const bool empty() const
{ {
std::unique_lock<fastlock> lock(m_lock); std::unique_lock<fastlock> lock(m_lock);
return m_vecepochs.empty(); return m_listepochs.empty();
} }
void endEpoch(uint64_t epoch, bool fNoFree = false) void endEpoch(uint64_t epoch, bool fNoFree = false)
@ -63,12 +64,12 @@ public:
m_setepochOutstanding.erase(epoch); m_setepochOutstanding.erase(epoch);
if (fNoFree) if (fNoFree)
return; return;
std::vector<EpochHolder> vecclean; std::list<EpochHolder> listclean;
// No outstanding epochs? // No outstanding epochs?
if (m_setepochOutstanding.empty()) if (m_setepochOutstanding.empty())
{ {
vecclean = std::move(m_vecepochs); // Everything goes! listclean = std::move(m_listepochs); // Everything goes!
} }
else else
{ {
@ -77,18 +78,20 @@ public:
return; // No available epochs to free return; // No available epochs to free
// Clean any epochs available (after the lock) // Clean any epochs available (after the lock)
for (size_t iepoch = 0; iepoch < m_vecepochs.size(); ++iepoch) for (auto itr = m_listepochs.begin(); itr != m_listepochs.end(); /* itr incremented in loop*/)
{ {
auto &e = m_vecepochs[iepoch]; auto &e = *itr;
auto itrNext = itr;
++itrNext;
if (e < minepoch) if (e < minepoch)
{ {
vecclean.emplace_back(std::move(e)); listclean.emplace_back(std::move(e));
m_vecepochs.erase(m_vecepochs.begin() + iepoch); m_listepochs.erase(itr);
--iepoch;
} }
itr = itrNext;
} }
assert(vecclean.empty() || fMinElement); assert(listclean.empty() || fMinElement);
} }
lock.unlock(); // don't hold it for the potentially long delete of vecclean lock.unlock(); // don't hold it for the potentially long delete of vecclean
@ -100,13 +103,13 @@ public:
serverAssert(m_setepochOutstanding.find(epoch) != m_setepochOutstanding.end()); serverAssert(m_setepochOutstanding.find(epoch) != m_setepochOutstanding.end());
serverAssert(sp->FWillFreeChildDebug() == false); serverAssert(sp->FWillFreeChildDebug() == false);
auto itr = std::find(m_vecepochs.begin(), m_vecepochs.end(), m_epochNext+1); auto itr = std::find(m_listepochs.begin(), m_listepochs.end(), m_epochNext+1);
if (itr == m_vecepochs.end()) if (itr == m_listepochs.end())
{ {
EpochHolder e; EpochHolder e;
e.tstamp = m_epochNext+1; e.tstamp = m_epochNext+1;
e.m_vecObjs.push_back(std::move(sp)); e.m_vecObjs.push_back(std::move(sp));
m_vecepochs.emplace_back(std::move(e)); m_listepochs.emplace_back(std::move(e));
} }
else else
{ {
@ -117,7 +120,7 @@ public:
private: private:
mutable fastlock m_lock { "Garbage Collector"}; mutable fastlock m_lock { "Garbage Collector"};
std::vector<EpochHolder> m_vecepochs; std::list<EpochHolder> m_listepochs;
std::unordered_set<uint64_t> m_setepochOutstanding; std::unordered_set<uint64_t> m_setepochOutstanding;
uint64_t m_epochNext = 0; uint64_t m_epochNext = 0;
}; };