diff --git a/flow/include/flow/IndexedSet.actor.h b/flow/include/flow/IndexedSet.actor.h deleted file mode 100644 index 147786303cc..00000000000 --- a/flow/include/flow/IndexedSet.actor.h +++ /dev/null @@ -1,75 +0,0 @@ -/* - * IndexedSet.actor.h - * - * This source file is part of the FoundationDB open source project - * - * Copyright 2013-2026 Apple Inc. and the FoundationDB project authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -// When actually compiled (NO_INTELLISENSE), include the generated version of this file. In intellisense use the source -// version. -#if defined(NO_INTELLISENSE) && !defined(FLOW_INDEXEDSET_ACTOR_G_H) -#define FLOW_INDEXEDSET_ACTOR_G_H -#include "flow/IndexedSet.actor.g.h" -#elif !defined(FLOW_INDEXEDSET_ACTOR_H) -#define FLOW_INDEXEDSET_ACTOR_H - -#include "flow/flow.h" -#include "flow/Platform.h" -#include "flow/actorcompiler.h" // This must be the last #include. - -ACTOR template -[[flow_allow_discard]] Future ISFreeNodes(std::vector toFree, bool synchronous) { - // Frees the forest of nodes in the 'toFree' vector. - // If 'synchronous' is true, then there can be no waits. - - state int eraseCount = 0; - - // Freeing many items from a large tree is bound by the memory latency to - // fetch each node from main memory. This code does a largely depth first - // traversal of the forest to be destroyed (using a stack) but prefetches - // each node and puts it on a short queue before actually processing it, so - // that several memory transactions can be outstanding simultaneously. - state Deque prefetchQueue; - while (!prefetchQueue.empty() || !toFree.empty()) { - - while (prefetchQueue.size() < 10 && !toFree.empty()) { - _mm_prefetch((const char*)toFree.back(), _MM_HINT_T0); - prefetchQueue.push_back(toFree.back()); - toFree.pop_back(); - } - - auto n = prefetchQueue.front(); - prefetchQueue.pop_front(); - - if (n->child[0]) - toFree.push_back(n->child[0]); - if (n->child[1]) - toFree.push_back(n->child[1]); - n->child[0] = n->child[1] = 0; - delete n; - ++eraseCount; - - if (!synchronous && eraseCount % 1000 == 0) - wait(yield()); - } - - return Void(); -} - -#include "flow/unactorcompiler.h" -#endif diff --git a/flow/include/flow/IndexedSet.h b/flow/include/flow/IndexedSet.h index 74daee5ffbc..3235cd70e05 100644 --- a/flow/include/flow/IndexedSet.h +++ b/flow/include/flow/IndexedSet.h @@ -1384,7 +1384,60 @@ Metric IndexedSet::sumTo(typename IndexedSet::const_iterat } #include "flow/flow.h" -#include "flow/IndexedSet.actor.h" + +template +bool ISFreeNodeImpl(std::vector& toFree, Deque& prefetchQueue) { + // Freeing many items from a large tree is bound by the memory latency to + // fetch each node from main memory. This code does a largely depth first + // traversal of the forest to be destroyed (using a stack) but prefetches + // each node and puts it on a short queue before actually processing it, so + // that several memory transactions can be outstanding simultaneously. + if (prefetchQueue.empty() && toFree.empty()) { + return false; + } + + while (prefetchQueue.size() < 10 && !toFree.empty()) { + _mm_prefetch((const char*)toFree.back(), _MM_HINT_T0); + prefetchQueue.push_back(toFree.back()); + toFree.pop_back(); + } + + auto n = prefetchQueue.front(); + prefetchQueue.pop_front(); + + if (n->child[0]) + toFree.push_back(n->child[0]); + if (n->child[1]) + toFree.push_back(n->child[1]); + n->child[0] = n->child[1] = 0; + delete n; + + return true; +} + +template +void ISFreeNodesSync(std::vector toFree) { + // Frees the forest of nodes in the 'toFree' vector without waiting. + + Deque prefetchQueue; + while (ISFreeNodeImpl(toFree, prefetchQueue)) { + } +} + +template +Future ISFreeNodes(std::vector toFree) { + // Frees the forest of nodes in the 'toFree' vector, yielding periodically. + + int eraseCount = 0; + Deque prefetchQueue; + while (ISFreeNodeImpl(toFree, prefetchQueue)) { + ++eraseCount; + + if (eraseCount % 1000 == 0) { + co_await yield(); + } + } +} template void IndexedSet::erase(typename IndexedSet::iterator begin, @@ -1392,7 +1445,7 @@ void IndexedSet::erase(typename IndexedSet::iterator begin std::vector::Node*> toFree; erase(begin, end, toFree); - ISFreeNodes(toFree, true); + ISFreeNodesSync(toFree); } template @@ -1407,7 +1460,7 @@ Future IndexedSet::eraseAsync(typename IndexedSet::i std::vector::Node*> toFree; erase(begin, end, toFree); - return uncancellable(ISFreeNodes(toFree, false)); + return uncancellable(ISFreeNodes(toFree)); } template