This sample demonstrates how to build a specialized, zero-reflection custom gRPC codec and memory pool tailored specifically for Google Cloud Spanner streaming reads without requiring any third-party compiler plugins or code-generation tools.
In high-throughput Cloud Spanner workloads (such as analytical streaming queries or large ETL scans via ExecuteStreamingSql), the vast majority of network payload bytes consist of repeated google.protobuf.Value items inside PartialResultSet.values.
The standard Go Protobuf runtime (google.golang.org/protobuf) uses table-driven reflection to parse each message. By writing a lightweight, specialized decoder for PartialResultSet and Value:
*sppb.PartialResultSet and *structpb.Value are parsed directly from wire bytes using inline varint and fixed64 bit-shifts.PartialResultSet chunk containers and inner Value objects (strings, numbers, booleans, nulls) are recycled using sync.Pool.protoc plugins or code generation scripts required.proto.Unmarshal.SpannerFastCodec)Implements google.golang.org/grpc/encoding.Codec:
type SpannerFastCodec struct{}
func (SpannerFastCodec) Name() string { return "proto" }
func (SpannerFastCodec) Marshal(value any) ([]byte, error) {
return proto.Marshal(value.(proto.Message))
}
func (SpannerFastCodec) Unmarshal(data []byte, value any) error {
if partialResultSet, ok := value.(*sppb.PartialResultSet); ok {
return FastUnmarshalPartialResultSet(data, partialResultSet)
}
return proto.Unmarshal(data, value.(proto.Message))
}
CustomPartialResultSetPool)Implements spanner.PartialResultSetPool:
type CustomPartialResultSetPool struct{} func (p *CustomPartialResultSetPool) Get() *sppb.PartialResultSet { return partialResultSetPool.Get().(*sppb.PartialResultSet) } func (p *CustomPartialResultSetPool) Put(partialResultSet *sppb.PartialResultSet) { // Recycles nested *structpb.Value objects and resets the chunk slice ... }
func NewCustomOptimizedSpannerClient(ctx context.Context, database string, opts ...option.ClientOption) (*spanner.Client, error) {
codecOption := option.WithGRPCDialOption(
grpc.WithDefaultCallOptions(grpc.ForceCodec(SpannerFastCodec{})),
)
allOpts := append([]option.ClientOption{codecOption}, opts...)
return spanner.NewClientWithConfig(ctx, database,
spanner.ClientConfig{
SessionPoolConfig: spanner.DefaultSessionPoolConfig,
PartialResultSetPool: &CustomPartialResultSetPool{},
},
allOpts...,
)
}
go test -v ./...
go test -bench=BenchmarkSpannerClient -benchmem -benchtime=2s
BenchmarkSpannerClient/Standard_Protobuf-8 385 6203632 ns/op 5892991 B/op 115213 allocs/op BenchmarkSpannerClient/CustomCodec_With_Pooling-8 415 5777385 ns/op 5571052 B/op 103241 allocs/op