aerospike / aerospike-client-go

Aerospike Client Go
Apache License 2.0
429 stars 199 forks source link

Buffers not correctly set for MapIncrementOp on v6 BatchOperate for writes #376

Closed leedavis81 closed 2 years ago

leedavis81 commented 2 years ago

The new aerospike.NewBatchWrite feature doesn't allocate the correct buffer size for a MapIncrementOp determined at https://github.com/aerospike/aerospike-client-go/blob/v6/command.go#L606-L629

This results in a slice out of range panic when it begins writing ops into the buffer slice...

panic: runtime error: slice bounds out of range [:360043] with capacity 360040

goroutine 28 [running]:
github.com/aerospike/aerospike-client-go/v6.(*bufferEx).Write(0xc000512140, {0xc00002a1c0, 0xc000236b48, 0x127aeea})
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/bytes_buffer.go:145 +0x90
github.com/aerospike/aerospike-client-go/v6.BytesValue.write(...)
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/value.go:595
github.com/aerospike/aerospike-client-go/v6.(*baseCommand).writeOperationForOperation(0xc000512140, 0xc000092480)
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/command.go:2163 +0x32d
github.com/aerospike/aerospike-client-go/v6.(*baseCommand).writeBatchOperations(0xc000512140, 0xc000094068, {0xc000094068, 0x1, 0xc00023e0a0}, 0xc000236c18, 0x1084037)
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/command.go:1028 +0x66
github.com/aerospike/aerospike-client-go/v6.(*baseCommand).setBatchOperateIfc(0xc000512140, 0xc0000924e0, {0xc000480000, 0x1388, 0x14067b8}, 0xc0000924e0)
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/command.go:702 +0x83d
github.com/aerospike/aerospike-client-go/v6.(*batchCommandOperate).writeBuffer(0xc000512140, {0x14067b8, 0xc0000924e0})
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/batch_command_operate.go:55 +0x45
github.com/aerospike/aerospike-client-go/v6.(*baseCommand).executeAt(0xc000512140, {0x1410508, 0xc000512140}, 0xc0000924e0, 0xb9, {0x1381796, 0x0, 0x1647000}, 0xc000049720, 0x0)
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/command.go:2544 +0xa74
github.com/aerospike/aerospike-client-go/v6.(*baseCommand).execute(0xc0000981a4, {0x1410508, 0xc000512140}, 0xf0)
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/command.go:2421 +0x8a
github.com/aerospike/aerospike-client-go/v6.(*baseMultiCommand).execute(...)
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/multi_command.go:407
github.com/aerospike/aerospike-client-go/v6.(*batchCommandOperate).Execute(0x1275606)
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/batch_command_operate.go:169 +0x2a
github.com/aerospike/aerospike-client-go/v6.(*werrGroup).execute.func1()
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/werrgroup.go:62 +0xdb
created by github.com/aerospike/aerospike-client-go/v6.(*werrGroup).execute
    /project/vendor/github.com/aerospike/aerospike-client-go/v6/werrgroup.go:55 +0x15a

Here's a supporting test..


import (
    "github.com/aerospike/aerospike-client-go/v6"
    "github.com/stretchr/testify/assert"
    "testing"
    "time"
)

func TestBatchWrites(t *testing.T) {

    client, err := aerospike.NewClient("127.0.0.1", 3010)
    if err != nil {
        panic(err)
    }

    now := time.Now().UTC()
    if err := client.Truncate(client.DefaultWritePolicy, "sdb", "", &now); err != nil {
        panic(err)
    }

    ops := []*aerospike.Operation{
        aerospike.MapIncrementOp(
            aerospike.DefaultMapPolicy(),
            "f",
            "1",
            1,
            aerospike.CtxMapKeyCreate(aerospike.StringValue("mm"), aerospike.MapOrder.UNORDERED),
            // frequency map is to be key ordered by segment id
            aerospike.CtxMapKeyCreate(aerospike.IntegerValue(123), aerospike.MapOrder.KEY_ORDERED)),
    }

    var batchKeys []*aerospike.Key
    var writeRecords []aerospike.BatchRecordIfc
    for x := 0; x < 5000; x++ {
        batchEntry, err := aerospike.NewKey("sdb", "", x)
        batchKeys = append(batchKeys, batchEntry)
        if err != nil {
            panic(err)
        }
        writeRecords = append(
            writeRecords,
            aerospike.NewBatchWrite(
                aerospike.NewBatchWritePolicy(),
                batchEntry,
                ops...),
        )
    }

    err = client.BatchOperate(aerospike.NewBatchPolicy(), writeRecords)
    if err != nil {
        panic(err)
    }

    records, err := client.BatchGet(aerospike.NewBatchPolicy(), batchKeys, "f")
    if err != nil {
        panic(err)
    }

    assert.Equal(t, len(batchKeys), len(records))

    for _, r := range records {
        assert.NotEqual(t, nil, r)
        if r == nil{
            panic("nil BatchGet record")
        }
    }
}
khaf commented 2 years ago

Thanks for your report. The fix was released in v6.1.0, but please upgrade to v6.2.0 released today since it a few more important fixes.