@@ -1272,14 +1272,20 @@ func batchCount(keys, values any) (int, error) {
1272
1272
//
1273
1273
// It's not possible to guarantee that all keys in a map will be
1274
1274
// 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 {
1280
1276
return newMapIterator (m )
1281
1277
}
1282
1278
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
+
1283
1289
// Close the Map's underlying file descriptor, which could unload the
1284
1290
// Map from the kernel if it is not pinned or in use by a loaded Program.
1285
1291
func (m * Map ) Close () error {
@@ -1529,103 +1535,57 @@ func marshalMap(m *Map, length int) ([]byte, error) {
1529
1535
return buf , nil
1530
1536
}
1531
1537
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.
1557
1539
//
1558
1540
// See Map.Iterate.
1559
- type keyValueMapIterator struct {
1541
+ type MapIterator struct {
1560
1542
target * Map
1561
1543
// Temporary storage to avoid allocations in Next(). This is any instead
1562
1544
// of []byte to avoid allocations.
1563
1545
cursor any
1564
1546
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
1576
1551
}
1577
1552
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 {
1587
1555
target : target ,
1588
1556
maxEntries : target .maxEntries ,
1589
1557
}
1590
1558
}
1591
1559
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.
1593
1562
//
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.
1618
1569
//
1619
1570
// Returns false if there are no more entries. You must check
1620
1571
// 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 {
1622
1575
if mi .err != nil || mi .done {
1623
1576
return false
1624
1577
}
1578
+ if mi .drain {
1579
+ return mi .nextDrain (keyOut , valueOut )
1580
+ }
1581
+ return mi .nextIterate (keyOut , valueOut )
1582
+ }
1625
1583
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 {
1629
1589
if mi .cursor == nil {
1630
1590
// Pass nil interface to NextKey to make sure the Map's first key
1631
1591
// is returned. If we pass an uninitialized []byte instead, it'll see a
@@ -1677,41 +1637,91 @@ func (mi *keyValueMapIterator) next(keyOut, valueOut interface{}) bool {
1677
1637
return false
1678
1638
}
1679
1639
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
+ } else if mi .err != nil {
1650
+ return false
1651
+ }
1652
+ mi .count ++
1653
+ return true
1654
+ }
1693
1655
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 )
1656
+ // Here we allocate only once data for retrieving the next key in the map.
1657
+ if mi .cursor == nil {
1658
+ mi .cursor = make ([]byte , mi .target .keySize )
1659
+ }
1660
+
1661
+ // Always retrieve first key in the map. This should ensure that
1662
+ // the whole map is traversed, despite concurrent insertion.
1663
+ // The expected ordering might differ:
1664
+ // - initial keys in map: `a -> b -> c`
1665
+ // - call MapIterator.Next and retrieve key `a`
1666
+ // - insert key `d` in map
1667
+ // - retrieve all the remaining keys `d -> b -> c`
1668
+ mi .err = mi .target .NextKey (nil , mi .cursor )
1669
+ if errors .Is (mi .err , ErrKeyNotExist ) {
1670
+ mi .done = true
1671
+ mi .err = nil
1672
+ return false
1673
+ } else if mi .err != nil {
1674
+ mi .err = fmt .Errorf ("get next key: %w" , mi .err )
1675
+ return false
1676
+ }
1677
+
1678
+ // falling back to sequential Lookup -> Delete in case LookupAndDelete
1679
+ // is not supported (e.g., kernel < 5.14).
1680
+ if mi .fallback {
1681
+ mi .count ++
1682
+ mi .err = mi .target .Lookup (mi .cursor , valueOut )
1683
+ if errors .Is (mi .err , ErrKeyNotExist ) {
1684
+ // Same as in MapIterator.nextIterate.
1685
+ return mi .nextDrain (keyOut , valueOut )
1686
+ } else if mi .err != nil {
1687
+ mi .err = fmt .Errorf ("look up next key: %w" , mi .err )
1688
+ return false
1689
+ }
1690
+ mi .err = mi .target .Delete (mi .cursor )
1691
+ } else {
1692
+ // Check if LookupAndDelete is supported and not invalid args, otherwise fallback
1693
+ mi .err = mi .target .LookupAndDelete (mi .cursor , valueOut )
1694
+ if mi .err != nil && errors .Is (mi .err , ErrNotSupported ) || errors .Is (mi .err , unix .EINVAL ) {
1695
+ mi .fallback = true
1696
+ return mi .nextDrain (keyOut , valueOut )
1697
+ }
1698
+ mi .count ++
1699
+ }
1700
+
1701
+ if errors .Is (mi .err , ErrKeyNotExist ) {
1702
+ // Same as in MapIterator.nextIterate.
1703
+ return mi .nextDrain (keyOut , valueOut )
1704
+ } else if mi .err != nil {
1705
+ mi .err = fmt .Errorf ("delete next key: %w" , mi .err )
1706
+ return false
1707
+ }
1708
+
1709
+ buf := mi .cursor .([]byte )
1710
+ if ptr , ok := keyOut .(unsafe.Pointer ); ok {
1711
+ copy (unsafe .Slice ((* byte )(ptr ), len (buf )), buf )
1712
+ } else {
1713
+ mi .err = sysenc .Unmarshal (keyOut , buf )
1714
+ }
1715
+
1716
+ return mi .err == nil
1700
1717
}
1701
1718
1702
1719
// Err returns any encountered error.
1703
1720
//
1704
1721
// The method must be called after Next returns nil.
1705
1722
//
1706
1723
// 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 {
1724
+ func (mi * MapIterator ) Err () error {
1715
1725
return mi .err
1716
1726
}
1717
1727
0 commit comments