-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathlimits.go
More file actions
145 lines (130 loc) · 5.57 KB
/
Copy pathlimits.go
File metadata and controls
145 lines (130 loc) · 5.57 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
package codemode
import (
"fmt"
"time"
)
const (
defaultMaxSourceBytes = 64 * 1024
defaultMaxExecutionSteps = 1_000_000
defaultMaxExecutionTime = 5 * time.Second
defaultMaxNativeCalls = 100
defaultMaxValueDepth = 32
defaultMaxValueBytes = 1024 * 1024
defaultMaxIntermediateValueBytes = 8 * 1024 * 1024
defaultMaxSearchQueryBytes = 256
defaultMaxSearchResults = 20
defaultMaxConcurrentExecutions = 8
)
// Limits bounds one execution and the model-facing catalog search surface.
type Limits struct {
// MaxSourceBytes is the maximum accepted Starlark source size in bytes.
MaxSourceBytes int
// MaxExecutionSteps is the maximum number of Starlark bytecode steps.
MaxExecutionSteps uint64
// MaxExecutionTime is the maximum elapsed execution budget. The budget starts
// before waiting for a worker slot and covers spawn, protocol exchange,
// Starlark execution, and parent dispatch. Killing and reaping can add
// operating-system overhead.
MaxExecutionTime time.Duration
// MaxNativeCalls is the maximum number of attempted native capability calls.
MaxNativeCalls uint64
// MaxValueDepth is the maximum nesting depth of any JSON-shaped value crossing
// the worker boundary, including arguments, native results, and the final value.
MaxValueDepth int
// MaxValueBytes is the maximum encoded size of any JSON-shaped value crossing
// the worker boundary, including arguments, native results, and the final value.
// Size is measured by CodeMode's type-preserving JSON value encoder.
MaxValueBytes int
// MaxIntermediateValueBytes is the maximum cumulative encoded size of
// successful parent-to-child native-result value bodies in one Execute
// call. Size is measured by CodeMode's type-preserving JSON value encoder
// and excludes frame envelopes, native-call arguments, failed handlers,
// and the final program value. The budget is independent of MaxValueBytes.
MaxIntermediateValueBytes int
// MaxSearchQueryBytes is the maximum capability-search query size in bytes.
MaxSearchQueryBytes int
// MaxSearchResults is the maximum number of capability-search results.
MaxSearchResults int
// MaxConcurrentExecutions is the maximum number of concurrent spawn attempts
// and live execution-worker children. Waiting for a slot consumes
// MaxExecutionTime and remains cancelable through the request context.
MaxConcurrentExecutions int
}
// DefaultLimits returns positive development defaults for every supported budget.
func DefaultLimits() Limits {
return Limits{
MaxSourceBytes: defaultMaxSourceBytes,
MaxExecutionSteps: defaultMaxExecutionSteps,
MaxExecutionTime: defaultMaxExecutionTime,
MaxNativeCalls: defaultMaxNativeCalls,
MaxValueDepth: defaultMaxValueDepth,
MaxValueBytes: defaultMaxValueBytes,
MaxIntermediateValueBytes: defaultMaxIntermediateValueBytes,
MaxSearchQueryBytes: defaultMaxSearchQueryBytes,
MaxSearchResults: defaultMaxSearchResults,
MaxConcurrentExecutions: defaultMaxConcurrentExecutions,
}
}
// withDefaults replaces each zero-valued field with its bounded default.
func (limits Limits) withDefaults() Limits {
defaults := DefaultLimits()
if limits.MaxSourceBytes == 0 {
limits.MaxSourceBytes = defaults.MaxSourceBytes
}
if limits.MaxExecutionSteps == 0 {
limits.MaxExecutionSteps = defaults.MaxExecutionSteps
}
if limits.MaxExecutionTime == 0 {
limits.MaxExecutionTime = defaults.MaxExecutionTime
}
if limits.MaxNativeCalls == 0 {
limits.MaxNativeCalls = defaults.MaxNativeCalls
}
if limits.MaxValueDepth == 0 {
limits.MaxValueDepth = defaults.MaxValueDepth
}
if limits.MaxValueBytes == 0 {
limits.MaxValueBytes = defaults.MaxValueBytes
}
if limits.MaxIntermediateValueBytes == 0 {
limits.MaxIntermediateValueBytes = defaults.MaxIntermediateValueBytes
}
if limits.MaxSearchQueryBytes == 0 {
limits.MaxSearchQueryBytes = defaults.MaxSearchQueryBytes
}
if limits.MaxSearchResults == 0 {
limits.MaxSearchResults = defaults.MaxSearchResults
}
if limits.MaxConcurrentExecutions == 0 {
limits.MaxConcurrentExecutions = defaults.MaxConcurrentExecutions
}
return limits
}
// Validate rejects non-positive limits; Build replaces zero-valued fields with
// bounded defaults before validation.
func (limits Limits) Validate() error {
switch {
case limits.MaxSourceBytes <= 0:
return fmt.Errorf("%w: MaxSourceBytes must be positive", ErrInvalidRegistration)
case limits.MaxExecutionSteps == 0:
return fmt.Errorf("%w: MaxExecutionSteps must be positive", ErrInvalidRegistration)
case limits.MaxExecutionTime <= 0:
return fmt.Errorf("%w: MaxExecutionTime must be positive", ErrInvalidRegistration)
case limits.MaxNativeCalls == 0:
return fmt.Errorf("%w: MaxNativeCalls must be positive", ErrInvalidRegistration)
case limits.MaxValueDepth <= 0:
return fmt.Errorf("%w: MaxValueDepth must be positive", ErrInvalidRegistration)
case limits.MaxValueBytes <= 0:
return fmt.Errorf("%w: MaxValueBytes must be positive", ErrInvalidRegistration)
case limits.MaxIntermediateValueBytes <= 0:
return fmt.Errorf("%w: MaxIntermediateValueBytes must be positive", ErrInvalidRegistration)
case limits.MaxSearchQueryBytes <= 0:
return fmt.Errorf("%w: MaxSearchQueryBytes must be positive", ErrInvalidRegistration)
case limits.MaxSearchResults <= 0:
return fmt.Errorf("%w: MaxSearchResults must be positive", ErrInvalidRegistration)
case limits.MaxConcurrentExecutions <= 0:
return fmt.Errorf("%w: MaxConcurrentExecutions must be positive", ErrInvalidRegistration)
default:
return nil
}
}