@@ -21,9 +21,22 @@ import (
21
21
"time"
22
22
)
23
23
24
- // QueueSetFactory is used to create QueueSet objects.
24
+ // QueueSetFactory is used to create QueueSet objects. Creation, like
25
+ // config update, is done in two phases: the first phase consumes the
26
+ // QueuingConfig and the second consumes the DispatchingConfig. They
27
+ // are separated so that errors from the first phase can be found
28
+ // before committing to a concurrency allotment for the second.
25
29
type QueueSetFactory interface {
26
- NewQueueSet (config QueueSetConfig ) (QueueSet , error )
30
+ // BeginConstruction does the first phase of creating a QueueSet
31
+ BeginConstruction (QueuingConfig ) (QueueSetCompleter , error )
32
+ }
33
+
34
+ // QueueSetCompleter finishes the two-step process of creating or
35
+ // reconfiguring a QueueSet
36
+ type QueueSetCompleter interface {
37
+ // Complete returns a QueueSet configured by the given
38
+ // dispatching configuration.
39
+ Complete (DispatchingConfig ) QueueSet
27
40
}
28
41
29
42
// QueueSet is the abstraction for the queuing and dispatching
@@ -34,19 +47,27 @@ type QueueSetFactory interface {
34
47
// . Some day we may have connections between priority levels, but
35
48
// today is not that day.
36
49
type QueueSet interface {
37
- // SetConfiguration updates the configuration
38
- SetConfiguration (QueueSetConfig ) error
39
-
40
- // Quiesce controls whether the QueueSet is operating normally or is quiescing.
41
- // A quiescing QueueSet drains as normal but does not admit any
42
- // new requests. Passing a non-nil handler means the system should
43
- // be quiescing, a nil handler means the system should operate
44
- // normally. A call to Wait while the system is quiescing
45
- // will be rebuffed by returning tryAnother=true. If all the
46
- // queues have no requests waiting nor executing while the system
47
- // is quiescing then the handler will eventually be called with no
48
- // locks held (even if the system becomes non-quiescing between the
49
- // triggering state and the required call).
50
+ // BeginConfigChange starts the two-step process of updating
51
+ // the configuration. No change is made until Complete is
52
+ // called. If `C := X.BeginConstruction(q)` then
53
+ // `C.Complete(d)` returns the same value `X`. If the
54
+ // QueuingConfig's DesiredNumQueues field is zero then the other
55
+ // queuing-specific config parameters are not changed, so that the
56
+ // queues continue draining as before.
57
+ BeginConfigChange (QueuingConfig ) (QueueSetCompleter , error )
58
+
59
+ // Quiesce controls whether the QueueSet is operating normally or
60
+ // is quiescing. A quiescing QueueSet drains as normal but does
61
+ // not admit any new requests. Passing a non-nil handler means the
62
+ // system should be quiescing, a nil handler means the system
63
+ // should operate normally. A call to Wait while the system is
64
+ // quiescing will be rebuffed by returning tryAnother=true. If all
65
+ // the queues have no requests waiting nor executing while the
66
+ // system is quiescing then the handler will eventually be called
67
+ // with no locks held (even if the system becomes non-quiescing
68
+ // between the triggering state and the required call). In Go
69
+ // Memory Model terms, the triggering state happens before the
70
+ // call to the EmptyHandler.
50
71
Quiesce (EmptyHandler )
51
72
52
73
// Wait uses the given hashValue as the source of entropy as it
@@ -56,34 +77,47 @@ type QueueSet interface {
56
77
// tryAnother==true at return then the QueueSet has become
57
78
// undesirable and the client should try to find a different
58
79
// QueueSet to use; execute and afterExecution are irrelevant in
59
- // this case. Otherwise, if execute then the client should start
60
- // executing the request and, once the request finishes execution
61
- // or is canceled, call afterExecution(). Otherwise the client
62
- // should not execute the request and afterExecution is
63
- // irrelevant.
80
+ // this case. In the terms of the Go Memory Model, there was a
81
+ // call to Quiesce with a non-nil handler that happened before
82
+ // this return from Wait. Otherwise, if execute then the client
83
+ // should start executing the request and, once the request
84
+ // finishes execution or is canceled, call afterExecution().
85
+ // Otherwise the client should not execute the request and
86
+ // afterExecution is irrelevant. Canceling the context while the
87
+ // request is waiting in its queue will cut short that wait and
88
+ // cause a return with tryAnother and execute both false; later
89
+ // cancellations are the caller's problem.
64
90
Wait (ctx context.Context , hashValue uint64 , descr1 , descr2 interface {}) (tryAnother , execute bool , afterExecution func ())
65
91
}
66
92
67
- // QueueSetConfig defines the configuration of a QueueSet.
68
- type QueueSetConfig struct {
93
+ // QueuingConfig defines the configuration of the queuing aspect of a QueueSet.
94
+ type QueuingConfig struct {
69
95
// Name is used to identify a queue set, allowing for descriptive information about its intended use
70
96
Name string
71
- // ConcurrencyLimit is the maximum number of requests of this QueueSet that may be executing at a time
72
- ConcurrencyLimit int
97
+
73
98
// DesiredNumQueues is the number of queues that the API says
74
99
// should exist now. This may be zero, in which case
75
100
// QueueLengthLimit, HandSize, and RequestWaitLimit are ignored.
76
101
DesiredNumQueues int
102
+
77
103
// QueueLengthLimit is the maximum number of requests that may be waiting in a given queue at a time
78
104
QueueLengthLimit int
105
+
79
106
// HandSize is a parameter of shuffle sharding. Upon arrival of a request, a queue is chosen by randomly
80
107
// dealing a "hand" of this many queues and then picking one of minimum length.
81
108
HandSize int
109
+
82
110
// RequestWaitLimit is the maximum amount of time that a request may wait in a queue.
83
111
// If, by the end of that time, the request has not been dispatched then it is rejected.
84
112
RequestWaitLimit time.Duration
85
113
}
86
114
115
+ // DispatchingConfig defines the configuration of the dispatching aspect of a QueueSet.
116
+ type DispatchingConfig struct {
117
+ // ConcurrencyLimit is the maximum number of requests of this QueueSet that may be executing at a time
118
+ ConcurrencyLimit int
119
+ }
120
+
87
121
// EmptyHandler is used to notify the callee when all the queues
88
122
// of a QueueSet have been drained.
89
123
type EmptyHandler interface {
0 commit comments