]> git.ipfire.org Git - thirdparty/git.git/commitdiff
reftable/stack: handle outdated stacks when compacting
authorPatrick Steinhardt <ps@pks.im>
Tue, 12 Aug 2025 09:54:20 +0000 (11:54 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 12 Aug 2025 14:41:00 +0000 (07:41 -0700)
When we compact the reftable stack we first acquire the lock for the
"tables.list" file and then reload the stack to check that it is still
up-to-date. This is done by calling `stack_uptodate()`, which knows to
return zero in case the stack is up-to-date, a positive value if it is
not and a negative error code on unexpected conditions.

We don't do proper error checking though, but instead we only check
whether the returned error code is non-zero. If so, we simply bubble it
up the calling stack, which means that callers may see an unexpected
positive value.

Fix this issue by translating to `REFTABLE_OUTDATED_ERROR` instead.
Handle this situation in `reftable_addition_commit()`, where we perform
a best-effort auto-compaction.

All other callsites of `stack_uptodate()` know to handle a positive
return value and thus don't need to be fixed.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
reftable/stack.c

index 1ce4d90cb8214d4f89a9a7463713cb59dfdf5be4..af0f94d882644323622d4924572799362b9d0694 100644 (file)
@@ -579,9 +579,11 @@ out:
        return err;
 }
 
-/* -1 = error
- 0 = up to date
- 1 = changed. */
+/*
+ * Check whether the given stack is up-to-date with what we have in memory.
+ * Returns 0 if so, 1 if the stack is out-of-date or a negative error code
+ * otherwise.
+ */
 static int stack_uptodate(struct reftable_stack *st)
 {
        char **names = NULL;
@@ -850,10 +852,13 @@ int reftable_addition_commit(struct reftable_addition *add)
                 * control. It is possible that a concurrent writer is already
                 * trying to compact parts of the stack, which would lead to a
                 * `REFTABLE_LOCK_ERROR` because parts of the stack are locked
-                * already. This is a benign error though, so we ignore it.
+                * already. Similarly, the stack may have been rewritten by a
+                * concurrent writer, which causes `REFTABLE_OUTDATED_ERROR`.
+                * Both of these errors are benign, so we simply ignore them.
                 */
                err = reftable_stack_auto_compact(add->stack);
-               if (err < 0 && err != REFTABLE_LOCK_ERROR)
+               if (err < 0 && err != REFTABLE_LOCK_ERROR &&
+                   err != REFTABLE_OUTDATED_ERROR)
                        goto done;
                err = 0;
        }
@@ -1215,9 +1220,24 @@ static int stack_compact_range(struct reftable_stack *st,
                goto done;
        }
 
+       /*
+        * Check whether the stack is up-to-date. We unfortunately cannot
+        * handle the situation gracefully in case it's _not_ up-to-date
+        * because the range of tables that the user has requested us to
+        * compact may have been changed. So instead we abort.
+        *
+        * We could in theory improve the situation by having the caller not
+        * pass in a range, but instead the list of tables to compact. If so,
+        * we could check that relevant tables still exist. But for now it's
+        * good enough to just abort.
+        */
        err = stack_uptodate(st);
-       if (err)
+       if (err < 0)
                goto done;
+       if (err > 0) {
+               err = REFTABLE_OUTDATED_ERROR;
+               goto done;
+       }
 
        /*
         * Lock all tables in the user-provided range. This is the slice of our