resume_credentials.go RawHistoryFolder

1package daemon
2
3// resumeCredentials owns every resume credential that is not held by a live
4// attachment: attachments between detach and park publication (parking), and
5// parked attachments waiting for a reconnect (parked). A token is unique
6// across both, and every lookup, publication, and retirement of either goes
7// through this type, so the credential lifecycle has one owner.
8//
9// resumeCredentials is guarded by Daemon.mu; every method requires it held.
10// It never takes another lock and never stops timers or closes transports
11// beyond closing its own done channels: external retirement stays with the
12// caller, after d.mu is released.
13type resumeCredentials struct {
14	parked  map[uint64]*parkedAttachment
15	parking map[uint64]*parkingAttachment
16}
17
18func newResumeCredentials() resumeCredentials {
19	return resumeCredentials{
20		parked:  make(map[uint64]*parkedAttachment),
21		parking: make(map[uint64]*parkingAttachment),
22	}
23}
24
25// issue returns a fresh nonzero token no parked or parking entry holds.
26func (c *resumeCredentials) issue() uint64 {
27	for {
28		token := newResumeToken()
29		if token == 0 {
30			continue
31		}
32		if c.parked[token] == nil && c.parking[token] == nil {
33			return token
34		}
35	}
36}
37
38// parkedFor returns the parked entry holding token, or nil.
39func (c *resumeCredentials) parkedFor(token uint64) *parkedAttachment { return c.parked[token] }
40
41// parkingFor returns the in-flight parking entry holding token, or nil.
42func (c *resumeCredentials) parkingFor(token uint64) *parkingAttachment { return c.parking[token] }
43
44// sessionFor returns the session a parked or parking token belongs to.
45func (c *resumeCredentials) sessionFor(token uint64) *session {
46	if parked := c.parked[token]; parked != nil {
47		return parked.sess
48	}
49	if pending := c.parking[token]; pending != nil {
50		return pending.sess
51	}
52	return nil
53}
54
55// retainsSession reports whether any parked or parking credential keeps sess.
56func (c *resumeCredentials) retainsSession(sess *session) bool {
57	for _, parked := range c.parked {
58		if parked.sess == sess {
59			return true
60		}
61	}
62	for _, pending := range c.parking {
63		if pending.sess == sess {
64			return true
65		}
66	}
67	return false
68}
69
70// markParking records or refreshes the in-flight marker for ac's token.
71func (c *resumeCredentials) markParking(sess *session, ac *attachedClient) {
72	token := ac.resumeToken
73	if token == 0 {
74		return
75	}
76	if existing := c.parking[token]; existing != nil {
77		if existing.ac == ac {
78			existing.sess = sess
79			return
80		}
81		delete(c.parking, token)
82		existing.closeDone()
83	}
84	c.parking[token] = &parkingAttachment{sess: sess, ac: ac, done: make(chan struct{})}
85}
86
87// clearParking removes token's marker, waking its waiters. A non-nil ac only
88// clears its own marker.
89func (c *resumeCredentials) clearParking(token uint64, ac *attachedClient) {
90	pending := c.parking[token]
91	if pending == nil || (ac != nil && pending.ac != ac) {
92		return
93	}
94	delete(c.parking, token)
95	pending.closeDone()
96}
97
98// purgeParking removes every marker for sess, or every marker when sess is
99// nil, so same-token waiters fail closed instead of hanging.
100func (c *resumeCredentials) purgeParking(sess *session) {
101	for token, pending := range c.parking {
102		if sess == nil || pending.sess == sess {
103			delete(c.parking, token)
104			pending.closeDone()
105		}
106	}
107}
108
109// publishParked stores parked under token, replacing any previous entry, and
110// clears the matching in-flight marker.
111func (c *resumeCredentials) publishParked(token uint64, parked *parkedAttachment) {
112	c.parked[token] = parked
113	c.clearParking(token, parked.ac)
114}
115
116// takeParked removes token's parked entry when it still holds parked. It
117// reports false when another path already replaced or removed it.
118func (c *resumeCredentials) takeParked(token uint64, parked *parkedAttachment) bool {
119	if parked == nil || c.parked[token] != parked {
120		return false
121	}
122	delete(c.parked, token)
123	return true
124}
125
126// parkedForSession returns every parked entry for sess, or every parked entry
127// when sess is nil, keyed by token.
128func (c *resumeCredentials) parkedForSession(sess *session) map[uint64]*parkedAttachment {
129	matches := make(map[uint64]*parkedAttachment)
130	for token, parked := range c.parked {
131		if sess == nil || parked.sess == sess {
132			matches[token] = parked
133		}
134	}
135	return matches
136}

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 12

Tags 11

↑↓ moveenter openesc close