@@ -1005,6 +1005,53 @@ type BatchCursor struct {
1005
1005
}
1006
1006
1007
1007
func (m * Map ) batchLookup (cmd sys.Cmd , cursor * BatchCursor , keysOut , valuesOut interface {}, opts * BatchOptions ) (int , error ) {
1008
+ if m .typ .hasPerCPUValue () {
1009
+ return m .batchLookupPerCPU (cmd , cursor , keysOut , valuesOut , opts )
1010
+ }
1011
+
1012
+ count , err := batchCount (keysOut , valuesOut )
1013
+ if err != nil {
1014
+ return 0 , err
1015
+ }
1016
+
1017
+ valueBuf := sysenc .SyscallOutput (valuesOut , count * int (m .fullValueSize ))
1018
+
1019
+ n , err := m .batchLookupCmd (cmd , cursor , count , keysOut , valueBuf .Pointer (), opts )
1020
+ if err != nil {
1021
+ return n , err
1022
+ }
1023
+
1024
+ err = valueBuf .Unmarshal (valuesOut )
1025
+ if err != nil {
1026
+ return 0 , err
1027
+ }
1028
+
1029
+ return n , nil
1030
+ }
1031
+
1032
+ func (m * Map ) batchLookupPerCPU (cmd sys.Cmd , cursor * BatchCursor , keysOut , valuesOut interface {}, opts * BatchOptions ) (int , error ) {
1033
+ count , err := sliceLen (keysOut )
1034
+ if err != nil {
1035
+ return 0 , fmt .Errorf ("keys: %w" , err )
1036
+ }
1037
+
1038
+ valueBuf := make ([]byte , count * int (m .fullValueSize ))
1039
+ valuePtr := sys .NewSlicePointer (valueBuf )
1040
+
1041
+ n , sysErr := m .batchLookupCmd (cmd , cursor , count , keysOut , valuePtr , opts )
1042
+ if sysErr != nil && ! errors .Is (sysErr , unix .ENOENT ) {
1043
+ return 0 , err
1044
+ }
1045
+
1046
+ err = unmarshalBatchPerCPUValue (valuesOut , count , int (m .valueSize ), valueBuf )
1047
+ if err != nil {
1048
+ return 0 , err
1049
+ }
1050
+
1051
+ return n , sysErr
1052
+ }
1053
+
1054
+ func (m * Map ) batchLookupCmd (cmd sys.Cmd , cursor * BatchCursor , count int , keysOut any , valuePtr sys.Pointer , opts * BatchOptions ) (int , error ) {
1008
1055
cursorLen := int (m .keySize )
1009
1056
if cursorLen < 4 {
1010
1057
// * generic_map_lookup_batch requires that batch_out is key_size bytes.
@@ -1033,29 +1080,13 @@ func (m *Map) batchLookup(cmd sys.Cmd, cursor *BatchCursor, keysOut, valuesOut i
1033
1080
if err := haveBatchAPI (); err != nil {
1034
1081
return 0 , err
1035
1082
}
1036
- if m .typ .hasPerCPUValue () {
1037
- return 0 , ErrNotSupported
1038
- }
1039
- keysValue := reflect .ValueOf (keysOut )
1040
- if keysValue .Kind () != reflect .Slice {
1041
- return 0 , fmt .Errorf ("keys must be a slice" )
1042
- }
1043
- valuesValue := reflect .ValueOf (valuesOut )
1044
- if valuesValue .Kind () != reflect .Slice {
1045
- return 0 , fmt .Errorf ("valuesOut must be a slice" )
1046
- }
1047
- count := keysValue .Len ()
1048
- if count != valuesValue .Len () {
1049
- return 0 , fmt .Errorf ("keysOut and valuesOut must be the same length" )
1050
- }
1051
1083
1052
1084
keyBuf := sysenc .SyscallOutput (keysOut , count * int (m .keySize ))
1053
- valueBuf := sysenc .SyscallOutput (valuesOut , count * int (m .fullValueSize ))
1054
1085
1055
1086
attr := sys.MapLookupBatchAttr {
1056
1087
MapFd : m .fd .Uint (),
1057
1088
Keys : keyBuf .Pointer (),
1058
- Values : valueBuf . Pointer () ,
1089
+ Values : valuePtr ,
1059
1090
Count : uint32 (count ),
1060
1091
InBatch : sys .NewSlicePointer (inBatch ),
1061
1092
OutBatch : sys .NewSlicePointer (cursor .opaque ),
@@ -1075,9 +1106,6 @@ func (m *Map) batchLookup(cmd sys.Cmd, cursor *BatchCursor, keysOut, valuesOut i
1075
1106
if err := keyBuf .Unmarshal (keysOut ); err != nil {
1076
1107
return 0 , err
1077
1108
}
1078
- if err := valueBuf .Unmarshal (valuesOut ); err != nil {
1079
- return 0 , err
1080
- }
1081
1109
1082
1110
return int (attr .Count ), sysErr
1083
1111
}
@@ -1088,29 +1116,24 @@ func (m *Map) batchLookup(cmd sys.Cmd, cursor *BatchCursor, keysOut, valuesOut i
1088
1116
// to a slice or buffer will not work.
1089
1117
func (m * Map ) BatchUpdate (keys , values interface {}, opts * BatchOptions ) (int , error ) {
1090
1118
if m .typ .hasPerCPUValue () {
1091
- return 0 , ErrNotSupported
1119
+ return m . batchUpdatePerCPU ( keys , values , opts )
1092
1120
}
1093
- keysValue := reflect .ValueOf (keys )
1094
- if keysValue .Kind () != reflect .Slice {
1095
- return 0 , fmt .Errorf ("keys must be a slice" )
1096
- }
1097
- valuesValue := reflect .ValueOf (values )
1098
- if valuesValue .Kind () != reflect .Slice {
1099
- return 0 , fmt .Errorf ("values must be a slice" )
1100
- }
1101
- var (
1102
- count = keysValue .Len ()
1103
- valuePtr sys.Pointer
1104
- err error
1105
- )
1106
- if count != valuesValue .Len () {
1107
- return 0 , fmt .Errorf ("keys and values must be the same length" )
1121
+
1122
+ count , err := batchCount (keys , values )
1123
+ if err != nil {
1124
+ return 0 , err
1108
1125
}
1109
- keyPtr , err := marshalMapSyscallInput (keys , count * int (m .keySize ))
1126
+
1127
+ valuePtr , err := marshalMapSyscallInput (values , count * int (m .valueSize ))
1110
1128
if err != nil {
1111
1129
return 0 , err
1112
1130
}
1113
- valuePtr , err = marshalMapSyscallInput (values , count * int (m .valueSize ))
1131
+
1132
+ return m .batchUpdate (count , keys , valuePtr , opts )
1133
+ }
1134
+
1135
+ func (m * Map ) batchUpdate (count int , keys any , valuePtr sys.Pointer , opts * BatchOptions ) (int , error ) {
1136
+ keyPtr , err := marshalMapSyscallInput (keys , count * int (m .keySize ))
1114
1137
if err != nil {
1115
1138
return 0 , err
1116
1139
}
@@ -1137,17 +1160,28 @@ func (m *Map) BatchUpdate(keys, values interface{}, opts *BatchOptions) (int, er
1137
1160
return int (attr .Count ), nil
1138
1161
}
1139
1162
1163
+ func (m * Map ) batchUpdatePerCPU (keys , values any , opts * BatchOptions ) (int , error ) {
1164
+ count , err := sliceLen (keys )
1165
+ if err != nil {
1166
+ return 0 , fmt .Errorf ("keys: %w" , err )
1167
+ }
1168
+
1169
+ valueBuf , err := marshalBatchPerCPUValue (values , count , int (m .valueSize ))
1170
+ if err != nil {
1171
+ return 0 , err
1172
+ }
1173
+
1174
+ return m .batchUpdate (count , keys , sys .NewSlicePointer (valueBuf ), opts )
1175
+ }
1176
+
1140
1177
// BatchDelete batch deletes entries in the map by keys.
1141
1178
// "keys" must be of type slice, a pointer to a slice or buffer will not work.
1142
1179
func (m * Map ) BatchDelete (keys interface {}, opts * BatchOptions ) (int , error ) {
1143
- if m .typ .hasPerCPUValue () {
1144
- return 0 , ErrNotSupported
1145
- }
1146
- keysValue := reflect .ValueOf (keys )
1147
- if keysValue .Kind () != reflect .Slice {
1148
- return 0 , fmt .Errorf ("keys must be a slice" )
1180
+ count , err := sliceLen (keys )
1181
+ if err != nil {
1182
+ return 0 , fmt .Errorf ("keys: %w" , err )
1149
1183
}
1150
- count := keysValue . Len ()
1184
+
1151
1185
keyPtr , err := marshalMapSyscallInput (keys , count * int (m .keySize ))
1152
1186
if err != nil {
1153
1187
return 0 , fmt .Errorf ("cannot marshal keys: %v" , err )
@@ -1174,6 +1208,24 @@ func (m *Map) BatchDelete(keys interface{}, opts *BatchOptions) (int, error) {
1174
1208
return int (attr .Count ), nil
1175
1209
}
1176
1210
1211
+ func batchCount (keys , values any ) (int , error ) {
1212
+ keysLen , err := sliceLen (keys )
1213
+ if err != nil {
1214
+ return 0 , fmt .Errorf ("keys: %w" , err )
1215
+ }
1216
+
1217
+ valuesLen , err := sliceLen (values )
1218
+ if err != nil {
1219
+ return 0 , fmt .Errorf ("values: %w" , err )
1220
+ }
1221
+
1222
+ if keysLen != valuesLen {
1223
+ return 0 , fmt .Errorf ("keys and values must have the same length" )
1224
+ }
1225
+
1226
+ return keysLen , nil
1227
+ }
1228
+
1177
1229
// Iterate traverses a map.
1178
1230
//
1179
1231
// It's safe to create multiple iterators at the same time.
@@ -1552,3 +1604,12 @@ func NewMapFromID(id MapID) (*Map, error) {
1552
1604
1553
1605
return newMapFromFD (fd )
1554
1606
}
1607
+
1608
+ // sliceLen returns the length if the value is a slice or an error otherwise.
1609
+ func sliceLen (slice any ) (int , error ) {
1610
+ sliceValue := reflect .ValueOf (slice )
1611
+ if sliceValue .Kind () != reflect .Slice {
1612
+ return 0 , fmt .Errorf ("%T is not a slice" , slice )
1613
+ }
1614
+ return sliceValue .Len (), nil
1615
+ }
0 commit comments