Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitaly.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/doc
diff options
context:
space:
mode:
authorPatrick Steinhardt <psteinhardt@gitlab.com>2021-11-30 15:14:14 +0300
committerPatrick Steinhardt <psteinhardt@gitlab.com>2021-12-03 10:19:07 +0300
commit1a1728782fdf444ec55ba5d968fe6845adc1bd28 (patch)
tree77e9a814cc083ab9b9b220bd30f4c04734985068 /doc
parentdee973f98c485bc70c6d73cec1a49c498ac22db0 (diff)
doc: Document reference-transaction hook
The hooks documentation does not document the reference-transaction hook. Add this missing information.
Diffstat (limited to 'doc')
-rw-r--r--doc/hooks.md99
1 files changed, 82 insertions, 17 deletions
diff --git a/doc/hooks.md b/doc/hooks.md
index 493894e30..296683f6e 100644
--- a/doc/hooks.md
+++ b/doc/hooks.md
@@ -23,14 +23,14 @@ able to derive required information:
script, which locates the `gitaly-hooks` executable using `GITALY_BIN_DIR`.
- We inject `GITALY_HOOKS_PAYLOAD`, which contains JSON-formatted data. This
payload encodes various information:
- - Which hooks have been requested. Gitaly uses this to only configure a
- subset of hooks even if the executed Git command would run additional
- hooks.
- - Information about the repository the hook is executed in.
- - Information about how to connect to Gitaly.
- - Information about the ongoing transaction, if any.
- - Information about the user who triggered hook. This is required for access
- checks.
+ - Which hooks have been requested. Gitaly uses this to only configure a
+ subset of hooks even if the executed Git command would run additional
+ hooks.
+ - Information about the repository the hook is executed in.
+ - Information about how to connect to Gitaly.
+ - Information about the ongoing transaction, if any.
+ - Information about the user who triggered the hook. This is required for
+ access checks.
The `gitaly-hooks` executable is only a gateway to be able to use gRPC and
execute the hook logic inside of the Gitaly server process. It uses the injected
@@ -50,13 +50,54 @@ execution path is:
The logic implemented in Gitaly's hook RPC handlers depends on which hook is
being executed.
+### Reference-transaction hook
+
+The reference-transaction hook is executed whenever Git updates a reference from
+an old value to a new value, where it hooks into the low-level mechanism to
+update references in Git. An update of a hook goes through two phases, where the
+hook is executed once for each phase:
+
+1. Git "prepares" the reference transaction. When the hook is called in this
+ phase, the references that are about to be updated are locked for concurrent
+ modification.
+1. Git "commits" or "aborts" the reference transaction.
+
+Depending on how the command updates references, this hook can be executed per
+reference that is about to be updated, or for all references at once. The
+references that are about to be updated are received on standard input.
+
+In Gitaly, we use the reference-transaction mechanism to perform votes on all
+references which are updated by Git in a way that is transparent to Gitaly
+itself. That is, we do not know how often and with which arguments the hook is
+going to be executed when we execute any Git command, and the order can change
+when new Git versions are rolled out that do internal changes.
+
+The reference-transaction can therefore be used to put an absolute ordering on
+all reference updates across multiple Gitaly nodes. To ensure that multiple
+Gitaly nodes part of a single transaction (that is, all Gitalies execute the
+same logic at the same point in time) perform the same action, we vote on each
+of the hook executions. Gitaly nodes:
+
+1. Take the standard input containing all references we are about to update.
+1. Hash these references.
+1. Use the resulting hash as it's vote that it sends to Praefect.
+
+We expect the hash must be the same across all Gitaly nodes if (and only if) all
+nodes:
+
+- Are in the same state before.
+- Make the change deterministically.
+
+If a [quorum](design_ha.md) is reached, the update is committed to disk,
+otherwise the update is rejected.
+
### Receive-Pack Hooks
These hooks are executed by `git-receive-pack` whenever changes are pushed into
a repository and can be used to:
- Verify whether the changes should be allowed into the repository in the first
- place (`pre-receive` and `update` hooks)
+ place (`pre-receive` and `update` hooks).
- Show information to the user (`post-update` hook).
While the reference-transaction hook executes on all Gitaly nodes, the
@@ -64,16 +105,17 @@ receive-pack style hooks only run on a single Gitaly, which is the primary node.
It can thus happen that receive-pack style hooks reject the update on the
primary node, which is not something the secondary nodes would see. The result
is that secondaries would now hang until the timeout for the RPC call triggers
-given that the primary is never going to vote on this transaction. To fix the
-hang, transactions support graceful stops: if the primary node fails the RPC
-call in code that is only executed on the primary, then it will stop the
+given that the primary is never going to vote on this transaction.
+
+To fix the hang, transactions support graceful stops: if the primary node fails
+the RPC call in code that is only executed on the primary, then it will stop the
transaction and thus tell other Gitaly nodes to stop waiting for quorum.
There are two users of these hooks:
- `PostReceivePack` and `SSHReceivePack` directly invoke `git-receive-pack`,
which then executes the hooks for us.
-- Most RPCs in the OperationService that write objects into the repository
+- Most RPCs in the `OperationService` that write objects into the repository
manually invoke these hooks using the `updateref.UpdaterWithHooks` structure.
These hooks perform the following functions:
@@ -91,7 +133,7 @@ These hooks perform the following functions:
quarantine directory using the repository's alternative object directory
fields so that any subsequent RPC calls that check the change can access those
objects. When the access checks succeed, any existing custom pre-receive hooks
- installed by the admin are executed.
+ installed by the administrator are executed.
- `update`: The update hook runs after the pre-receive hook at the point where
objects from the object quarantine directory have already been migrated into
the main repository. This hook only executes custom hooks installed by the
@@ -109,9 +151,8 @@ happening.
Both custom hooks and the `/internal/allowed` API endpoint may return
specially-formatted error messages that have either a `GitLab:` or a
`GL-Hook-Error:` prefix. Messages with this prefix are returned as-is to Rails
-and signify an error message that ought to be printed to the user directly,
-either through the user interface or through standard error of
-`git-receive-pack`.
+and signify an error message that should be printed to the user directly, either
+through the user interface or through standard error of `git-receive-pack`.
#### Custom Hooks
@@ -145,6 +186,20 @@ sequenceDiagram
Custom Hooks->>-Hook Service: OK
Hook Service->>-gitaly-hooks: OK
gitaly-hooks->>-git-receive-pack: OK
+
+ git-receive-pack->>+gitaly-hooks: exec "reference-transaction prepare"
+ gitaly-hooks->>+Hook Service: call ReferenceTransactionHook(prepare)
+ Hook Service->>+Praefect: cast vote
+ Praefect->>-Hook Service: OK
+ Hook Service->>-gitaly-hooks: OK
+ gitaly-hooks->>-git-receive-pack: OK
+
+ git-receive-pack->>+gitaly-hooks: exec "reference-transaction commit"
+ gitaly-hooks->>+Hook Service: call ReferenceTransaction(commit)
+ Hook Service->>+Praefect: cast vote
+ Praefect->>-Hook Service: OK
+ Hook Service->>-gitaly-hooks: OK
+ gitaly-hooks->>-git-receive-pack: OK
end
git-receive-pack->>+gitaly-hooks: exec "post-receive"
@@ -174,6 +229,16 @@ sequenceDiagram
Custom Hooks->>-Hook Service: OK
Hook Service->>-Operation Service: OK
+ Operation Service->>+Hook Service: call ReferenceTransactionHook(prepare)
+ Hook Service->>+Praefect: cast vote
+ Praefect->>-Hook Service: OK
+ Hook Service->>-Operation Service: OK
+
+ Operation Service->>+Hook Service: call ReferenceTransactionHook(commit)
+ Hook Service->>+Praefect: cast vote
+ Praefect->>-Hook Service: OK
+ Hook Service->>-Operation Service: OK
+
Operation Service->>+Hook Service: call PostReceiveHook
Hook Service->>Rails: decrement counter
Hook Service->>+Custom Hooks: exec "post-receive"