From 63c6cf8fc5b2c94aa755c8ef64fb95e9e3be3d23 Mon Sep 17 00:00:00 2001 From: Bryce Kahle Date: Tue, 23 Jul 2024 01:31:17 -0700 Subject: [PATCH] map: do not allocate on lookup when key doesn't exist Looking up a non-existing key in a map currently allocates via fmt.Errorf. Ensure that such a lookup doesn't allocate anymore. Fixes #1516 Signed-off-by: Bryce Kahle --- map.go | 7 +++++++ map_test.go | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/map.go b/map.go index 7412e596c..94421baae 100644 --- a/map.go +++ b/map.go @@ -29,6 +29,10 @@ var ( ErrIterationAborted = errors.New("iteration aborted") ErrMapIncompatible = errors.New("map spec is incompatible with existing map") errMapNoBTFValue = errors.New("map spec does not contain a BTF Value") + + // pre-allocating these errors here since they may get called in hot code paths + // and cause unnecessary memory allocations + errMapLookupKeyNotExist = fmt.Errorf("lookup: %w", sysErrKeyNotExist) ) // MapOptions control loading a map into the kernel. @@ -711,6 +715,9 @@ func (m *Map) lookup(key interface{}, valueOut sys.Pointer, flags MapLookupFlags } if err = sys.MapLookupElem(&attr); err != nil { + if errors.Is(err, unix.ENOENT) { + return errMapLookupKeyNotExist + } return fmt.Errorf("lookup: %w", wrapMapError(err)) } return nil diff --git a/map_test.go b/map_test.go index 39a7ae28d..b8dd30f91 100644 --- a/map_test.go +++ b/map_test.go @@ -269,6 +269,17 @@ func TestMapLookupKeyTooSmall(t *testing.T) { qt.Assert(t, qt.IsNotNil(m.Lookup(uint32(0), &small))) } +func TestMapLookupKeyNotFoundAllocations(t *testing.T) { + m := createArray(t) + defer m.Close() + var key, out uint32 = 3, 0 + + allocs := testing.AllocsPerRun(5, func() { + _ = m.Lookup(&key, &out) + }) + qt.Assert(t, qt.Equals(allocs, float64(0))) +} + func TestBatchAPIMapDelete(t *testing.T) { if err := haveBatchAPI(); err != nil { t.Skipf("batch api not available: %v", err)