@@ -63,36 +63,74 @@ type ProgCache struct {
63
63
writeMu sync.Mutex
64
64
}
65
65
66
+ // The following types define the protocol for a GOCACHEPROG program.
67
+ //
68
+ // By default, the go command manages a build cache stored in the file system
69
+ // itself. GOCACHEPROG can be set to the name of a command (with optional
70
+ // space-separated flags) that implements the go command build cache externally.
71
+ // This permits defining a different cache policy.
72
+ //
73
+ // The go command will start the GOCACHEPROG as a subprocess and communicate
74
+ // with it via JSON messages over stdin/stdout. The subprocess's stderr will be
75
+ // connected to the go command's stderr.
76
+ //
77
+ // The subprocess should immediately send a [ProgResponse] with its capabilities.
78
+ // After that, the go command will send a stream of [ProgRequest] messages and the
79
+ // subprocess should reply to each [ProgRequest] with a [ProgResponse] message.
80
+
66
81
// ProgCmd is a command that can be issued to a child process.
67
82
//
68
- // If the interface needs to grow, we can add new commands or new versioned
69
- // commands like "get2".
83
+ // If the interface needs to grow, the go command can add new commands or new
84
+ // versioned commands like "get2" in the future. The initial [ProgResponse] from
85
+ // the child process indicates which commands it supports.
70
86
type ProgCmd string
71
87
72
88
const (
73
- cmdGet = ProgCmd ("get" )
74
- cmdPut = ProgCmd ("put" )
89
+ // cmdPut tells the cache program to store an object in the cache.
90
+ //
91
+ // [ProgRequest.ActionID] is the cache key of this object. The cache should
92
+ // store [ProgRequest.OutputID] and [ProgRequest.Body] under this key for a
93
+ // later "get" request. It must also store the Body in a file in the local
94
+ // file system and return the path to that file in [ProgResponse.DiskPath],
95
+ // which must exist at least until a "close" request.
96
+ cmdPut = ProgCmd ("put" )
97
+
98
+ // cmdGet tells the cache program to retrieve an object from the cache.
99
+ //
100
+ // [ProgRequest.ActionID] specifies the key of the object to get. If the
101
+ // cache does not contain this object, it should set [ProgResponse.Miss] to
102
+ // true. Otherwise, it should populate the fields of [ProgResponse],
103
+ // including setting [ProgResponse.OutputID] to the OutputID of the original
104
+ // "put" request and [ProgResponse.DiskPath] to the path of a local file
105
+ // containing the Body of the original "put" request. That file must
106
+ // continue to exist at least until a "close" request.
107
+ cmdGet = ProgCmd ("get" )
108
+
109
+ // cmdClose requests that the cache program exit gracefully.
110
+ //
111
+ // The cache program should reply to this request and then exit
112
+ // (thus closing its stdout).
75
113
cmdClose = ProgCmd ("close" )
76
114
)
77
115
78
- // ProgRequest is the JSON-encoded message that's sent from cmd/go to
79
- // the GOCACHEPROG child process over stdin. Each JSON object is on its
80
- // own line. A ProgRequest of Type "put" with BodySize > 0 will be followed
81
- // by a line containing a base64-encoded JSON string literal of the body.
116
+ // ProgRequest is the JSON-encoded message that's sent from the go command to
117
+ // the GOCACHEPROG child process over stdin. Each JSON object is on its own
118
+ // line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a
119
+ // line containing a base64-encoded JSON string literal of the body.
82
120
type ProgRequest struct {
83
121
// ID is a unique number per process across all requests.
84
122
// It must be echoed in the ProgResponse from the child.
85
123
ID int64
86
124
87
125
// Command is the type of request.
88
- // The cmd/ go tool will only send commands that were declared
126
+ // The go command will only send commands that were declared
89
127
// as supported by the child.
90
128
Command ProgCmd
91
129
92
- // ActionID is non-nil for get and puts .
130
+ // ActionID is the cache key for "put" and "get" requests .
93
131
ActionID []byte `json:",omitempty"` // or nil if not used
94
132
95
- // OutputID is set for Type "put".
133
+ // OutputID is stored with the body for "put" requests .
96
134
//
97
135
// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
98
136
// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
@@ -118,11 +156,11 @@ type ProgRequest struct {
118
156
ObjectID []byte `json:",omitempty"`
119
157
}
120
158
121
- // ProgResponse is the JSON response from the child process to cmd/go .
159
+ // ProgResponse is the JSON response from the child process to the go command .
122
160
//
123
161
// With the exception of the first protocol message that the child writes to its
124
162
// stdout with ID==0 and KnownCommands populated, these are only sent in
125
- // response to a ProgRequest from cmd/go .
163
+ // response to a ProgRequest from the go command .
126
164
//
127
165
// ProgResponses can be sent in any order. The ID must match the request they're
128
166
// replying to.
@@ -134,21 +172,22 @@ type ProgResponse struct {
134
172
// writes to stdout on startup (with ID==0). It includes the
135
173
// ProgRequest.Command types that are supported by the program.
136
174
//
137
- // This lets us extend the protocol gracefully over time (adding "get2",
138
- // etc), or fail gracefully when needed. It also lets us verify the program
139
- // wants to be a cache helper.
175
+ // This lets the go command extend the protocol gracefully over time (adding
176
+ // "get2", etc), or fail gracefully when needed. It also lets the go command
177
+ // verify the program wants to be a cache helper.
140
178
KnownCommands []ProgCmd `json:",omitempty"`
141
179
142
- // For Get requests.
180
+ // For "get" requests.
143
181
144
182
Miss bool `json:",omitempty"` // cache miss
145
- OutputID []byte `json:",omitempty"`
146
- Size int64 `json:",omitempty"` // in bytes
147
- Time * time.Time `json:",omitempty"` // an Entry.Time; when the object was added to the docs
183
+ OutputID []byte `json:",omitempty"` // the ObjectID stored with the body
184
+ Size int64 `json:",omitempty"` // body size in bytes
185
+ Time * time.Time `json:",omitempty"` // when the object was put in the cache (optional; used for cache expiration)
186
+
187
+ // For "get" and "put" requests.
148
188
149
- // DiskPath is the absolute path on disk of the ObjectID corresponding
150
- // a "get" request's ActionID (on cache hit) or a "put" request's
151
- // provided ObjectID.
189
+ // DiskPath is the absolute path on disk of the body corresponding to a
190
+ // "get" (on cache hit) or "put" request's ActionID.
152
191
DiskPath string `json:",omitempty"`
153
192
}
154
193
@@ -183,6 +222,8 @@ func startCacheProg(progAndArgs string, fuzzDirCache Cache) Cache {
183
222
base .Fatalf ("StdinPipe to GOCACHEPROG: %v" , err )
184
223
}
185
224
cmd .Stderr = os .Stderr
225
+ // On close, we cancel the context. Rather than killing the helper,
226
+ // close its stdin.
186
227
cmd .Cancel = in .Close
187
228
188
229
if err := cmd .Start (); err != nil {
@@ -435,7 +476,9 @@ func (c *ProgCache) Close() error {
435
476
if c .can [cmdClose ] {
436
477
_ , err = c .send (c .ctx , & ProgRequest {Command : cmdClose })
437
478
}
479
+ // Cancel the context, which will close the helper's stdin.
438
480
c .ctxCancel ()
481
+ // Wait until the helper closes its stdout.
439
482
<- c .readLoopDone
440
483
return err
441
484
}
0 commit comments