Skip to content

Commit 0f0a5ae

Browse files
committed
Remember multiple patterns with the same id
1 parent bfed084 commit 0f0a5ae

File tree

3 files changed

+77
-16
lines changed

3 files changed

+77
-16
lines changed

pruner/pruner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -247,11 +247,11 @@ func (m *Matcher) MatchesForFields(fields []quamina.Field) ([]quamina.X, error)
247247
// read lock here.
248248
var emitted, filtered int64
249249
for _, x := range xs {
250-
have, err := m.live.Get(x)
250+
have, err := m.live.Contains(x)
251251
if err != nil {
252252
return nil, err
253253
}
254-
if have == "" {
254+
if !have {
255255
filtered++
256256
continue
257257
}

pruner/pruner_test.go

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -293,8 +293,8 @@ func (s *badState) Add(x quamina.X, pattern string) error {
293293
return s.err
294294
}
295295

296-
func (s *badState) Get(x quamina.X) (string, error) {
297-
return "", s.err
296+
func (s *badState) Contains(x quamina.X) (bool, error) {
297+
return false, s.err
298298
}
299299

300300
func (s *badState) Delete(x quamina.X) (bool, error) {
@@ -383,3 +383,47 @@ func TestFlattener(t *testing.T) {
383383
}
384384

385385
}
386+
387+
func TestMultiplePatternsWithSameId(t *testing.T) {
388+
var (
389+
m = NewMatcher(nil)
390+
id interface{} = 1
391+
)
392+
393+
if err := m.AddPattern(id, `{"enjoys":["queso"]}`); err != nil {
394+
t.Fatal(err)
395+
}
396+
397+
if err := m.AddPattern(id, `{"needs":["chips"]}`); err != nil {
398+
t.Fatal(err)
399+
}
400+
401+
if err := m.Rebuild(false); err != nil {
402+
t.Fatal(err)
403+
}
404+
405+
// If we weren't able to remember that both patterns are still
406+
// live, then one of the two checks below will fail. In that
407+
// case, we can't tell which one in advance (because Go map
408+
// iteration order is not specified).
409+
410+
xs, err := m.MatchesForJSONEvent([]byte(`{"enjoys":"queso"}`))
411+
412+
check := func() {
413+
if err != nil {
414+
t.Fatal(err)
415+
}
416+
if len(xs) != id {
417+
t.Fatal(xs)
418+
}
419+
if xs[0] != id {
420+
t.Fatal(xs)
421+
}
422+
}
423+
424+
check()
425+
426+
xs, err = m.MatchesForJSONEvent([]byte(`{"needs":"chips"}`))
427+
428+
check()
429+
}

pruner/state.go

Lines changed: 29 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,51 +11,66 @@ import (
1111
// of live patterns.
1212
type State interface {
1313
// Add adds a new pattern or updates an old pattern.
14+
//
15+
// Note that multiple patterns can be associated with the same
16+
// X.
1417
Add(x quamina.X, pattern string) error
1518

1619
Delete(x quamina.X) (bool, error)
1720

1821
// Iterate calls the given function for every stored pattern.
1922
Iterate(func(x quamina.X, pattern string) error) error
2023

21-
// Get returns the pattern for the given X.
24+
// Contains returns true if x is in the live set; false
25+
// otherwise.
2226
//
2327
// Since a pattern can't be the empty string, that zero value
2428
// indicates no corresponding pattern.
25-
Get(x quamina.X) (string, error)
29+
Contains(x quamina.X) (bool, error)
2630
}
2731

32+
type (
33+
stringSet map[string]nothing
34+
nothing struct{}
35+
)
36+
37+
var na = nothing{}
38+
2839
// MemState is a State that is just a map (with a RWMutex).
2940
//
3041
// Since the State implementation can be provided to the
3142
// application, we're keeping things simple here initially.
3243
type MemState struct {
3344
lock sync.RWMutex
34-
m map[quamina.X]string
45+
m map[quamina.X]stringSet
3546
}
3647

3748
func NewMemState() *MemState {
3849
// Accept initial size as a parameter?
3950
return &MemState{
40-
m: make(map[quamina.X]string),
51+
m: make(map[quamina.X]stringSet),
4152
}
4253
}
4354

4455
var ErrExists = fmt.Errorf("pattern already exists for that X")
4556

4657
func (s *MemState) Add(x quamina.X, pattern string) error {
4758
s.lock.Lock()
48-
// We don't care if the X is already there.
49-
s.m[x] = pattern
59+
ps, have := s.m[x]
60+
if !have {
61+
ps = make(stringSet)
62+
s.m[x] = ps
63+
}
64+
ps[pattern] = na
5065
s.lock.Unlock()
5166
return nil
5267
}
5368

54-
func (s *MemState) Get(x quamina.X) (string, error) {
69+
func (s *MemState) Contains(x quamina.X) (bool, error) {
5570
s.lock.RLock()
56-
p := s.m[x]
71+
_, have := s.m[x]
5772
s.lock.RUnlock()
58-
return p, nil
73+
return have, nil
5974
}
6075

6176
func (s *MemState) Delete(x quamina.X) (bool, error) {
@@ -72,9 +87,11 @@ func (s *MemState) Delete(x quamina.X) (bool, error) {
7287
func (s *MemState) Iterate(f func(x quamina.X, pattern string) error) error {
7388
s.lock.RLock()
7489
var err error
75-
for x, p := range s.m {
76-
if err = f(x, p); err != nil {
77-
break
90+
for x, ps := range s.m {
91+
for p := range ps {
92+
if err = f(x, p); err != nil {
93+
break
94+
}
7895
}
7996
}
8097
s.lock.RUnlock()

0 commit comments

Comments
 (0)