v3.3.1 31f1eec

coordinator.go RawHistoryFolder

1package deployment
2
3import (
4	"context"
5	"sync"
6)
7
8// appCoordinator serializes workload mutations per app. User mutations
9// and boot acquire the app lock blocking; periodic reconciliation
10// probes it with TryAcquire and skips busy apps instead of waiting.
11// Entries are never deleted so a lock cannot be re-created under a
12// holder; the map stays bounded by known app names.
13type appCoordinator struct {
14	mu    sync.Mutex
15	locks map[string]chan struct{}
16}
17
18func newAppCoordinator() *appCoordinator {
19	return &appCoordinator{locks: map[string]chan struct{}{}}
20}
21
22// lockFor returns the app's lock channel, creating it free (token
23// present) on first use. The caller must hold mu.
24func (c *appCoordinator) lockFor(app string) chan struct{} {
25	ch, ok := c.locks[app]
26	if !ok {
27		ch = make(chan struct{}, 1)
28		ch <- struct{}{}
29		c.locks[app] = ch
30	}
31	return ch
32}
33
34// acquire blocks until the app lock is held or ctx ends. The returned
35// release must be called exactly once by the holder.
36func (c *appCoordinator) acquire(ctx context.Context, app string) (func(), error) {
37	c.mu.Lock()
38	ch := c.lockFor(app)
39	c.mu.Unlock()
40	select {
41	case <-ctx.Done():
42		return nil, ctx.Err()
43	case <-ch:
44		return func() { ch <- struct{}{} }, nil
45	}
46}
47
48// tryAcquire takes the app lock without blocking. ok is false when the
49// app is busy; the caller must skip the app in that case.
50func (c *appCoordinator) tryAcquire(app string) (release func(), ok bool) {
51	c.mu.Lock()
52	ch := c.lockFor(app)
53	c.mu.Unlock()
54	select {
55	case <-ch:
56		return func() { ch <- struct{}{} }, true
57	default:
58		return nil, false
59	}
60}

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close