apache / apache/cassandra-gocql-driver

Memory allocations optimization

Open
#1,695 7 comments 0 reactions 0 assignees View on GitHub
semver-major
Dominant language
Go
Stars
2.7k
Forks
658
PR merge metrics
No merged PRs in 30d

Description

There are lots of peaces of code where reciever is concrete value:
```
type CollectionType struct {
NativeType
Key TypeInfo // only used for TypeMap
Elem TypeInfo // only used for TypeMap, TypeList and TypeSet
}

func (t CollectionType) NewWithError() (interface{}, error) {
typ, err := goType(t)
if err != nil {
return nil, err
}
return reflect.New(typ).Interface(), nil
}
```

As result when `NewWithError` is called golang recreate copy of reciever, i.e. `CollectionType` struct.
There is simple way to optimize it is to convert all of them to pointer reciever, which will make these allocations go away.
I have run test on that and here is results.

Before the fix (concrete receiver)
```
➜ gocql git:(dk/1693-potential-panic-on-deserialization) ✗ go test -bench . -benchmem
goos: linux
goarch: amd64
pkg: github.com/gocql/gocql
cpu: 12th Gen Intel(R) Core(TM) i9-12900HK
BenchmarkMarshal-20 1532197 751.1 ns/op 504 B/op 13 allocs/op
```

After the fix (pointer receiver)
```
➜ gocql git:(dk/1693-potential-panic-on-deserialization) ✗ go test -bench . -benchmem
goos: linux
goarch: amd64
pkg: github.com/gocql/gocql
cpu: 12th Gen Intel(R) Core(TM) i9-12900HK
BenchmarkMarshal-20 1793576 676.4 ns/op 312 B/op 11 allocs/op
```

As you can see size-wize memory allocations went from `504` to `312` B/op and allocations went from `13` to `11` per op.

Test code:
```
func BenchmarkMarshal(b *testing.B) {
typeInfo := UDTTypeInfo{NativeType{proto: 3, typ: TypeUDT}, "", "xyz", []UDTField{
{Name: "x", Type: &NativeType{proto: 3, typ: TypeInt}},
{Name: "y", Type: &NativeType{proto: 3, typ: TypeInt}},
{Name: "z", Type: &NativeType{proto: 3, typ: TypeInt}},
}}
type NewWithError struct {
Value interface{}
Error error
}

type ResultStore struct {
NewWithError NewWithError
New interface{}
String string
Type Type
Version byte
Custom string
}

store := make([]ResultStore, b.N)
b.ResetTimer()
for i := 0; i < b.N; i++ {
rec := &store[i]
rec.NewWithError.Value, rec.NewWithError.Error = typeInfo.NewWithError()
rec.New = typeInfo.New()
rec.String = typeInfo.String()
rec.Type = typeInfo.Type()
rec.Version = typeInfo.Version()
rec.Custom = typeInfo.Custom()
}
}
```

Contributor guide

Open the contributing guide

Research direction

Start by locating CollectionType.NewWithError and the other concrete-value receiver methods described in the issue. Run the provided BenchmarkMarshal with go test -bench . -benchmem before and after the receiver changes; done means the relevant methods use pointer receivers without breaking the test suite and the benchmark confirms the reported allocation improvement.

Written by the indexing model from the issue text.

Assessment

Tech stack
go
Domain
databases, performance
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.