Skip to content

Commit

Permalink
SNOW-895536: Limit query context cache
Browse files Browse the repository at this point in the history
  • Loading branch information
sfc-gh-pfus committed Aug 30, 2023
1 parent 6e38e3c commit d455387
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 4 deletions.
2 changes: 1 addition & 1 deletion connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ func (sc *snowflakeConn) exec(
return nil, err
}

sc.queryContextCache.add(data.Data.QueryContext.Entries...)
sc.queryContextCache.add(sc, data.Data.QueryContext.Entries...)

// handle PUT/GET commands
if isFileTransfer(query) {
Expand Down
37 changes: 34 additions & 3 deletions htap.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,14 @@
package gosnowflake

import "sync"
import (
"strconv"
"sync"
)

const (
queryContextCacheSizeParamName = "QUERY_CONTEXT_CACHE_SIZE"
defaultQueryContextCacheSize = 5
)

type queryContextEntry struct {
ID int `json:"id"`
Expand All @@ -19,8 +27,31 @@ func (qcc *queryContextCache) init() *queryContextCache {
return qcc
}

func (qcc *queryContextCache) add(qces ...queryContextEntry) {
func (qcc *queryContextCache) add(sc *snowflakeConn, qces ...queryContextEntry) {
qcc.mutex.Lock()
defer qcc.mutex.Unlock()
qcc.entries = append(qcc.entries, qces...)
if len(qces) == 0 {
qcc.prune(0)
} else {
qcc.entries = append(qcc.entries, qces...)
qcc.prune(qcc.getQueryContextCacheSize(sc))
}
}

func (qcc *queryContextCache) prune(size int) {
if len(qcc.entries) > size {
qcc.entries = qcc.entries[0:size]
}
}

func (qcc *queryContextCache) getQueryContextCacheSize(sc *snowflakeConn) int {
if sizeStr, ok := sc.cfg.Params[queryContextCacheSizeParamName]; ok {
size, err := strconv.Atoi(*sizeStr)
if err != nil {
logger.Warnf("cannot parse %v as int as query context cache size: %v", sizeStr, err)
} else {
return size
}
}
return defaultQueryContextCacheSize
}
104 changes: 104 additions & 0 deletions htap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -147,3 +147,107 @@ func containsNewEntries(entriesAfter []queryContextEntry, entriesBefore []queryC

return false
}

func TestPruneBySessionValue(t *testing.T) {
qce1 := queryContextEntry{1, 1, 1, nil}
qce2 := queryContextEntry{2, 2, 2, nil}
qce3 := queryContextEntry{3, 3, 3, nil}

testcases := []struct {
size string
expected []queryContextEntry
}{
{
size: "1",
expected: []queryContextEntry{qce1},
},
{
size: "2",
expected: []queryContextEntry{qce1, qce2},
},
{
size: "3",
expected: []queryContextEntry{qce1, qce2, qce3},
},
{
size: "4",
expected: []queryContextEntry{qce1, qce2, qce3},
},
}

for _, tc := range testcases {
t.Run(tc.size, func(t *testing.T) {
sc := &snowflakeConn{
cfg: &Config{
Params: map[string]*string{
queryContextCacheSizeParamName: &tc.size,
},
},
}

qcc := (&queryContextCache{}).init()

qcc.add(sc, qce1)
qcc.add(sc, qce2)
qcc.add(sc, qce3)

if !reflect.DeepEqual(qcc.entries, tc.expected) {
t.Errorf("unexpected cache entries. expected: %v, got: %v", tc.expected, qcc.entries)
}
})
}
}

func TestPruneByDefaultValue(t *testing.T) {
qce1 := queryContextEntry{1, 1, 1, nil}
qce2 := queryContextEntry{2, 2, 2, nil}
qce3 := queryContextEntry{3, 3, 3, nil}
qce4 := queryContextEntry{4, 4, 4, nil}
qce5 := queryContextEntry{5, 5, 5, nil}
qce6 := queryContextEntry{6, 6, 6, nil}

sc := &snowflakeConn{
cfg: &Config{
Params: map[string]*string{},
},
}

qcc := (&queryContextCache{}).init()
qcc.add(sc, qce1)
qcc.add(sc, qce2)
qcc.add(sc, qce3)
qcc.add(sc, qce4)
qcc.add(sc, qce5)

if len(qcc.entries) != 5 {
t.Fatalf("Expected 5 elements, got: %v", len(qcc.entries))
}

qcc.add(sc, qce6)
if len(qcc.entries) != 5 {
t.Fatalf("Expected 5 elements, got: %v", len(qcc.entries))
}
}

func TestNoQcesClearsCache(t *testing.T) {
qce1 := queryContextEntry{1, 1, 1, nil}

sc := &snowflakeConn{
cfg: &Config{
Params: map[string]*string{},
},
}

qcc := (&queryContextCache{}).init()
qcc.add(sc, qce1)

if len(qcc.entries) != 1 {
t.Fatalf("improperly inited cache")
}

qcc.add(sc)

if len(qcc.entries) != 0 {
t.Errorf("after adding empty context list cache should be cleared")
}
}

0 comments on commit d455387

Please sign in to comment.