From 6ffd8655a9d4e3f9e0d8d3dae5c8149517f43216 Mon Sep 17 00:00:00 2001 From: rabbitstack Date: Thu, 14 May 2026 18:27:16 +0200 Subject: [PATCH] refactor(filter): Simplify cache valuer Use a flat map for both caching and as a sentinel for checking if the value is already cached. --- pkg/filter/fields/id.go | 75 --------------------------------------- pkg/filter/valuer.go | 27 +++----------- pkg/filter/valuer_test.go | 19 ---------- 3 files changed, 4 insertions(+), 117 deletions(-) delete mode 100644 pkg/filter/fields/id.go diff --git a/pkg/filter/fields/id.go b/pkg/filter/fields/id.go deleted file mode 100644 index 68e086dd8..000000000 --- a/pkg/filter/fields/id.go +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2016-present by Nedim Sabic Sabic - * https://www.fibratus.io - * All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package fields - -const MaxFieldID int16 = 23 - -// ID returns the filter index used by the valuer cache. -// Note that not all fields need to provide the identifier. -func (f Field) ID() int16 { - switch f { - case EvtName: - return 0 - case EvtPID: - return 1 - case RegistryPath: - return 2 - case FilePath: - return 3 - case FileExtension: - return 4 - case PsExe: - return 5 - case PsName: - return 6 - case PsPid: - return 7 - case FileOperation: - return 8 - case FileStatus: - return 9 - case RegistryStatus: - return 10 - case ModuleName: - return 11 - case ModulePath: - return 12 - case ModuleSignatureExists, DllSignatureExists: - return 13 - case ModuleSignatureTrusted, DllSignatureTrusted: - return 14 - case ThreadCallstackSummary: - return 15 - case ThreadCallstackModules: - return 16 - case ThreadCallstackSymbols: - return 17 - case PsParentName: - return 18 - case PsSID: - return 19 - case PsCmdline: - return 20 - case PsTokenIntegrityLevel: - return 21 - case PsAccessMaskNames: - return MaxFieldID - 1 - } - return -1 -} diff --git a/pkg/filter/valuer.go b/pkg/filter/valuer.go index 2f5d57f8f..ac483ef9b 100644 --- a/pkg/filter/valuer.go +++ b/pkg/filter/valuer.go @@ -21,20 +21,18 @@ package filter import ( "sync" - "github.com/rabbitstack/fibratus/pkg/filter/fields" "github.com/rabbitstack/fibratus/pkg/filter/ql" ) // ValuerCache caches extracted field values for a single event's lifetime. type ValuerCache struct { - slots [fields.MaxFieldID]any valuer ql.MapValuer } var valuerCachePool = sync.Pool{ New: func() any { return &ValuerCache{ - valuer: make(ql.MapValuer, 8), // pre-allocate buckets + valuer: make(ql.MapValuer), } }, } @@ -44,30 +42,13 @@ func AcquireValuerCache() *ValuerCache { } func (c *ValuerCache) Release() { - c.slots = [fields.MaxFieldID]any{} clear(c.valuer) valuerCachePool.Put(c) } func (c *ValuerCache) populateValuer(f Field, extract func() any) { - id := f.Name.ID() - if id == -1 { - // if the field doesn't allow fast id lookup - // extract the value and cache inside valuer - n := f.String() - if _, ok := c.valuer[n]; !ok { - c.valuer[n] = extract() - } - return - } - - // field value is already cached, skip - v := c.slots[id] - if v != nil { - return + n := f.String() + if _, ok := c.valuer[n]; !ok { + c.valuer[n] = extract() } - - // extract the value and cache - v = extract() - c.slots[id], c.valuer[f.String()] = v, v } diff --git a/pkg/filter/valuer_test.go b/pkg/filter/valuer_test.go index c857eaf38..aa1e0ed92 100644 --- a/pkg/filter/valuer_test.go +++ b/pkg/filter/valuer_test.go @@ -75,25 +75,6 @@ func TestValuerCacheDistinctFields(t *testing.T) { assert.Equal(t, `C:\Windows\System32\cmd.exe`, c.valuer[f1.String()]) } -func TestValuerCacheNilValue(t *testing.T) { - c := AcquireValuerCache() - defer c.Release() - - calls := 0 - c.populateValuer(Field{Name: fields.PsName, Value: fields.PsName.String()}, func() any { - calls++ - return nil - }) - - // nil is not cached in slots (v != nil check), so extract will be called again - c.populateValuer(Field{Name: fields.PsName, Value: fields.PsName.String()}, func() any { - calls++ - return nil - }) - - assert.Equal(t, 2, calls, "nil values are not cached, extract is called on every invocation") -} - func TestValuerCacheReset(t *testing.T) { c := AcquireValuerCache()