@@ -1272,14 +1272,20 @@ func batchCount(keys, values any) (int, error) {
12721272//
12731273// It's not possible to guarantee that all keys in a map will be
12741274// returned if there are concurrent modifications to the map.
1275- //
1276- // For value-only maps (Queue and Stack), multiple iterators will
1277- // never lookup the same entry, as it is removed from the buffer by design
1278- // (pop operation).
1279- func (m * Map ) Iterate () MapIterator {
1275+ func (m * Map ) Iterate () * MapIterator {
12801276 return newMapIterator (m )
12811277}
12821278
1279+ // Drain traverses a map while also removing entries.
1280+ //
1281+ // It's safe to create multiple drainers at the same time,
1282+ // but their respective outputs will differ.
1283+ func (m * Map ) Drain () * MapIterator {
1284+ it := newMapIterator (m )
1285+ it .drain = true
1286+ return it
1287+ }
1288+
12831289// Close the Map's underlying file descriptor, which could unload the
12841290// Map from the kernel if it is not pinned or in use by a loaded Program.
12851291func (m * Map ) Close () error {
@@ -1529,103 +1535,57 @@ func marshalMap(m *Map, length int) ([]byte, error) {
15291535 return buf , nil
15301536}
15311537
1532- // MapIterator is the interface defining methods to iterate
1533- // through the content of the target map.
1534- //
1535- // See Map.Iterate.
1536- type MapIterator interface {
1537- // Err returns any encountered error.
1538- //
1539- // The method must be called after Next returns nil.
1540- //
1541- // For key-value maps, returns ErrIterationAborted if
1542- // it wasn't possible to do a full iteration.
1543- Err () error
1544-
1545- // Next decodes the next key and value.
1546- //
1547- // In case of a value-only map (Queue and Stack), the key
1548- // parameter is set to nil in case of no errors.
1549- //
1550- // Returns false if there are no more entries. You must check
1551- // the result of Err afterwards.
1552- Next (keyOut , valueOut interface {}) bool
1553- }
1554-
1555- // keyValueMapIterator iterates a Map defined by key-value pairs.
1556- // (all except Queue and Stack)
1538+ // MapIterator iterates a Map.
15571539//
15581540// See Map.Iterate.
1559- type keyValueMapIterator struct {
1541+ type MapIterator struct {
15601542 target * Map
15611543 // Temporary storage to avoid allocations in Next(). This is any instead
15621544 // of []byte to avoid allocations.
15631545 cursor any
15641546 count , maxEntries uint32
1565- done bool
1566- err error
1567- }
1568-
1569- // keylessMapIterator iterates a Map defined with only values.
1570- // (Queue and Stack)
1571- //
1572- // See Map.Iterate.
1573- type keylessMapIterator struct {
1574- target * Map
1575- err error
1547+ done , drain bool
1548+ // Used in old kernels while Draining a map and LookupAndDelete is not supported
1549+ fallback bool
1550+ err error
15761551}
15771552
1578- // newMapIterator return the correct MapIterator implementation
1579- // based on the underlying map type.
1580- func newMapIterator (target * Map ) MapIterator {
1581- if target .typ .isQueueStack () {
1582- return & keylessMapIterator {
1583- target : target ,
1584- }
1585- }
1586- return & keyValueMapIterator {
1553+ func newMapIterator (target * Map ) * MapIterator {
1554+ return & MapIterator {
15871555 target : target ,
15881556 maxEntries : target .maxEntries ,
15891557 }
15901558}
15911559
1592- // next decodes the next value from a map of type Queue or Stack.
1560+ // Next decodes the next key and value. If the iterator is created
1561+ // through the Map.Drain API, the key and value are also removed.
15931562//
1594- // Returns false if there are no more entries. You must check
1595- // the result of Err afterwards.
1596- func (mi * keylessMapIterator ) next (_ , valueOut interface {}) bool {
1597- // Check whether there was a previous error
1598- if mi .err != nil {
1599- return false
1600- }
1601-
1602- err := mi .target .LookupAndDelete (nil , valueOut )
1603- if errors .Is (err , ErrKeyNotExist ) {
1604- // For these maps this error indicates that the map is empty.
1605- // Return false instead of the error.
1606- return false
1607- }
1608- if err != nil {
1609- // Whether any other error rather than ErrKeyNotExist occurred
1610- mi .err = fmt .Errorf ("look up next value: %w" , err )
1611- return false
1612- }
1613- return true
1614- }
1615-
1616- // next decodes the next key and value from a map with key-value pair
1617- // (all except Queue and Stack).
1563+ // Iterating a hash map from which keys are being deleted is not
1564+ // safe. You may see the same key multiple times. Iteration may
1565+ // also abort with an error, see IsIterationAborted.
1566+ //
1567+ // Iterating a queue/stack map returns ErrIterationAborted, as only
1568+ // Map.Drain is supported.
16181569//
16191570// Returns false if there are no more entries. You must check
16201571// the result of Err afterwards.
1621- func (mi * keyValueMapIterator ) next (keyOut , valueOut interface {}) bool {
1572+ //
1573+ // See Map.Get for further caveats around valueOut.
1574+ func (mi * MapIterator ) Next (keyOut , valueOut interface {}) bool {
16221575 if mi .err != nil || mi .done {
16231576 return false
16241577 }
1578+ if mi .drain {
1579+ return mi .nextDrain (keyOut , valueOut )
1580+ }
1581+ return mi .nextIterate (keyOut , valueOut )
1582+ }
16251583
1626- // For array-like maps NextKey returns nil only after maxEntries
1627- // iterations.
1628- for mi .count <= mi .maxEntries {
1584+ func (mi * MapIterator ) nextIterate (keyOut , valueOut interface {}) bool {
1585+ // For array-like maps NextKey returns nil only after maxEntries iterations.
1586+ // For maps with keySize equal to 0 (Queue/Stack) we return ErrIterationAborted,
1587+ // since NextKey returns an error. In this case, Map.Drain should be used instead.
1588+ for mi .target .keySize != 0 && mi .count <= mi .maxEntries {
16291589 if mi .cursor == nil {
16301590 // Pass nil interface to NextKey to make sure the Map's first key
16311591 // is returned. If we pass an uninitialized []byte instead, it'll see a
@@ -1677,41 +1637,86 @@ func (mi *keyValueMapIterator) next(keyOut, valueOut interface{}) bool {
16771637 return false
16781638}
16791639
1680- // Next decodes the next key and value.
1681- //
1682- // Iterating a hash map from which keys are being deleted is not
1683- // safe. You may see the same key multiple times. Iteration may
1684- // also abort with an error, see IsIterationAborted.
1685- //
1686- // Returns false if there are no more entries. You must check
1687- // the result of Err afterwards.
1688- //
1689- // See Map.Get for further caveats around valueOut.
1690- func (mi * keyValueMapIterator ) Next (keyOut , valueOut interface {}) bool {
1691- return mi .next (keyOut , valueOut )
1692- }
1640+ func (mi * MapIterator ) nextDrain (keyOut , valueOut interface {}) bool {
1641+ // Check for maps without a key (e.g., Queue/Stack). In this case, when there is no
1642+ // more data, ErrKeyNotExist arise, but we gently stop the retrieval with no error.
1643+ if mi .target .keySize == 0 {
1644+ mi .err = mi .target .LookupAndDelete (keyOut , valueOut )
1645+ if errors .Is (mi .err , ErrKeyNotExist ) {
1646+ mi .done = true
1647+ mi .err = nil
1648+ return false
1649+ }
1650+ return mi .err == nil
1651+ }
16931652
1694- // Next decodes the next value in the Queue/Stack, ignoring the keyOut parameter.
1695- //
1696- // Returns false if there are no more entries (ErrKeyNotExist).
1697- // You must check the result of Err afterwards.
1698- func (mi * keylessMapIterator ) Next (keyOut , valueOut interface {}) bool {
1699- return mi .next (keyOut , valueOut )
1653+ // Here we allocate only once data for retrieving the next key in the map.
1654+ if mi .cursor == nil {
1655+ mi .cursor = make ([]byte , mi .target .keySize )
1656+ }
1657+
1658+ // Always retrieve first key in the map. This should ensure that
1659+ // the whole map is traversed, despite concurrent insertion.
1660+ // The expected ordering might differ:
1661+ // - initial keys in map: `a -> b -> c`
1662+ // - call MapIterator.Next and retrieve key `a`
1663+ // - insert key `d` in map
1664+ // - retrieve all the remaining keys `d -> b -> c`
1665+ mi .err = mi .target .NextKey (nil , mi .cursor )
1666+ if errors .Is (mi .err , ErrKeyNotExist ) {
1667+ mi .done = true
1668+ mi .err = nil
1669+ return false
1670+ } else if mi .err != nil {
1671+ mi .err = fmt .Errorf ("get next key: %w" , mi .err )
1672+ return false
1673+ }
1674+
1675+ // falling back to sequential Lookup -> Delete in case LookupAndDelete
1676+ // is not supported (e.g., kernel < 5.14).
1677+ if mi .fallback {
1678+ mi .err = mi .target .Lookup (mi .cursor , valueOut )
1679+ if errors .Is (mi .err , ErrKeyNotExist ) {
1680+ // Same as in MapIterator.nextIterate.
1681+ return mi .nextDrain (keyOut , valueOut )
1682+ } else if mi .err != nil {
1683+ mi .err = fmt .Errorf ("look up next key: %w" , mi .err )
1684+ return false
1685+ }
1686+ mi .err = mi .target .Delete (mi .cursor )
1687+ } else {
1688+ // Check if LookupAndDelete is supported and not invalid args, otherwise fallback
1689+ mi .err = mi .target .LookupAndDelete (mi .cursor , valueOut )
1690+ if mi .err != nil && errors .Is (mi .err , ErrNotSupported ) || errors .Is (mi .err , unix .EINVAL ) {
1691+ mi .fallback = true
1692+ return mi .nextDrain (keyOut , valueOut )
1693+ }
1694+ }
1695+
1696+ if errors .Is (mi .err , ErrKeyNotExist ) {
1697+ // Same as in MapIterator.nextIterate.
1698+ return mi .nextDrain (keyOut , valueOut )
1699+ } else if mi .err != nil {
1700+ mi .err = fmt .Errorf ("delete next key: %w" , mi .err )
1701+ return false
1702+ }
1703+
1704+ buf := mi .cursor .([]byte )
1705+ if ptr , ok := keyOut .(unsafe.Pointer ); ok {
1706+ copy (unsafe .Slice ((* byte )(ptr ), len (buf )), buf )
1707+ } else {
1708+ mi .err = sysenc .Unmarshal (keyOut , buf )
1709+ }
1710+
1711+ return mi .err == nil
17001712}
17011713
17021714// Err returns any encountered error.
17031715//
17041716// The method must be called after Next returns nil.
17051717//
17061718// Returns ErrIterationAborted if it wasn't possible to do a full iteration.
1707- func (mi * keyValueMapIterator ) Err () error {
1708- return mi .err
1709- }
1710-
1711- // Err returns any encountered error.
1712- //
1713- // The method must be called after Next returns nil.
1714- func (mi * keylessMapIterator ) Err () error {
1719+ func (mi * MapIterator ) Err () error {
17151720 return mi .err
17161721}
17171722
0 commit comments