| 133 | } |
| 134 | |
| 135 | func (ss *segmentStack) mergeInto(minSegmentLevel, maxSegmentHeight int, |
| 136 | dest SegmentMutator, base *segmentStack, includeDeletions, optimizeTail bool, |
| 137 | cancelCh chan struct{}) error { |
| 138 | cancelCheckEvery := ss.options.MergerCancelCheckEvery |
| 139 | if cancelCheckEvery <= 0 { |
| 140 | cancelCheckEvery = DefaultCollectionOptions.MergerCancelCheckEvery |
| 141 | } |
| 142 | |
| 143 | iter, err := ss.startIterator(nil, nil, IteratorOptions{ |
| 144 | IncludeDeletions: includeDeletions, |
| 145 | SkipLowerLevel: true, |
| 146 | MinSegmentLevel: minSegmentLevel, |
| 147 | MaxSegmentHeight: maxSegmentHeight, |
| 148 | base: base, |
| 149 | }) |
| 150 | if err != nil { |
| 151 | return err |
| 152 | } |
| 153 | |
| 154 | defer iter.Close() |
| 155 | |
| 156 | readOptions := ReadOptions{NoCopyValue: true} |
| 157 | |
| 158 | OUTER: |
| 159 | for i := 0; true; i++ { |
| 160 | if cancelCh != nil && i%cancelCheckEvery == 0 { |
| 161 | select { |
| 162 | case <-cancelCh: |
| 163 | return ErrAborted |
| 164 | default: |
| 165 | // NO-OP. |
| 166 | } |
| 167 | } |
| 168 | |
| 169 | entryEx, key, val, err := iter.CurrentEx() |
| 170 | if err == ErrIteratorDone { |
| 171 | break |
| 172 | } |
| 173 | if err != nil { |
| 174 | return err |
| 175 | } |
| 176 | |
| 177 | if optimizeTail && len(iter.cursors) == 1 { |
| 178 | // When only 1 cursor remains, copy the remains of the |
| 179 | // last segment more directly instead of Next()'ing |
| 180 | // through the iterator. |
| 181 | cursor := iter.cursors[0] |
| 182 | |
| 183 | var op uint64 |
| 184 | var k, v []byte |
| 185 | op, k, v = cursor.sc.Current() |
| 186 | for op != 0 { |
| 187 | err = dest.Mutate(op, k, v) |
| 188 | if err != nil { |
| 189 | return err |
| 190 | } |
| 191 | err = cursor.sc.Next() |
| 192 | if err != nil { |