Source file src/cmd/go/internal/cacheprog/cacheprog.go

     1  // Copyright 2024 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  // Package cacheprog defines the protocol for a GOCACHEPROG program.
     6  //
     7  // By default, the go command manages a build cache stored in the file system
     8  // itself. GOCACHEPROG can be set to the name of a command (with optional
     9  // space-separated flags) that implements the go command build cache externally.
    10  // This permits defining a different cache policy.
    11  //
    12  // The go command will start the GOCACHEPROG as a subprocess and communicate
    13  // with it via JSON messages over stdin/stdout. The subprocess's stderr will be
    14  // connected to the go command's stderr.
    15  //
    16  // The subprocess should immediately send a [Response] with its capabilities.
    17  // After that, the go command will send a stream of [Request] messages and the
    18  // subprocess should reply to each [Request] with a [Response] message.
    19  package cacheprog
    20  
    21  import (
    22  	"io"
    23  	"time"
    24  )
    25  
    26  // Cmd is a command that can be issued to a child process.
    27  //
    28  // If the interface needs to grow, the go command can add new commands or new
    29  // versioned commands like "get2" in the future. The initial [Response] from
    30  // the child process indicates which commands it supports.
    31  type Cmd string
    32  
    33  const (
    34  	// CmdPut tells the cache program to store an object in the cache.
    35  	//
    36  	// [Request.ActionID] is the cache key of this object. The cache should
    37  	// store [Request.OutputID] and [Request.Body] under this key for a
    38  	// later "get" request. It must also store the Body in a file in the local
    39  	// file system and return the path to that file in [Response.DiskPath],
    40  	// which must exist at least until a "close" request.
    41  	CmdPut = Cmd("put")
    42  
    43  	// CmdGet tells the cache program to retrieve an object from the cache.
    44  	//
    45  	// [Request.ActionID] specifies the key of the object to get. If the
    46  	// cache does not contain this object, it should set [Response.Miss] to
    47  	// true. Otherwise, it should populate the fields of [Response],
    48  	// including setting [Response.OutputID] to the OutputID of the original
    49  	// "put" request and [Response.DiskPath] to the path of a local file
    50  	// containing the Body of the original "put" request. That file must
    51  	// continue to exist at least until a "close" request.
    52  	CmdGet = Cmd("get")
    53  
    54  	// CmdClose requests that the cache program exit gracefully.
    55  	//
    56  	// The cache program should reply to this request and then exit
    57  	// (thus closing its stdout).
    58  	CmdClose = Cmd("close")
    59  )
    60  
    61  // Request is the JSON-encoded message that's sent from the go command to
    62  // the GOCACHEPROG child process over stdin. Each JSON object is on its own
    63  // line. A ProgRequest of Type "put" with BodySize > 0 will be followed by a
    64  // line containing a base64-encoded JSON string literal of the body.
    65  type Request struct {
    66  	// ID is a unique number per process across all requests.
    67  	// It must be echoed in the Response from the child.
    68  	ID int64
    69  
    70  	// Command is the type of request.
    71  	// The go command will only send commands that were declared
    72  	// as supported by the child.
    73  	Command Cmd
    74  
    75  	// ActionID is the cache key for "put" and "get" requests.
    76  	ActionID []byte `json:",omitempty"` // or nil if not used
    77  
    78  	// OutputID is stored with the body for "put" requests.
    79  	//
    80  	// Prior to Go 1.24, when GOCACHEPROG was still an experiment, this was
    81  	// accidentally named ObjectID. It was renamed to OutputID in Go 1.24.
    82  	OutputID []byte `json:",omitempty"` // or nil if not used
    83  
    84  	// Body is the body for "put" requests. It's sent after the JSON object
    85  	// as a base64-encoded JSON string when BodySize is non-zero.
    86  	// It's sent as a separate JSON value instead of being a struct field
    87  	// send in this JSON object so large values can be streamed in both directions.
    88  	// The base64 string body of a Request will always be written
    89  	// immediately after the JSON object and a newline.
    90  	Body io.Reader `json:"-"`
    91  
    92  	// BodySize is the number of bytes of Body. If zero, the body isn't written.
    93  	BodySize int64 `json:",omitempty"`
    94  
    95  	// ObjectID is the accidental spelling of OutputID that was used prior to Go
    96  	// 1.24.
    97  	//
    98  	// Deprecated: use OutputID. This field is only populated temporarily for
    99  	// backwards compatibility with Go 1.23 and earlier when
   100  	// GOEXPERIMENT=gocacheprog is set. It will be removed in Go 1.25.
   101  	ObjectID []byte `json:",omitempty"`
   102  }
   103  
   104  // Response is the JSON response from the child process to the go command.
   105  //
   106  // With the exception of the first protocol message that the child writes to its
   107  // stdout with ID==0 and KnownCommands populated, these are only sent in
   108  // response to a Request from the go command.
   109  //
   110  // Responses can be sent in any order. The ID must match the request they're
   111  // replying to.
   112  type Response struct {
   113  	ID  int64  // that corresponds to Request; they can be answered out of order
   114  	Err string `json:",omitempty"` // if non-empty, the error
   115  
   116  	// KnownCommands is included in the first message that cache helper program
   117  	// writes to stdout on startup (with ID==0). It includes the
   118  	// Request.Command types that are supported by the program.
   119  	//
   120  	// This lets the go command extend the protocol gracefully over time (adding
   121  	// "get2", etc), or fail gracefully when needed. It also lets the go command
   122  	// verify the program wants to be a cache helper.
   123  	KnownCommands []Cmd `json:",omitempty"`
   124  
   125  	// For "get" requests.
   126  
   127  	Miss     bool       `json:",omitempty"` // cache miss
   128  	OutputID []byte     `json:",omitempty"` // the ObjectID stored with the body
   129  	Size     int64      `json:",omitempty"` // body size in bytes
   130  	Time     *time.Time `json:",omitempty"` // when the object was put in the cache (optional; used for cache expiration)
   131  
   132  	// For "get" and "put" requests.
   133  
   134  	// DiskPath is the absolute path on disk of the body corresponding to a
   135  	// "get" (on cache hit) or "put" request's ActionID.
   136  	DiskPath string `json:",omitempty"`
   137  }
   138  

View as plain text