Skip to content

gitai 0.4.1

Choose a tag to compare

@feder-cr feder-cr released this 05 Nov 08:51
· 30 commits to main since this release

A correctness and robustness release, recommended for everyone, above all for deployments in shadow or authoritative storage mode and for those where agents can push. It also brings the policy reload that landed after 0.4.0. See "Upgrade" for what changes for clients.

Reference name limit

Reference names and symbolic reference targets over 1024 bytes are refused.
RPCs answer InvalidArgument. A push refuses only that reference, unless the
push is atomic. Existing references over the limit can still be read and deleted.

  • An object pool's names under refs/remotes/origin/ may be 15 bytes longer,
    which is what its refspec adds to a source name. The allowance goes by the
    repository's path, so a repository at a pool-shaped path has it too.
  • A repository holding such a reference fails with a permanent error, until the
    reference is deleted, when forking, creating or updating a replica, creating or
    fetching into an object pool, restoring a backup, FetchBundle,
    CreateRepositoryFromBundle and RewriteHistory.
  • Importing such a repository into the storage core answers FailedPrecondition
    before anything is registered or uploaded, and names the first few references.
    A repository with an incomplete registration from an earlier failed import is
    refused the same way: run the commands below on the node, with writers stopped,
    and import again to resume.
  • One such reference on a remote fails the whole of a mirror's FetchRemote.
  • UserLand on a branch name over the limit reports this limit.

To find such references (the second command covers an unborn HEAD) and delete one:

git -C <repository> for-each-ref --format='%(refname) %(symref)' | LC_ALL=C awk 'length($1) > 1024 || length($2) > 1024'
git -C <repository> symbolic-ref -q HEAD | LC_ALL=C awk 'length($0) > 1024'
git -C <repository> update-ref --no-deref -d <reference>

Keep --no-deref: without it, deleting a symbolic reference deletes its target.
In an object pool the first command also lists the allowed names of 1025 to 1039
bytes under refs/remotes/origin/. The DeleteRefs RPC and a push that deletes
the reference work too, where the repository's writes are allowed. A symbolic
reference other than HEAD that points at nothing is not checked when a
repository is created from a copy.

Check your repositories before upgrading a storage-core deployment: a node
rebuilt from a database that already holds such a name still writes it through
git. Delete those references first.

Fixes

  • A refused create could overwrite a branch in the database (shadow and
    authoritative). When two pushes raced to create one branch, the loser was told
    it was rejected while the database kept its commit. A push that creates an
    existing branch is now refused. Until a fuller fix, the whole push is refused,
    so other references of a non-atomic push don't land in that case. Other rejected
    updates of a non-atomic push are not addressed in this release.
  • Writes stalled after a failed git transaction (authoritative). A repository's
    write turn stayed held for up to 10 s when git failed a prepare, because git
    reports neither commit nor abort then. Every writer behind it waited. The turn now
    ends with the git process, on update-ref, in-process updates and atomic pushes over
    SSH and smart HTTP. New metric
    graft_storage_ref_admission_released_unreported_total. Smart HTTP's
    PostReceivePack now returns when receive-pack exits, even if the client's
    stream is still open.
  • Cancelled commands left git's reference lock behind. A cancelled context sent
    SIGKILL, so git could not clean up, and the next writer failed with "reference is
    already locked" until housekeeping removed the lock after an hour. Commands now get
    SIGTERM, and SIGKILL to the process group after 10 s if it outlives that. A process
    that traps SIGTERM and exits 0 now returns success after cancellation, so callers
    must check their context. A lock left by an out-of-memory kill or a crash can still
    block writers for up to an hour.
  • Concurrent proposal sweeps failed each other. One sweep now runs at a time per
    branch, bounded at 5 s after a land. New metric
    graft_land_proposal_sweep_timeouts_total. The file tickets of a land are released
    before its sweep.
  • Writers could fail when housekeeping removed a loose object directory. Gitaly's
    own writers now re-create it. Pushes of fewer than 100 objects can still fail, rarely,
    inside git; a retry succeeds, and nothing is corrupted (LIMITATIONS).

New

  • The policy reloads without a restart. SIGUSR1 reloads the standalone policy
    from the configuration file. The swap is atomic; an invalid file keeps the old
    policy. See CONFIGURATION.
  • graft policy check FILE validates a policy and, with -repo, replays recent
    changesets against it. Exit 0 when it denies nothing, 1 when it would deny updates,
    2 when invalid.

Docs and CI

  • README and BENCH now agree and state what was measured. Benchmarks were not
    repeated for this release, so the effect of these fixes on throughput is not measured.
  • STORAGE.md records two measurements that ended in "don't build": sharing directory
    fsyncs, and moving reftable compaction out of the write path.
  • LIMITATIONS was checked against the code, claim by claim.
  • More tests no longer depend on the speed of the machine.

Upgrade

Check for over-limit references first (above). No configuration or data migration.