Previously we just rely on the unordered_set order to iterate over the BaseObjects, which is not deterministic. The iteration is only used in printing, verification, and snapshot generation. In the first two cases the performance overhead of sorting does not matter because they are only used for debugging. In the last case the determinism is more important than the trivial overhead of sorting. So this patch makes the iteration deterministic by sorting the set first, as what is already being done when we drain the queue. PR-URL: https://github.com/nodejs/node/pull/48702 Refs: https://github.com/nodejs/build/issues/3043 Reviewed-By: Tobias Nießen <tniessen@tnie.de> Reviewed-By: Yagiz Nizipli <yagiz@nizipli.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com>
52 lines
1.7 KiB
C++
52 lines
1.7 KiB
C++
#include "cleanup_queue.h" // NOLINT(build/include_inline)
|
|
#include <algorithm>
|
|
#include <vector>
|
|
#include "cleanup_queue-inl.h"
|
|
|
|
namespace node {
|
|
|
|
std::vector<CleanupQueue::CleanupHookCallback> CleanupQueue::GetOrdered()
|
|
const {
|
|
// Copy into a vector, since we can't sort an unordered_set in-place.
|
|
std::vector<CleanupHookCallback> callbacks(cleanup_hooks_.begin(),
|
|
cleanup_hooks_.end());
|
|
// We can't erase the copied elements from `cleanup_hooks_` yet, because we
|
|
// need to be able to check whether they were un-scheduled by another hook.
|
|
|
|
std::sort(callbacks.begin(),
|
|
callbacks.end(),
|
|
[](const CleanupHookCallback& a, const CleanupHookCallback& b) {
|
|
// Sort in descending order so that the most recently inserted
|
|
// callbacks are run first.
|
|
return a.insertion_order_counter_ > b.insertion_order_counter_;
|
|
});
|
|
|
|
return callbacks;
|
|
}
|
|
|
|
void CleanupQueue::Drain() {
|
|
std::vector<CleanupHookCallback> callbacks = GetOrdered();
|
|
|
|
for (const CleanupHookCallback& cb : callbacks) {
|
|
if (cleanup_hooks_.count(cb) == 0) {
|
|
// This hook was removed from the `cleanup_hooks_` set during another
|
|
// hook that was run earlier. Nothing to do here.
|
|
continue;
|
|
}
|
|
|
|
cb.fn_(cb.arg_);
|
|
cleanup_hooks_.erase(cb);
|
|
}
|
|
}
|
|
|
|
size_t CleanupQueue::CleanupHookCallback::Hash::operator()(
|
|
const CleanupHookCallback& cb) const {
|
|
return std::hash<void*>()(cb.arg_);
|
|
}
|
|
|
|
bool CleanupQueue::CleanupHookCallback::Equal::operator()(
|
|
const CleanupHookCallback& a, const CleanupHookCallback& b) const {
|
|
return a.fn_ == b.fn_ && a.arg_ == b.arg_;
|
|
}
|
|
|
|
} // namespace node
|