@@ -1957,9 +1957,23 @@ class ToDeleteTreeCollector
19571957 uint32_t nodes_observed = 1 ; // / root node
19581958
19591959 std::list<KeeperStorageBase::Delta> deltas;
1960- using UncommittedChildren
1960+ using ProcessedUncommittedChildren
19611961 = std::unordered_set<std::string_view, StringHashForHeterogeneousLookup, StringHashForHeterogeneousLookup::transparent_key_equal>;
19621962
1963+ struct PathCmp
1964+ {
1965+ auto operator ()(const std::string_view a,
1966+ const std::string_view b) const
1967+ {
1968+ size_t level_a = std::count (a.begin (), a.end (), ' /' );
1969+ size_t level_b = std::count (b.begin (), b.end (), ' /' );
1970+ return level_a < level_b || (level_a == level_b && a < b);
1971+ }
1972+
1973+ using is_transparent = void ; // required to make find() work with different type than key_type
1974+ };
1975+
1976+ std::map<std::string_view, typename Storage::UncommittedState::UncommittedNode *, PathCmp> uncommitted_children;
19631977public:
19641978 enum class CollectStatus
19651979 {
@@ -1983,6 +1997,16 @@ class ToDeleteTreeCollector
19831997 if (checkLimits (root_node))
19841998 return CollectStatus::LimitExceeded;
19851999
2000+ // / Collect uncommitted children of root node in a specialized structure so we avoid iterating all uncommitted
2001+ // / nodes for each child node.
2002+ auto & nodes = storage.uncommitted_state .nodes ;
2003+ auto root_path_view = root_path.toView ();
2004+ for (auto & [node_path, uncommitted_node] : nodes)
2005+ {
2006+ if (Coordination::matchPath (node_path, root_path_view) == Coordination::PathMatchResult::IS_CHILD)
2007+ uncommitted_children[node_path] = &uncommitted_node;
2008+ }
2009+
19862010 addDelta (root_path, root_node.stats , storage.uncommitted_state .getACLs (root_path), std::string{root_node.getData ()});
19872011
19882012 for (auto current_delta_it = deltas.rbegin (); current_delta_it != deltas.rend (); ++current_delta_it)
@@ -1993,18 +2017,18 @@ class ToDeleteTreeCollector
19932017 if (!storage.checkACL (current_path, Coordination::ACL::Delete, session_id, /* is_local=*/ false ))
19942018 return CollectStatus::NoAuth;
19952019
1996- UncommittedChildren uncommitted_children ;
1997- if (auto status = visitUncommitted (current_path, uncommitted_children ); status != CollectStatus::Ok)
2020+ ProcessedUncommittedChildren processed_uncommitted_children ;
2021+ if (auto status = visitUncommitted (current_path, processed_uncommitted_children ); status != CollectStatus::Ok)
19982022 return status;
19992023
20002024 if constexpr (Storage::use_rocksdb)
20012025 {
2002- if (auto status = visitRocksDBNode (current_path, uncommitted_children ); status != CollectStatus::Ok)
2026+ if (auto status = visitRocksDBNode (current_path, processed_uncommitted_children ); status != CollectStatus::Ok)
20032027 return status;
20042028 }
20052029 else
20062030 {
2007- if (auto status = visitMemNode (current_path, uncommitted_children ); status != CollectStatus::Ok)
2031+ if (auto status = visitMemNode (current_path, processed_uncommitted_children ); status != CollectStatus::Ok)
20082032 return status;
20092033 }
20102034 }
@@ -2018,7 +2042,7 @@ class ToDeleteTreeCollector
20182042 }
20192043
20202044private:
2021- CollectStatus visitRocksDBNode (StringRef current_path, const UncommittedChildren & uncommitted_children ) requires Storage::use_rocksdb
2045+ CollectStatus visitRocksDBNode (StringRef current_path, const ProcessedUncommittedChildren & processed_uncommitted_children ) requires Storage::use_rocksdb
20222046 {
20232047 std::filesystem::path current_path_fs (current_path.toString ());
20242048
@@ -2032,7 +2056,7 @@ class ToDeleteTreeCollector
20322056 {
20332057 auto child_path = (current_path_fs / child_name).generic_string ();
20342058
2035- if (uncommitted_children .contains (child_path))
2059+ if (processed_uncommitted_children .contains (child_path))
20362060 continue ;
20372061
20382062 if (checkLimits (child_node))
@@ -2044,7 +2068,7 @@ class ToDeleteTreeCollector
20442068 return CollectStatus::Ok;
20452069 }
20462070
2047- CollectStatus visitMemNode (StringRef current_path, const UncommittedChildren & uncommitted_children ) requires (!Storage::use_rocksdb)
2071+ CollectStatus visitMemNode (StringRef current_path, const ProcessedUncommittedChildren & processed_uncommitted_children ) requires (!Storage::use_rocksdb)
20482072 {
20492073 std::lock_guard lock (storage.storage_mutex );
20502074 auto node_it = storage.container .find (current_path);
@@ -2058,7 +2082,7 @@ class ToDeleteTreeCollector
20582082 {
20592083 auto child_path = (current_path_fs / child_name.toView ()).generic_string ();
20602084
2061- if (uncommitted_children .contains (child_path))
2085+ if (processed_uncommitted_children .contains (child_path))
20622086 continue ;
20632087
20642088 auto child_it = storage.container .find (child_path);
@@ -2074,27 +2098,26 @@ class ToDeleteTreeCollector
20742098 return CollectStatus::Ok;
20752099 }
20762100
2077- CollectStatus visitUncommitted (const std::string & path, UncommittedChildren & uncommitted_children )
2101+ CollectStatus visitUncommitted (const std::string & path, ProcessedUncommittedChildren & processed_uncommitted_children )
20782102 {
2079- auto & nodes = storage. uncommitted_state . nodes ;
2080-
2081- for ( auto & [node_path, uncommitted_node] : nodes )
2103+ for ( auto nodes_it = uncommitted_children. upper_bound (path + " / " ) ;
2104+ nodes_it != uncommitted_children. end () && Coordination::parentNodePath (StringRef{nodes_it-> first }) == path;
2105+ ++nodes_it )
20822106 {
2083- if (Coordination::parentNodePath (node_path) != path)
2084- continue ;
2107+ const auto & [node_path, uncommitted_node] = *nodes_it;
20852108
2086- uncommitted_children .insert (node_path);
2109+ processed_uncommitted_children .insert (node_path);
20872110
2088- const auto node_ptr = uncommitted_node. node ;
2111+ const auto node_ptr = uncommitted_node-> node ;
20892112
20902113 if (node_ptr == nullptr ) // / node was deleted in previous step of multi transaction
20912114 continue ;
20922115
20932116 if (checkLimits (*node_ptr))
20942117 return CollectStatus::LimitExceeded;
20952118
2096- uncommitted_node. materializeACL (storage.acl_map );
2097- addDelta (node_path, node_ptr->stats , *uncommitted_node. acls , std::string{node_ptr->getData ()});
2119+ uncommitted_node-> materializeACL (storage.acl_map );
2120+ addDelta (std::string{ node_path} , node_ptr->stats , *uncommitted_node-> acls , std::string{node_ptr->getData ()});
20982121 }
20992122
21002123 return CollectStatus::Ok;
0 commit comments