Skip to content

Commit 130bbbb

Browse files
aiborlmb
authored andcommitted
map: unmarshal values for partial batch
In case of a partial batch the values are not unmarshalled in BatchLookup and BatchLookupDelete for non-perCPU maps. This commit fixes it by adapting the error handling from batchLookupPerCPU. Fixes #1741 Signed-off-by: Tobias Böhm <[email protected]>
1 parent a77e0ce commit 130bbbb

File tree

2 files changed

+65
-6
lines changed

2 files changed

+65
-6
lines changed

map.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,21 +1152,21 @@ func (m *Map) batchLookup(cmd sys.Cmd, cursor *MapBatchCursor, keysOut, valuesOu
11521152

11531153
valueBuf := sysenc.SyscallOutput(valuesOut, count*int(m.fullValueSize))
11541154

1155-
n, err := m.batchLookupCmd(cmd, cursor, count, keysOut, valueBuf.Pointer(), opts)
1156-
if errors.Is(err, unix.ENOSPC) {
1155+
n, sysErr := m.batchLookupCmd(cmd, cursor, count, keysOut, valueBuf.Pointer(), opts)
1156+
if errors.Is(sysErr, unix.ENOSPC) {
11571157
// Hash tables return ENOSPC when the size of the batch is smaller than
11581158
// any bucket.
1159-
return n, fmt.Errorf("%w (batch size too small?)", err)
1160-
} else if err != nil {
1161-
return n, err
1159+
return n, fmt.Errorf("%w (batch size too small?)", sysErr)
1160+
} else if sysErr != nil && !errors.Is(sysErr, unix.ENOENT) {
1161+
return 0, sysErr
11621162
}
11631163

11641164
err = valueBuf.Unmarshal(valuesOut)
11651165
if err != nil {
11661166
return 0, err
11671167
}
11681168

1169-
return n, nil
1169+
return n, sysErr
11701170
}
11711171

11721172
func (m *Map) batchLookupPerCPU(cmd sys.Cmd, cursor *MapBatchCursor, keysOut, valuesOut interface{}, opts *BatchOptions) (int, error) {

map_test.go

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -983,6 +983,65 @@ func TestMapBatchLookupAllocations(t *testing.T) {
983983
qt.Assert(t, qt.Equals(allocs, 0))
984984
}
985985

986+
type customTestUnmarshaler []uint8
987+
988+
func (c customTestUnmarshaler) UnmarshalBinary(data []byte) error {
989+
chunkSize := len(data) / len(c)
990+
991+
for i := range len(data) / chunkSize {
992+
c[i] = data[i*chunkSize]
993+
}
994+
995+
return nil
996+
}
997+
998+
func TestMapBatchLookupCustomUnmarshaler(t *testing.T) {
999+
testutils.SkipIfNotSupported(t, haveBatchAPI())
1000+
1001+
m := mustNewMap(t, &MapSpec{
1002+
Type: Array,
1003+
MaxEntries: 3,
1004+
KeySize: 4,
1005+
ValueSize: 4,
1006+
Contents: []MapKV{
1007+
{uint32(0), uint32(3)},
1008+
{uint32(1), uint32(4)},
1009+
{uint32(2), uint32(5)},
1010+
},
1011+
}, nil)
1012+
1013+
var (
1014+
cursor MapBatchCursor
1015+
// Use data structures that result in different memory size than the
1016+
// map keys and values. Otherwise their memory is used as backing
1017+
// memory for the syscall directly and Unmarshal is a no-op.
1018+
// Use batch size that results in partial second lookup.
1019+
batchKeys = make(customTestUnmarshaler, 2)
1020+
batchValues = make(customTestUnmarshaler, 2)
1021+
keys []uint8
1022+
values []uint8
1023+
)
1024+
1025+
_, err := m.BatchLookup(&cursor, batchKeys, batchValues, nil)
1026+
if err != nil {
1027+
t.Fatal("Full batch lookup failed:", err)
1028+
}
1029+
1030+
keys = append(keys, batchKeys...)
1031+
values = append(values, batchValues...)
1032+
1033+
_, err = m.BatchLookup(&cursor, batchKeys, batchValues, nil)
1034+
if !errors.Is(err, ErrKeyNotExist) {
1035+
t.Fatal("Partial batch lookup doesn't return ErrKeyNotExist:", err)
1036+
}
1037+
1038+
keys = append(keys, batchKeys[0])
1039+
values = append(values, batchValues[0])
1040+
1041+
qt.Assert(t, qt.DeepEquals(keys, []uint8{0, 1, 2}))
1042+
qt.Assert(t, qt.DeepEquals(values, []uint8{3, 4, 5}))
1043+
}
1044+
9861045
func TestMapIterateHashKeyOneByteFull(t *testing.T) {
9871046
hash := mustNewMap(t, &MapSpec{
9881047
Type: Hash,

0 commit comments

Comments
 (0)