8000 Get rid of parent reference when marking node for deletion (#21779) · arangodb/arangodb@3258958 · GitHub
[go: up one dir, main page]

Skip to content

Commit 3258958

Browse files
authored
Get rid of parent reference when marking node for deletion (#21779)
1 parent ed9e585 commit 3258958

File tree

3 files changed

+14
-82
lines changed

3 files changed

+14
-82
lines changed

lib/TaskMonitoring/include/TaskMonitoring/task.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,6 @@ struct TaskInRegistry {
122122

123123
std::string const name;
124124
std::atomic<State> state;
125-
std::atomic<bool> isDeleted = false;
126125
ParentTask parent;
127126
std::optional<basics::ThreadId>
128127
running_thread; // proably has to also be atomic because

lib/TaskMonitoring/task.cpp

Lines changed: 14 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -73,74 +73,25 @@ auto TaskInRegistry::snapshot() -> TaskSnapshot {
7373

7474
namespace {
7575
/**
76-
Marks itself for deletion and all finishes parent nodes that do not have any
77-
other children.
76+
Marks itself for deletion and deletes a parent reference.
7877
79-
Loops over the hierarchy of parents of the given node. This function makes
80-
sure that these hierarchies are all marked for deletion together and can
81-
therefore be deleted in the next garbage collection run. Otherwise, a parent
82-
exists as long as its last child is not garbage collected because the child
83-
owns a shared reference to the parent, requiring as many garbage collection
84-
cycles as hierarchy levels to cleanup the given hierarchy.
85-
86-
Some examples:
87-
88-
If there are dependencies like (A └ B means A is parent of B)
89-
node_A
90-
└ node_B
91-
└ node (input to this function)
92-
and all of these nodes do not have any other references and are therefore
93-
finished, then this function makes sure that all of these node are marked for
94-
deletion.
95-
96-
If we have dependencies like
97-
node_A
98-
├ node_B
99-
└ node_C
100-
└ node (input to this function)
101-
with node_C and node beeing finished, this function will mark node_C and node
102-
for deletion but neither node_B nor node_A, independent of their state.
78+
Deleting the parent reference makes sure that
79+
a parent can directly be marked for deletion when all its children are
80+
marked. Otherwise, we need to wait for the garbage collection to delete the
81+
references, possibly requiring several garbage collection cycles to delete
82+
all hierarchy levels.
10383
*/
10484
auto mark_finished_nodes_for_deletion(Node* node) {
105-
auto current_node = node;
106-
while (true) {
107-
auto specific_node =
108-
reinterpret_cast<containers::ThreadOwnedList<TaskInRegistry>::Node*>(
109-
current_node);
110-
111-
// make sure that we don't mark a node twice for deletion
112-
auto expected = false;
113-
if (not specific_node->data.isDeleted.compare_exchange_strong(
114-
expected, true, std::memory_order_acq_rel)) {
115-
break;
116-
}
117-
118-
// do not continue if node does not have a parent
119-
auto& parent = specific_node->data.parent;
120-
if (not std::holds_alternative<NodeReference>(parent)) {
121-
specific_node->list->mark_for_deletion(specific_node);
122-
break;
123-
}
124-
// do not continue if node is not the only child of parent
125-
// if child is the only reference to parent, parent is not running any more
126-
// (there is no Task that holds another shared reference) so no new children
127-
// can be added to the parent
128-
auto& parent_ref = std::get<NodeReference>(parent);
129-
if (parent_ref.use_count() != 1) {
130-
// if we miss decrement updates here, it does not matter:
131-
// miss 2 -> 1: parent mark for deletion is done by the other child
132-
// miss 1 -> 0: loop once more but exit early because isDeleted==true
133-
specific_node->list->mark_for_deletion(specific_node);
134-
break;
135-
}
85+
auto specific_node =
86+
reinterpret_cast<containers::ThreadOwnedList<TaskInRegistry>::Node*>(
87+
node);
13688

137-
// continue with parent node
138-
current_node = parent_ref.get();
89+
// get rid of parent task and delete a shared reference
90+
specific_node->data.parent = {RootTask{}};
13991

140-
// mark node for deletion needs to be last action on specific_node, because
141-
// then a garbage collection run can destroy the node at any time
142-
specific_node->list->mark_for_deletion(specific_node);
143-
}
92+
// mark node for deletion needs to be last action on specific_node, because
93+
// then a garbage collection run can destroy the node at any time
94+
specific_node->list->mark_for_deletion(specific_node);
14495
}
14596
} // namespace
14697

tests/TaskMonitoring/TaskRegistryTest.cpp

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -54,24 +54,6 @@ struct MyTask : public Task {
5454

5555
struct TaskRegistryTest : ::testing::Test {
5656
void TearDown() override {
57-
// garbage collection has to run at most twice in order to clean everything
58-
// up on the current thread:
59-
// - when a child task scope is deleted, the child's task-in-registry is
60-
// marked for deletion
61-
// - at this point its parent task scope can still exist, therefore it is
62-
// not marked for deletion inside the child task scope destructor
63-
// - when then the parent task scope is deleted, the parent's
64-
// task-in-registry is still referenced by the child's task-in-registry
65-
// (which is not yet deleted), therefore it is not yet marked for deletion
66-
67-
// the first gc run destroys the child's task-in-registry
68-
// which destroys the last reference to the parent's task-in-registry, which
69-
// is therfore marked for deletion (together with all remaining
70-
// task-in-registries higher up in the hierarchy that are not referenced by
71-
// any other tasks)
72-
get_thread_registry().garbage_collect();
73-
// the second gc run destroys the parent's task-in-registry (and possibly
74-
// other marked for deletion items)
7557
get_thread_registry().garbage_collect();
7658
EXPECT_EQ(get_all_tasks().size(), 0);
7759
}

0 commit comments

Comments
 (0)
0