@@ -72,21 +72,16 @@ func (d *DB) exciseTable(
7272 return nil , nil
7373 }
7474
75- var iters iterSet
76- var itersLoaded bool
77- defer iters .CloseAll ()
78- loadItersIfNecessary := func () error {
79- if itersLoaded {
80- return nil
81- }
82- var err error
83- iters , err = d .newIters (ctx , m , & IterOptions {
84- Category : categoryIngest ,
85- layer : manifest .Level (level ),
86- }, internalIterOpts {}, iterPointKeys | iterRangeDeletions | iterRangeKeys )
87- itersLoaded = true
88- return err
75+ // The file partially overlaps the excise span; we will need to open it to
76+ // determine tight bounds for the left-over table(s).
77+ iters , err := d .newIters (ctx , m , & IterOptions {
78+ Category : categoryIngest ,
79+ layer : manifest .Level (level ),
80+ }, internalIterOpts {}, iterPointKeys | iterRangeDeletions | iterRangeKeys )
81+ if err != nil {
82+ return nil , err
8983 }
84+ defer iters .CloseAll ()
9085
9186 needsBacking := false
9287 // Create a file to the left of the excise span, if necessary.
@@ -123,9 +118,6 @@ func (d *DB) exciseTable(
123118 LargestSeqNumAbsolute : m .LargestSeqNumAbsolute ,
124119 SyntheticPrefixAndSuffix : m .SyntheticPrefixAndSuffix ,
125120 }
126- if err := loadItersIfNecessary (); err != nil {
127- return nil , err
128- }
129121 if err := determineLeftTableBounds (d .cmp , m , leftFile , exciseSpan .Start , iters ); err != nil {
130122 return nil , err
131123 }
@@ -179,70 +171,8 @@ func (d *DB) exciseTable(
179171 LargestSeqNumAbsolute : m .LargestSeqNumAbsolute ,
180172 SyntheticPrefixAndSuffix : m .SyntheticPrefixAndSuffix ,
181173 }
182- if m .HasPointKeys && ! exciseSpan .ContainsInternalKey (d .cmp , m .LargestPointKey ) {
183- // This file will probably contain point keys
184- if err := loadItersIfNecessary (); err != nil {
185- return nil , err
186- }
187- largestPointKey := m .LargestPointKey
188- if kv := iters .Point ().SeekGE (exciseSpan .End .Key , base .SeekGEFlagsNone ); kv != nil {
189- if exciseSpan .End .Kind == base .Inclusive && d .equal (exciseSpan .End .Key , kv .K .UserKey ) {
190- return nil , base .AssertionFailedf ("cannot excise with an inclusive end key and data overlap at end key" )
191- }
192- rightFile .ExtendPointKeyBounds (d .cmp , kv .K .Clone (), largestPointKey )
193- }
194- // Store the max of (exciseSpan.End, rdel.Start) in firstRangeDel. This
195- // needs to be a copy if the key is owned by the range del iter.
196- var firstRangeDel []byte
197- rdel , err := iters .RangeDeletion ().SeekGE (exciseSpan .End .Key )
198- if err != nil {
199- return nil , err
200- } else if rdel != nil {
201- firstRangeDel = append (firstRangeDel [:0 ], rdel .Start ... )
202- if d .cmp (firstRangeDel , exciseSpan .End .Key ) < 0 {
203- // NB: This can only be done if the end bound is exclusive.
204- if exciseSpan .End .Kind != base .Exclusive {
205- return nil , base .AssertionFailedf ("cannot truncate rangedel during excise with an inclusive upper bound" )
206- }
207- firstRangeDel = exciseSpan .End .Key
208- }
209- }
210- if firstRangeDel != nil {
211- smallestPointKey := rdel .SmallestKey ()
212- smallestPointKey .UserKey = firstRangeDel
213- rightFile .ExtendPointKeyBounds (d .cmp , smallestPointKey , largestPointKey )
214- }
215- }
216- if m .HasRangeKeys && ! exciseSpan .ContainsInternalKey (d .cmp , m .LargestRangeKey ) {
217- // This file will probably contain range keys.
218- if err := loadItersIfNecessary (); err != nil {
219- return nil , err
220- }
221- largestRangeKey := m .LargestRangeKey
222- // Store the max of (exciseSpan.End, rkey.Start) in firstRangeKey. This
223- // needs to be a copy if the key is owned by the range key iter.
224- var firstRangeKey []byte
225- rkey , err := iters .RangeKey ().SeekGE (exciseSpan .End .Key )
226- if err != nil {
227- return nil , err
228- } else if rkey != nil {
229- firstRangeKey = append (firstRangeKey [:0 ], rkey .Start ... )
230- if d .cmp (firstRangeKey , exciseSpan .End .Key ) < 0 {
231- if exciseSpan .End .Kind != base .Exclusive {
232- return nil , base .AssertionFailedf ("cannot truncate range key during excise with an inclusive upper bound" )
233- }
234- firstRangeKey = exciseSpan .End .Key
235- }
236- }
237- if firstRangeKey != nil {
238- smallestRangeKey := rkey .SmallestKey ()
239- smallestRangeKey .UserKey = firstRangeKey
240- // We call ExtendRangeKeyBounds so any internal boundType fields are
241- // set correctly. Note that this is mildly wasteful as we'll be comparing
242- // rightFile.{Smallest,Largest}RangeKey with themselves, which can be
243- // avoided if we exported ExtendOverallKeyBounds or so.
244- rightFile .ExtendRangeKeyBounds (d .cmp , smallestRangeKey , largestRangeKey )
245- }
174+ if err := determineRightTableBounds (d .cmp , m , rightFile , exciseSpan .End , iters ); err != nil {
175+ return nil , err
246176 }
247177 if rightFile .HasRangeKeys || rightFile .HasPointKeys {
248178 var err error
@@ -331,9 +261,8 @@ func determineLeftTableBounds(
331261) error {
332262 if originalTable .HasPointKeys && cmp (originalTable .SmallestPointKey .UserKey , exciseSpanStart ) < 0 {
333263 // This file will probably contain point keys.
334- smallestPointKey := originalTable .SmallestPointKey
335264 if kv := iters .Point ().SeekLT (exciseSpanStart , base .SeekLTFlagsNone ); kv != nil {
336- leftTable .ExtendPointKeyBounds (cmp , smallestPointKey , kv .K .Clone ())
265+ leftTable .ExtendPointKeyBounds (cmp , originalTable . SmallestPointKey , kv .K .Clone ())
337266 }
338267 rdel , err := iters .RangeDeletion ().SeekLT (exciseSpanStart )
339268 if err != nil {
@@ -346,12 +275,12 @@ func determineLeftTableBounds(
346275 // The key is owned by the range del iter, so we need to copy it.
347276 lastRangeDel = slices .Clone (rdel .End )
348277 }
349- leftTable .ExtendPointKeyBounds (cmp , smallestPointKey , base .MakeExclusiveSentinelKey (InternalKeyKindRangeDelete , lastRangeDel ))
278+ leftTable .ExtendPointKeyBounds (cmp , originalTable .SmallestPointKey ,
279+ base .MakeExclusiveSentinelKey (InternalKeyKindRangeDelete , lastRangeDel ))
350280 }
351281 }
352282
353283 if originalTable .HasRangeKeys && cmp (originalTable .SmallestRangeKey .UserKey , exciseSpanStart ) < 0 {
354- smallestRangeKey := originalTable .SmallestRangeKey
355284 rkey , err := iters .RangeKey ().SeekLT (exciseSpanStart )
356285 if err != nil {
357286 return err
@@ -364,7 +293,72 @@ func determineLeftTableBounds(
364293 lastRangeKey = slices .Clone (rkey .End )
365294 }
366295 lastRangeKeyKind := rkey .Keys [0 ].Kind ()
367- leftTable .ExtendRangeKeyBounds (cmp , smallestRangeKey , base .MakeExclusiveSentinelKey (lastRangeKeyKind , lastRangeKey ))
296+ leftTable .ExtendRangeKeyBounds (cmp , originalTable .SmallestRangeKey ,
297+ base .MakeExclusiveSentinelKey (lastRangeKeyKind , lastRangeKey ))
298+ }
299+ }
300+ return nil
301+ }
302+
303+ // determineRightTableBounds calculates the bounds for the table that remains to
304+ // the right of the excise span after excising originalFile.
305+ //
306+ // Sets the smallest and largest keys, as well as HasPointKeys/HasRangeKeys in
307+ // the right.
308+ //
309+ // Note that the case where exciseSpanEnd is Inclusive is very restrictive; we
310+ // are only allowed to excise if the original table has no keys or ranges
311+ // overlapping exciseSpanEnd.Key.
312+ func determineRightTableBounds (
313+ cmp Compare ,
314+ originalTable , rightTable * tableMetadata ,
315+ exciseSpanEnd base.UserKeyBoundary ,
316+ iters iterSet ,
317+ ) error {
318+ if originalTable .HasPointKeys && ! exciseSpanEnd .IsUpperBoundForInternalKey (cmp , originalTable .LargestPointKey ) {
319+ if kv := iters .Point ().SeekGE (exciseSpanEnd .Key , base .SeekGEFlagsNone ); kv != nil {
320+ if exciseSpanEnd .Kind == base .Inclusive && cmp (exciseSpanEnd .Key , kv .K .UserKey ) == 0 {
321+ return base .AssertionFailedf ("cannot excise with an inclusive end key and data overlap at end key" )
322+ }
323+ rightTable .ExtendPointKeyBounds (cmp , kv .K .Clone (), originalTable .LargestPointKey )
324+ }
325+ rdel , err := iters .RangeDeletion ().SeekGE (exciseSpanEnd .Key )
326+ if err != nil {
327+ return err
328+ }
329+ if rdel != nil {
330+ // Use the larger of exciseSpanEnd.Key and rdel.Start.
331+ firstRangeDel := exciseSpanEnd .Key
332+ if cmp (rdel .Start , exciseSpanEnd .Key ) > 0 {
333+ // The key is owned by the range del iter, so we need to copy it.
334+ firstRangeDel = slices .Clone (rdel .Start )
335+ } else if exciseSpanEnd .Kind != base .Exclusive {
336+ return base .AssertionFailedf ("cannot truncate rangedel during excise with an inclusive upper bound" )
337+ }
338+ rightTable .ExtendPointKeyBounds (cmp , base.InternalKey {
339+ UserKey : firstRangeDel ,
340+ Trailer : rdel .SmallestKey ().Trailer ,
341+ }, originalTable .LargestPointKey )
342+ }
343+ }
344+ if originalTable .HasRangeKeys && ! exciseSpanEnd .IsUpperBoundForInternalKey (cmp , originalTable .LargestRangeKey ) {
345+ rkey , err := iters .RangeKey ().SeekGE (exciseSpanEnd .Key )
346+ if err != nil {
347+ return err
348+ }
349+ if rkey != nil {
350+ // Use the larger of exciseSpanEnd.Key and rkey.Start.
351+ firstRangeKey := exciseSpanEnd .Key
352+ if cmp (rkey .Start , exciseSpanEnd .Key ) > 0 {
353+ // The key is owned by the range key iter, so we need to copy it.
354+ firstRangeKey = slices .Clone (rkey .Start )
355+ } else if exciseSpanEnd .Kind != base .Exclusive {
356+ return base .AssertionFailedf ("cannot truncate range key during excise with an inclusive upper bound" )
357+ }
358+ rightTable .ExtendRangeKeyBounds (cmp , base.InternalKey {
359+ UserKey : firstRangeKey ,
360+ Trailer : rkey .SmallestKey ().Trailer ,
361+ }, originalTable .LargestRangeKey )
368362 }
369363 }
370364 return nil
0 commit comments