Skip to content

Commit 175ccd8

Browse files
committed
perf(function): optimize changed column comparison
Signed-off-by: Jiayin Ng <ngjaying@gmail.com>
1 parent 2c95a7d commit 175ccd8

2 files changed

Lines changed: 82 additions & 3 deletions

File tree

internal/binder/function/funcs_cols.go

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2022-2024 EMQ Technologies Co., Ltd.
1+
// Copyright 2022-2026 EMQ Technologies Co., Ltd.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -89,7 +89,7 @@ func changedFunc(ctx api.FunctionContext, args []interface{}, keys []string) (Re
8989
if err != nil {
9090
return nil, err
9191
}
92-
if !reflect.DeepEqual(v, lv) {
92+
if !changedValueEqual(v, lv) {
9393
if r == nil {
9494
r = make(ResultCols)
9595
}
@@ -102,3 +102,32 @@ func changedFunc(ctx api.FunctionContext, args []interface{}, keys []string) (Re
102102
}
103103
return r, nil
104104
}
105+
106+
func changedValueEqual(v1, v2 interface{}) bool {
107+
if v1 == nil || v2 == nil {
108+
return v1 == v2
109+
}
110+
switch t1 := v1.(type) {
111+
case string:
112+
if t2, ok := v2.(string); ok {
113+
return t1 == t2
114+
}
115+
case int64:
116+
if t2, ok := v2.(int64); ok {
117+
return t1 == t2
118+
}
119+
case float64:
120+
if t2, ok := v2.(float64); ok {
121+
return t1 == t2
122+
}
123+
case bool:
124+
if t2, ok := v2.(bool); ok {
125+
return t1 == t2
126+
}
127+
case int:
128+
if t2, ok := v2.(int); ok {
129+
return t1 == t2
130+
}
131+
}
132+
return reflect.DeepEqual(v1, v2)
133+
}

internal/binder/function/funcs_cols_test.go

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright 2022 EMQ Technologies Co., Ltd.
1+
// Copyright 2022-2026 EMQ Technologies Co., Ltd.
22
//
33
// Licensed under the Apache License, Version 2.0 (the "License");
44
// you may not use this file except in compliance with the License.
@@ -305,3 +305,53 @@ func TestExecIgnoreNull(t *testing.T) {
305305
}
306306
}
307307
}
308+
309+
func TestChangedValueEqual(t *testing.T) {
310+
tests := []struct {
311+
name string
312+
v1 any
313+
v2 any
314+
want bool
315+
}{
316+
{name: "nil", want: true},
317+
{name: "one nil", v1: int64(1), want: false},
318+
{name: "string", v1: "value", v2: "value", want: true},
319+
{name: "different string", v1: "value", v2: "other", want: false},
320+
{name: "int64", v1: int64(1), v2: int64(1), want: true},
321+
{name: "different numeric types", v1: int64(1), v2: int(1), want: false},
322+
{name: "float64", v1: float64(1.5), v2: float64(1.5), want: true},
323+
{name: "bool", v1: true, v2: true, want: true},
324+
{name: "int", v1: int(1), v2: int(1), want: true},
325+
{name: "slice fallback", v1: []int{1, 2}, v2: []int{1, 2}, want: true},
326+
{name: "map fallback", v1: map[string]any{"a": 1}, v2: map[string]any{"a": 2}, want: false},
327+
}
328+
for _, tt := range tests {
329+
t.Run(tt.name, func(t *testing.T) {
330+
if got := changedValueEqual(tt.v1, tt.v2); got != tt.want {
331+
t.Errorf("changedValueEqual(%v, %v) = %v, want %v", tt.v1, tt.v2, got, tt.want)
332+
}
333+
})
334+
}
335+
}
336+
337+
func BenchmarkChangedColsStable(b *testing.B) {
338+
contextLogger := conf.Log.WithField("rule", "BenchmarkChangedColsStable")
339+
ctx := kctx.WithValue(kctx.Background(), kctx.LoggerKey, contextLogger)
340+
tempStore, err := state.CreateStore("BenchmarkChangedColsStable", def.AtMostOnce)
341+
if err != nil {
342+
b.Fatal(err)
343+
}
344+
fctx := kctx.NewDefaultFuncContext(ctx.WithMeta("BenchmarkChangedColsStable", "changed_cols", tempStore), 1)
345+
args := []any{"p_", true, "same", int64(42), true}
346+
keys := []string{"prefix", "ignore", "string", "integer", "boolean"}
347+
if _, err := changedFunc(fctx, args, keys); err != nil {
348+
b.Fatal(err)
349+
}
350+
b.ReportAllocs()
351+
b.ResetTimer()
352+
for i := 0; i < b.N; i++ {
353+
if _, err := changedFunc(fctx, args, keys); err != nil {
354+
b.Fatal(err)
355+
}
356+
}
357+
}

0 commit comments

Comments
 (0)