Skip to content

Commit 4774e0f

Browse files
radeksimkoSarahFrench
authored andcommitted
Implement configurable state chunk size
1 parent deb7423 commit 4774e0f

File tree

2 files changed

+35
-1
lines changed

2 files changed

+35
-1
lines changed

internal/command/meta_backend.go

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,20 @@ import (
4949
tfversion "github.com/hashicorp/terraform/version"
5050
)
5151

52+
const (
53+
// defaultStateStoreChunkSize is the default chunk size proposed
54+
// to the provider.
55+
// This can be tweaked but should provide reasonable performance
56+
// trade-offs for average network conditions and state file sizes.
57+
defaultStateStoreChunkSize int64 = 8 << 20 // 8 MB
58+
59+
// maxStateStoreChunkSize is the highest chunk size provider may choose
60+
// which we still consider reasonable/safe.
61+
// This reflects terraform-plugin-go's max. RPC message size of 256MB
62+
// and leaves plenty of space for other variable data like diagnostics.
63+
maxStateStoreChunkSize int64 = 128 << 20 // 128 MB
64+
)
65+
5266
// BackendOpts are the options used to initialize a backendrun.OperationsBackend.
5367
type BackendOpts struct {
5468
// BackendConfig is a representation of the backend configuration block given in
@@ -2127,7 +2141,6 @@ func (m *Meta) stateStoreInitFromConfig(c *configs.StateStore, opts *BackendOpts
21272141
configureResp := provider.ConfigureProvider(providers.ConfigureProviderRequest{
21282142
TerraformVersion: tfversion.String(),
21292143
Config: providerConfigVal,
2130-
// TODO ClientCapabilities?
21312144
})
21322145
diags = diags.Append(configureResp.Diagnostics)
21332146
if configureResp.Diagnostics.HasErrors() {
@@ -2149,12 +2162,32 @@ func (m *Meta) stateStoreInitFromConfig(c *configs.StateStore, opts *BackendOpts
21492162
cfgStoreResp := provider.ConfigureStateStore(providers.ConfigureStateStoreRequest{
21502163
TypeName: c.Type,
21512164
Config: stateStoreConfigVal,
2165+
Capabilities: providers.StateStoreClientCapabilities{
2166+
ChunkSize: defaultStateStoreChunkSize,
2167+
},
21522168
})
21532169
diags = diags.Append(cfgStoreResp.Diagnostics)
21542170
if cfgStoreResp.Diagnostics.HasErrors() {
21552171
return nil, cty.NilVal, cty.NilVal, diags
21562172
}
21572173

2174+
chunkSize := cfgStoreResp.Capabilities.ChunkSize
2175+
if chunkSize > maxStateStoreChunkSize {
2176+
diags = diags.Append(fmt.Errorf("Failed to negotiate acceptable chunk size. "+
2177+
"Expected size <= %d bytes, provider wants %d bytes",
2178+
maxStateStoreChunkSize, chunkSize,
2179+
))
2180+
return nil, cty.NilVal, cty.NilVal, diags
2181+
}
2182+
2183+
p, ok := provider.(providers.StateStoreChunkSizeSetter)
2184+
if !ok {
2185+
msg := fmt.Sprintf("Unable to set chunk size for provider %s; this is a bug in Terraform - please report it", c.Type)
2186+
panic(msg)
2187+
}
2188+
// casting to int here is okay because the number should never exceed int32
2189+
p.SetStateStoreChunkSize(c.Type, int(chunkSize))
2190+
21582191
// Now we have a fully configured state store, ready to be used.
21592192
// To make it usable we need to return it in a backend.Backend interface.
21602193
b, err := backendPluggable.NewPluggable(provider, c.Type)

internal/plugin6/grpc_provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1562,6 +1562,7 @@ func (p *GRPCProvider) ReadStateBytes(r providers.ReadStateBytesRequest) (resp p
15621562

15631563
buf := &bytes.Buffer{}
15641564
var expectedTotalLength int
1565+
// TODO: Send warning if client misbehaves and uses (lower) chunk size that we didn't agree on
15651566
for {
15661567
chunk, err := client.Recv()
15671568
if err == io.EOF {

0 commit comments

Comments
 (0)