Skip to content

Commit

Permalink
fix tenant glob match bug
Browse files Browse the repository at this point in the history
Signed-off-by: Yi Jin <yi.jin@databricks.com>
  • Loading branch information
jnyi committed Feb 14, 2025
1 parent 034daed commit 7913f6d
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 22 deletions.
55 changes: 33 additions & 22 deletions pkg/receive/hashring.go
Original file line number Diff line number Diff line change
Expand Up @@ -244,13 +244,42 @@ func (c ketamaHashring) GetN(tenant string, ts *prompb.TimeSeries, n uint64) (En
return c.endpoints[endpointIndex], nil
}

type tenantSet map[string]tenantMatcher

func (t tenantSet) match(tenant string) (bool, error) {
// Fast path for the common case of direct match.
if mt, ok := t[tenant]; ok && isExactMatcher(mt) {
return true, nil
} else {
for tenantPattern, matcherType := range t {
switch matcherType {
case TenantMatcherGlob:
matches, err := filepath.Match(tenantPattern, tenant)
if err != nil {
return false, fmt.Errorf("error matching tenant pattern %s (tenant %s): %w", tenantPattern, tenant, err)
}
if matches {
return true, nil
}
case TenantMatcherTypeExact:
// Already checked above, skipping.
fallthrough
default:
continue
}

}
}
return false, nil
}

// multiHashring represents a set of hashrings.
// Which hashring to use for a tenant is determined
// by the tenants field of the hashring configuration.
type multiHashring struct {
cache map[string]Hashring
hashrings []Hashring
tenantSets []map[string]tenantMatcher
tenantSets []tenantSet

// We need a mutex to guard concurrent access
// to the cache map, as this is both written to
Expand Down Expand Up @@ -283,28 +312,10 @@ func (m *multiHashring) GetN(tenant string, ts *prompb.TimeSeries, n uint64) (En
if t == nil {
found = true
} else {
// Fast path for the common case of direct match.
if mt, ok := t[tenant]; ok && isExactMatcher(mt) {
found = true
} else {
for tenantPattern, matcherType := range t {
switch matcherType {
case TenantMatcherGlob:
matches, err := filepath.Match(tenantPattern, tenant)
if err != nil {
return Endpoint{}, fmt.Errorf("error matching tenant pattern %s (tenant %s): %w", tenantPattern, tenant, err)
}
found = matches
case TenantMatcherTypeExact:
// Already checked above, skipping.
fallthrough
default:
continue
}

}
var err error
if found, err = t.match(tenant); err != nil {
return Endpoint{}, err
}

}
if found {
m.mu.Lock()
Expand Down
57 changes: 57 additions & 0 deletions pkg/receive/hashring_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,63 @@ func TestHashringGet(t *testing.T) {
"node6": {},
},
},
{
name: "glob hashring match",
cfg: []HashringConfig{
{
Endpoints: []Endpoint{{Address: "node1"}, {Address: "node2"}, {Address: "node3"}},
Tenants: []string{"prefix*"},
TenantMatcherType: TenantMatcherGlob,
},
{
Endpoints: []Endpoint{{Address: "node4"}, {Address: "node5"}, {Address: "node6"}},
},
},
nodes: map[string]struct{}{
"node1": {},
"node2": {},
"node3": {},
},
tenant: "prefix-1",
},
{
name: "glob hashring not match",
cfg: []HashringConfig{
{
Endpoints: []Endpoint{{Address: "node1"}, {Address: "node2"}, {Address: "node3"}},
Tenants: []string{"prefix*"},
TenantMatcherType: TenantMatcherGlob,
},
{
Endpoints: []Endpoint{{Address: "node4"}, {Address: "node5"}, {Address: "node6"}},
},
},
nodes: map[string]struct{}{
"node4": {},
"node5": {},
"node6": {},
},
tenant: "suffix-1",
},
{
name: "glob hashring multiple matches",
cfg: []HashringConfig{
{
Endpoints: []Endpoint{{Address: "node1"}, {Address: "node2"}, {Address: "node3"}},
Tenants: []string{"t1-*", "t2", "t3-*"},
TenantMatcherType: TenantMatcherGlob,
},
{
Endpoints: []Endpoint{{Address: "node4"}, {Address: "node5"}, {Address: "node6"}},
},
},
nodes: map[string]struct{}{
"node1": {},
"node2": {},
"node3": {},
},
tenant: "t2",
},
} {
hs, err := NewMultiHashring(AlgorithmHashmod, 3, tc.cfg)
require.NoError(t, err)
Expand Down

0 comments on commit 7913f6d

Please sign in to comment.