-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathgroup_pressure.go
More file actions
178 lines (153 loc) · 7.1 KB
/
Copy pathgroup_pressure.go
File metadata and controls
178 lines (153 loc) · 7.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/*
Copyright 2026 The ARCORIS Authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package bufferpool
// PoolGroupPressureSnapshot describes pressure interpreted from aggregate group
// usage and group-level pressure signals.
//
// The fields intentionally mirror partition pressure snapshots because the
// current group policy is expressed in aggregate owned bytes. The distinct type
// keeps group reports from exposing partition vocabulary as the public concept.
type PoolGroupPressureSnapshot PartitionPressureSnapshot
// newGroupPressureSnapshot projects group aggregate sample usage against pressure policy.
func newGroupPressureSnapshot(policy PartitionPressurePolicy, sample PoolGroupSample) PoolGroupPressureSnapshot {
return PoolGroupPressureSnapshot(newPartitionPressureSnapshot(policy, sample.Aggregate))
}
// PoolGroupPressurePublication reports one group pressure publication.
//
// AppliedPartitions and SkippedPartitions make propagation explicit. The group
// snapshot is published only when every child partition accepts the signal.
// When a later child rejects the signal, earlier applied children remain listed
// so the caller can see the partial publication instead of inferring it from a
// generic error.
type PoolGroupPressurePublication struct {
// Generation identifies the fully applied group pressure publication. It is
// NoGeneration when group runtime was not published.
Generation Generation
// AttemptGeneration identifies the child signal attempted for this call.
AttemptGeneration Generation
// Signal is the group-level pressure signal.
Signal PressureSignal
// GroupRuntimePublished reports whether the group runtime snapshot was
// published after every child partition accepted the signal.
GroupRuntimePublished bool
// Partial reports whether at least one child accepted the signal while the
// group runtime snapshot was not published.
Partial bool
// FailureReason is empty on full success and diagnostic on skip/failure.
FailureReason string
// AppliedPartitions contains partitions that accepted the signal.
AppliedPartitions []PoolGroupPressurePublicationEntry
// SkippedPartitions contains partitions that could not accept the signal.
SkippedPartitions []PoolGroupPressurePublicationEntry
}
// FullyApplied reports whether every group-owned partition accepted the signal.
func (p PoolGroupPressurePublication) FullyApplied() bool {
return p.GroupRuntimePublished && len(p.SkippedPartitions) == 0
}
// PoolGroupPressurePublicationEntry describes one partition in pressure
// publication.
type PoolGroupPressurePublicationEntry struct {
// PartitionName is the group-local partition name.
PartitionName string
// Reason is empty for applied entries and diagnostic for skipped entries.
Reason string
}
// SetPressure publishes a group pressure signal and propagates it to partitions.
//
// SetPressure is a foreground control-plane operation. It serializes with group
// hard Close, validates the level, publishes an immutable group pressure snapshot
// only after child partition prevalidation, and asks each partition to publish
// the signal to its owned Pools. It does not scan Pool shards and does not
// execute physical trim. Call PublishPressure when the caller needs the applied
// and skipped partition list.
func (g *PoolGroup) SetPressure(level PressureLevel) error {
g.mustBeInitialized()
if err := (PressureSignal{Level: level}).validate(); err != nil {
return err
}
publication, err := g.PublishPressure(level)
if err != nil {
return err
}
if !publication.FullyApplied() {
return newError(ErrClosed, errGroupClosed)
}
return nil
}
// PublishPressure publishes a group pressure signal and returns exact
// propagation diagnostics.
func (g *PoolGroup) PublishPressure(level PressureLevel) (PoolGroupPressurePublication, error) {
g.mustBeInitialized()
if err := (PressureSignal{Level: level}).validate(); err != nil {
return PoolGroupPressurePublication{}, err
}
// Group pressure publication is serialized with group Close and runtime
// snapshot mutation. The group does not inspect Pool shards; it only
// propagates the signal to child partitions.
g.runtimeMu.Lock()
defer g.runtimeMu.Unlock()
if !g.lifecycle.AllowsWork() {
return PoolGroupPressurePublication{}, newError(ErrClosed, errGroupClosed)
}
attemptGeneration := g.generation.Load().Next()
signal := PressureSignal{Level: level, Source: PressureSourceGroup, Generation: attemptGeneration}
publication := PoolGroupPressurePublication{AttemptGeneration: attemptGeneration, Signal: signal}
// Closed partitions are reported before any child receives the signal, so a
// skipped-before-apply result cannot hide partial runtime state.
for _, entry := range g.registry.entries {
if entry.partition.IsClosed() {
publication.SkippedPartitions = append(publication.SkippedPartitions, PoolGroupPressurePublicationEntry{
PartitionName: entry.name,
Reason: policyUpdateFailureClosed,
})
}
}
if len(publication.SkippedPartitions) > 0 {
publication.FailureReason = policyUpdateFailureClosed
return publication, nil
}
// Child publication is foreground and explicit. If a later partition fails,
// the result lists earlier accepted partitions and the group runtime snapshot
// remains unpublished.
for _, entry := range g.registry.entries {
partitionPublication, err := entry.partition.publishPressureSignal(signal)
if err != nil {
reason := policyUpdateFailureReasonForError(err, policyUpdateFailureInvalid)
publication.Partial = len(publication.AppliedPartitions) > 0
publication.FailureReason = reason
publication.SkippedPartitions = append(publication.SkippedPartitions, PoolGroupPressurePublicationEntry{
PartitionName: entry.name,
Reason: reason,
})
return publication, err
}
if !partitionPublication.FullyApplied() {
publication.Partial = len(publication.AppliedPartitions) > 0
publication.FailureReason = policyUpdateFailureClosed
publication.SkippedPartitions = append(publication.SkippedPartitions, PoolGroupPressurePublicationEntry{
PartitionName: entry.name,
Reason: policyUpdateFailureClosed,
})
return publication, nil
}
publication.AppliedPartitions = append(publication.AppliedPartitions, PoolGroupPressurePublicationEntry{PartitionName: entry.name})
}
// The group snapshot is published only after every partition accepted the
// attempted generation.
g.generation.Store(attemptGeneration)
runtime := g.currentRuntimeSnapshot()
g.publishRuntimeSnapshot(newGroupRuntimeSnapshotWithPressure(attemptGeneration, runtime.Policy, signal))
publication.Generation = attemptGeneration
publication.GroupRuntimePublished = true
return publication, nil
}