Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 35 additions & 18 deletions server/datasource/etcd/kv/kv_dao.go
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ func (s *Dao) listData(ctx context.Context, project, domain string, options ...d
return listDataByCache(ctx, project, domain, opts, regex)
}

result, err := matchLabelsSearch(ctx, domain, project, regex, opts)
result, _, err := listDataByNoCache(ctx, domain, project, regex, opts)
if err != nil {
openlog.Error("list kv failed: " + err.Error())
return nil, opts, err
Expand Down Expand Up @@ -585,7 +585,7 @@ func listDataByCache(ctx context.Context, project string, domain string, opts da
openlog.Info("using fuzzy cache to search kv not hit")
}

result, err := matchLabelsSearch(ctx, domain, project, regex, opts)
result, onlyLabelFilteredResult, err := listDataByNoCache(ctx, domain, project, regex, opts)
if err != nil {
openlog.Error("list kv failed: " + err.Error())
return nil, opts, err
Expand All @@ -596,41 +596,52 @@ func listDataByCache(ctx context.Context, project string, domain string, opts da
}

kvIdSet := new(sync.Map)
for _, kv := range result.Data {
for _, kv := range onlyLabelFilteredResult.Data {
kvIdSet.Store(kv.ID, struct{}{})
}
cacheKey := kvCache.GetCacheKey(domain, project, opts.Labels)
kvCache.kvIDFuzzyCache.Set(cacheKey, kvIdSet, int64(result.Total))
kvCache.kvIDFuzzyCache.Set(cacheKey, kvIdSet, int64(onlyLabelFilteredResult.Total))
return result, opts, nil
}

func matchLabelsSearch(ctx context.Context, domain, project string, regex *regexp.Regexp, opts datasource.FindOptions) (*model.KVResponse, error) {
// 返回值 onlyLabelFilteredResult 用于调用者设置缓存
func listDataByNoCache(ctx context.Context, domain, project string, regex *regexp.Regexp,
opts datasource.FindOptions) (result, onlyLabelFilteredResult *model.KVResponse, err error) {
openlog.Debug("using labels to search kv")
kvs, _, err := etcdadpt.List(ctx, key.KVList(domain, project))
if err != nil {
return nil, err
return nil, nil, err
}

result = &model.KVResponse{
Data: []*model.KVDoc{},
}
result := &model.KVResponse{
onlyLabelFilteredResult = &model.KVResponse{
Data: []*model.KVDoc{},
}

for _, kv := range kvs {
var doc model.KVDoc
err := json.Unmarshal(kv.Value, &doc)
if err != nil {
openlog.Error("decode to KVList error: " + err.Error())
continue
}
if !filterMatch(&doc, opts, regex) {
if !matchLabels(&doc, opts) {
continue
}

datasource.ClearPart(&doc)
onlyLabelFilteredResult.Data = append(onlyLabelFilteredResult.Data, &doc)
onlyLabelFilteredResult.Total++

if !matchConditions(&doc, opts, regex) {
continue
}
result.Data = append(result.Data, &doc)
result.Total++

}

return result, nil
return result, onlyLabelFilteredResult, nil
}

func IsUniqueFind(opts datasource.FindOptions) bool {
Expand Down Expand Up @@ -682,13 +693,7 @@ func pagingResult(result *model.KVResponse, opts datasource.FindOptions) *model.
return result
}

func filterMatch(doc *model.KVDoc, opts datasource.FindOptions, regex *regexp.Regexp) bool {
if opts.Status != "" && doc.Status != opts.Status {
return false
}
if regex != nil && !regex.MatchString(doc.Key) {
return false
}
func matchLabels(doc *model.KVDoc, opts datasource.FindOptions) bool {
if len(opts.Labels) != 0 {
if opts.ExactLabels && !util.IsEquivalentLabel(opts.Labels, doc.Labels) {
return false
Expand All @@ -697,6 +702,18 @@ func filterMatch(doc *model.KVDoc, opts datasource.FindOptions, regex *regexp.Re
return false
}
}

return true
}

func matchConditions(doc *model.KVDoc, opts datasource.FindOptions, regex *regexp.Regexp) bool {
if opts.Status != "" && doc.Status != opts.Status {
return false
}
if regex != nil && !regex.MatchString(doc.Key) {
return false
}

if opts.LabelFormat != "" && doc.LabelFormat != opts.LabelFormat {
return false
}
Expand Down
103 changes: 103 additions & 0 deletions server/datasource/etcd/kv/kv_dao_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package kv

import (
"context"
"crypto/sha256"
"errors"
"fmt"
"strings"
"testing"
"time"

"github.com/stretchr/testify/assert"

"github.com/go-chassis/cari/db"
"github.com/go-chassis/cari/db/config"
_ "github.com/go-chassis/cari/db/etcd"

"github.com/apache/servicecomb-kie/pkg/model"
"github.com/apache/servicecomb-kie/server/datasource"
)

func init() {
cfg := config.Config{
Kind: "etcd",
URI: "http://127.0.0.1:2379",
PoolSize: 0,
TLSConfig: nil,
SSLEnabled: false,
Timeout: 10 * time.Second,
}
cfg.Kind = "etcd"
cfg.URI = "http://127.0.0.1:2379"
cfg.Timeout = 10 * time.Second
err := db.Init(&cfg)
if err != nil {
panic(err)
}
}

func Test_listDataByNoCache(t *testing.T) {
dao := Dao{}

kvDoc1 := model.KVDoc{
Key: "Test_listDataByNoCache-application.yml",
Value: "test",
Project: "default",
Status: "enabled",
Labels: map[string]string{
"app": "springCloud",
"env": "dev",
},
Domain: "default",
}
kvDoc1.ID = fmt.Sprintf("%x", sha256.Sum256([]byte(strings.Join([]string{
kvDoc1.Domain,
kvDoc1.Project,
kvDoc1.Key,
kvDoc1.LabelFormat,
}, "/"))))
_, err := dao.Create(context.Background(), &kvDoc1)
if err != nil {
assert.True(t, errors.Is(datasource.ErrKVAlreadyExists, err))
}

kvDoc2 := model.KVDoc{
Key: "Test_listDataByNoCache-servicecomb.rateLimiting.test",
Value: "test",
Project: "default",
Status: "enabled",
Labels: map[string]string{
"app": "springCloud",
"env": "dev",
},
Domain: "default",
}
kvDoc2.ID = fmt.Sprintf("%x", sha256.Sum256([]byte(strings.Join([]string{
kvDoc2.Domain,
kvDoc2.Project,
kvDoc2.Key,
kvDoc2.LabelFormat,
}, "/"))))
_, err = dao.Create(context.Background(), &kvDoc2)
if err != nil {
assert.True(t, errors.Is(datasource.ErrKVAlreadyExists, err))
}

opts := datasource.FindOptions{
Key: "beginWith(Test_listDataByNoCache-servicecomb.rateLimiting.)",
Labels: map[string]string{
"app": "springCloud",
"env": "dev",
},
}
re, reErr := toRegex(opts)
assert.Nil(t, reErr)

// onlyLabelFilteredResult 是仅通过label过滤后的值,没有后续的过滤条件,因此其内容应当更多
result, onlyLabelFilteredResult, listErr := listDataByNoCache(context.Background(), "default", "default", re, opts)
assert.Nil(t, listErr)
assert.True(t, onlyLabelFilteredResult.Total >= 2)
assert.True(t, result.Total >= 1)
assert.True(t, onlyLabelFilteredResult.Total > result.Total)
}
Loading