@@ -22,48 +22,16 @@ class TStatsPartGroupBtreeIndexIterator : public IStatsPartGroupIterator {
2222 TRowId BeginRowId;
2323 TRowId EndRowId;
2424 TCellsIterable BeginKey;
25- TCellsIterable EndKey;
26- std::optional<TBtreeIndexNode> Node;
27- std::optional<TRecIdx> Pos;
2825 ui64 DataSize;
2926
30- TNodeState (TPageId pageId, TRowId beginRowId, TRowId endRowId, TCellsIterable beginKey, TCellsIterable endKey, ui64 dataSize)
27+ TNodeState (TPageId pageId, TRowId beginRowId, TRowId endRowId, TCellsIterable beginKey, ui64 dataSize)
3128 : PageId(pageId)
3229 , BeginRowId(beginRowId)
3330 , EndRowId(endRowId)
3431 , BeginKey(beginKey)
35- , EndKey(endKey)
3632 , DataSize(dataSize)
3733 {
3834 }
39-
40- bool IsLastPos () const noexcept {
41- Y_ABORT_UNLESS (Node);
42- Y_ABORT_UNLESS (Pos);
43- return *Pos == Node->GetKeysCount ();
44- }
45-
46- bool IsFirstPos () const noexcept {
47- Y_ABORT_UNLESS (Node);
48- Y_ABORT_UNLESS (Pos);
49- return *Pos == 0 ;
50- }
51- };
52-
53- struct TSeekRowId {
54- TSeekRowId (TRowId rowId)
55- : RowId(rowId)
56- {}
57-
58- bool BelongsTo (const TNodeState& state) const noexcept {
59- return TBtreeIndexNode::Has (RowId, state.BeginRowId , state.EndRowId );
60- }
61-
62- TRecIdx Do (const TNodeState& state) const noexcept {
63- return state.Node ->Seek (RowId, state.Pos );
64- }
65-
66- const TRowId RowId;
6735 };
6836
6937public:
@@ -73,172 +41,103 @@ class TStatsPartGroupBtreeIndexIterator : public IStatsPartGroupIterator {
7341 , GroupId(groupId)
7442 , GroupInfo(part->Scheme->GetLayout (groupId))
7543 , Meta(groupId.IsHistoric() ? part->IndexPages.BTreeHistoric[groupId.Index] : part->IndexPages.BTreeGroups[groupId.Index])
76- , State(Reserve(Meta.LevelCount + 1 ))
7744 , GroupChannel(Part->GetGroupChannel (GroupId))
45+ , NodeIndex(0 )
7846 , PrevDataSize(0 )
7947 , PrevPrevDataSize(0 )
8048 {
81- const static TCellsIterable EmptyKey (static_cast <const char *>(nullptr ), TColumns ());
82- State.emplace_back (Meta.PageId , 0 , GetEndRowId (), EmptyKey, EmptyKey, Meta.DataSize );
8349 }
8450
8551 EReady Start () override {
86- return DoSeek<TSeekRowId>({0 });
87- }
88-
89- EReady Next () override {
90- Y_ABORT_UNLESS (!IsExhausted ());
52+ const static TCellsIterable EmptyKey (static_cast <const char *>(nullptr ), TColumns ());
9153
92- PrevPrevDataSize = PrevDataSize;
93- PrevDataSize = State.back ().DataSize ;
54+ bool ready = true ;
55+ TVector<TNodeState> nextNodes;
56+ Nodes.emplace_back (Meta.PageId , 0 , GetEndRowId (), EmptyKey, Meta.DataSize );
57+
58+ for (ui32 height = 0 ; height < Meta.LevelCount ; height++) {
59+ for (auto &nodeState : Nodes) {
60+ auto page = Env->TryGetPage (Part, nodeState.PageId );
61+ if (!page) {
62+ ready = false ;
63+ continue ;
64+ }
65+ TBtreeIndexNode node (*page);
66+
67+ for (TRecIdx pos : xrange<TRecIdx>(0 , node.GetChildrenCount ())) {
68+ auto & child = node.GetShortChild (pos);
69+
70+ TRowId beginRowId = pos ? node.GetShortChild (pos - 1 ).RowCount : nodeState.BeginRowId ;
71+ TRowId endRowId = child.RowCount ;
72+ TCellsIterable beginKey = pos ? node.GetKeyCellsIterable (pos - 1 , GroupInfo.ColsKeyIdx ) : nodeState.BeginKey ;
73+ ui64 dataSize = child.DataSize ;
74+
75+ nextNodes.emplace_back (child.PageId , beginRowId, endRowId, beginKey, dataSize);
76+ }
77+ }
9478
95- if (Meta. LevelCount == 0 ) {
96- return Exhaust ();
79+ Nodes. swap (nextNodes);
80+ nextNodes. clear ();
9781 }
9882
99- if (IsLeaf ()) {
100- do {
101- State.pop_back ();
102- } while (State.size () > 1 && State.back ().IsLastPos ());
103- if (State.back ().IsLastPos ()) {
104- return Exhaust ();
105- }
106- PushNextState (*State.back ().Pos + 1 );
83+ if (!ready) {
84+ Nodes.clear (); // some invalid subset
85+ return EReady::Page;
10786 }
10887
109- for (ui32 level : xrange<ui32>(State. size () - 1 , Meta. LevelCount )) {
110- if (! TryLoad (State[level])) {
111- // exiting with an intermediate state
112- Y_DEBUG_ABORT_UNLESS (! IsLeaf () && ! IsExhausted ());
113- return EReady::Page ;
114- }
115- PushNextState ( 0 ) ;
116- }
88+ return DataOrGone ();
89+ }
90+
91+ EReady Next () override {
92+ Y_ABORT_UNLESS ( IsValid ()) ;
93+
94+ PrevPrevDataSize = PrevDataSize ;
95+ PrevDataSize = GetCurrentNode (). DataSize ;
11796
118- // State.back() points to the target data page
119- Y_ABORT_UNLESS ( IsLeaf ());
120- return EReady::Data ;
97+ NodeIndex++;
98+
99+ return DataOrGone () ;
121100 }
122101
123102 void AddLastDeltaDataSize (TChanneledDataSize& dataSize) override {
124- Y_ABORT_UNLESS (IsExhausted () || IsLeaf ());
125103 Y_DEBUG_ABORT_UNLESS (PrevDataSize >= PrevPrevDataSize);
126104 ui64 delta = PrevDataSize - PrevPrevDataSize;
127105 dataSize.Add (delta, GroupChannel);
128106 }
129107
130108public:
131109 bool IsValid () const override {
132- Y_DEBUG_ABORT_UNLESS (IsLeaf () || IsExhausted ());
133- return IsLeaf ();
110+ return NodeIndex < Nodes.size ();
134111 }
135112
136113 TRowId GetEndRowId () const override {
137114 return Meta.RowCount ;
138115 }
139116
140117 TPageId GetPageId () const override {
141- Y_ABORT_UNLESS (IsLeaf ());
142- return State.back ().PageId ;
118+ return GetCurrentNode ().PageId ;
143119 }
144120
145121 TRowId GetRowId () const override {
146- Y_ABORT_UNLESS (IsLeaf ());
147- return State.back ().BeginRowId ;
122+ return GetCurrentNode ().BeginRowId ;
148123 }
149124
150125 TPos GetKeyCellsCount () const override {
151- Y_ABORT_UNLESS (IsLeaf ());
152- return State.back ().BeginKey .Count ();
126+ return GetCurrentNode ().BeginKey .Count ();
153127 }
154128
155129 TCell GetKeyCell (TPos index) const override {
156- Y_ABORT_UNLESS (IsLeaf ());
157- return State.back ().BeginKey .Iter ().At (index);
130+ return GetCurrentNode ().BeginKey .Iter ().At (index);
158131 }
159132
160133private:
161- template <typename TSeek>
162- EReady DoSeek (TSeek seek) {
163- while (State.size () > 1 && !seek.BelongsTo (State.back ())) {
164- State.pop_back ();
165- }
166-
167- if (IsExhausted ()) {
168- // don't use exhausted state as an initial one
169- State[0 ].Pos = { };
170- }
171-
172- for (ui32 level : xrange<ui32>(State.size () - 1 , Meta.LevelCount )) {
173- auto &state = State[level];
174- Y_DEBUG_ABORT_UNLESS (seek.BelongsTo (state));
175- if (!TryLoad (state)) {
176- // exiting with an intermediate state
177- Y_DEBUG_ABORT_UNLESS (!IsLeaf () && !IsExhausted ());
178- return EReady::Page;
179- }
180- auto pos = seek.Do (state);
181-
182- PushNextState (pos);
183- }
184-
185- // State.back() points to the target data page
186- Y_ABORT_UNLESS (IsLeaf ());
187- Y_DEBUG_ABORT_UNLESS (seek.BelongsTo (State.back ()));
188- return EReady::Data;
189- }
190-
191- bool IsRoot () const noexcept {
192- return State.size () == 1 ;
193- }
194-
195- bool IsExhausted () const noexcept {
196- return State[0 ].Pos == Max<TRecIdx>();
134+ EReady DataOrGone () const {
135+ return IsValid () ? EReady::Data : EReady::Gone;
197136 }
198137
199- bool IsLeaf () const noexcept {
200- // Note: it is possible to have 0 levels in B-Tree
201- // so we may have exhausted state with leaf (data) node
202- return State.size () == Meta.LevelCount + 1 && !IsExhausted ();
203- }
204-
205- EReady Exhaust () {
206- while (State.size () > 1 ) {
207- State.pop_back ();
208- }
209- State[0 ].Pos = Max<TRecIdx>();
210- return EReady::Gone;
211- }
212-
213- void PushNextState (TRecIdx pos) {
214- TNodeState& current = State.back ();
215- Y_ABORT_UNLESS (pos < current.Node ->GetChildrenCount (), " Should point to some child" );
216- current.Pos .emplace (pos);
217-
218- auto & child = current.Node ->GetShortChild (pos);
219-
220- TRowId beginRowId = pos ? current.Node ->GetShortChild (pos - 1 ).RowCount : current.BeginRowId ;
221- TRowId endRowId = child.RowCount ;
222-
223- TCellsIterable beginKey = pos ? current.Node ->GetKeyCellsIterable (pos - 1 , GroupInfo.ColsKeyIdx ) : current.BeginKey ;
224- TCellsIterable endKey = pos < current.Node ->GetKeysCount () ? current.Node ->GetKeyCellsIterable (pos, GroupInfo.ColsKeyIdx ) : current.EndKey ;
225-
226- ui64 dataSize = child.DataSize ;
227-
228- State.emplace_back (child.PageId , beginRowId, endRowId, beginKey, endKey, dataSize);
229- }
230-
231- bool TryLoad (TNodeState& state) {
232- if (state.Node ) {
233- return true ;
234- }
235-
236- auto page = Env->TryGetPage (Part, state.PageId );
237- if (page) {
238- state.Node .emplace (*page);
239- return true ;
240- }
241- return false ;
138+ const TNodeState& GetCurrentNode () const {
139+ Y_ABORT_UNLESS (IsValid ());
140+ return Nodes[NodeIndex];
242141 }
243142
244143private:
@@ -247,8 +146,9 @@ class TStatsPartGroupBtreeIndexIterator : public IStatsPartGroupIterator {
247146 const TGroupId GroupId;
248147 const TPartScheme::TGroupInfo& GroupInfo;
249148 const TBtreeIndexMeta Meta;
250- TVector<TNodeState> State;
251149 ui8 GroupChannel;
150+ ui32 NodeIndex;
151+ TVector<TNodeState> Nodes;
252152 ui64 PrevDataSize, PrevPrevDataSize;
253153};
254154
0 commit comments