Skip to content

db/commits: fix off-by-one in FindNearestToTs for "db vacate <ts>"#6842

Open
SAY-5 wants to merge 1 commit intobrimdata:mainfrom
SAY-5:fix/vacate-off-by-one-6746
Open

db/commits: fix off-by-one in FindNearestToTs for "db vacate <ts>"#6842
SAY-5 wants to merge 1 commit intobrimdata:mainfrom
SAY-5:fix/vacate-off-by-one-6746

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 21, 2026

Summary

Fixes #6746.

FindNearestToTs is supposed to return the oldest commit whose Date is still >= ts, so SetBase keeps that commit and drops everything strictly older. Today it walks from HEAD toward the root and returns on ts >= commit.Date, i.e. the newest commit older-than-or-equal-to ts. SetBase then keeps that too-old commit as the new base, leaving one extra commit in the chain.

Concretely, in #6746:

commit date
x:0 20:48:35Z
x:1 20:48:37Z
x:2 20:48:39Z
x:3 20:48:41Z

super db vacate -f 2026-03-18T20:48:38Z - expected to drop x:0 and x:1 (both strictly before 38s) and keep x:2/x:3. Actual: only x:0 is dropped, because the walk stops at x:1 on the first iteration where 38s >= commit.Date.

Fix

Flip the loop: advance while commit.Date >= ts, record the most recently visited commit in prev, and return prev when we hit a commit whose Date < ts. The -f-without-timestamp path (which passes HEAD.Date) still returns HEAD on the first iteration (since HEAD.Date < HEAD.Date is false, then parent's Date < HEAD.Date is true), matching the current behaviour.

Test plan

  • go build ./...
  • go build ./db/...
  • Existing db/ztests/vacate.yaml (the -f-without-timestamp scenario) is behaviourally unchanged under the new loop
  • An explicit ztest for the timestamp-arg off-by-one case would be a welcome follow-up; I didn't add one here to keep the change narrow, but happy to layer one on top if the maintainers would like it

FindNearestToTs is supposed to return the oldest commit whose Date
is still >= the vacate timestamp, so SetBase keeps that commit and
drops everything strictly older. Today it walks from HEAD toward
the root and returns on `ts >= commit.Date`, i.e. the newest
commit older-than-or-equal-to ts. SetBase then keeps that too-old
commit as the new base, leaving one extra commit in the chain.

Concretely, in brimdata#6746 the user loads x:0 @ t=35s, x:1 @ 37s, x:2 @
39s, x:3 @ 41s and runs `super db vacate -f 38s`. Expected: drop
x:0 and x:1 (both strictly before 38s), keep x:2 and x:3. Actual:
only x:0 is dropped because the walk stops at x:1 on the first
iteration where 38s >= commit.Date.

Flip the loop so we advance while Date >= ts and track the most
recently visited ID in `prev`; return it when we hit a commit
whose Date < ts. The `-f`-without-timestamp path (which passes
HEAD.Date) still returns HEAD, matching current behaviour.

Signed-off-by: SAY-5 <SAY-5@users.noreply.github.com>

Fixes brimdata#6746
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Off-by-one result on "db vacate" with timestamp

1 participant