Skip to content

Commit 1152cd2

Browse files
authored
cache per user (#258)
* make cache not anymore shared per user * make cache shareable by user configurable
1 parent def5e4b commit 1152cd2

16 files changed

+297
-48
lines changed

cache/async_cache.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@ type AsyncCache struct {
2020

2121
graceTime time.Duration
2222

23-
MaxPayloadSize config.ByteSize
23+
MaxPayloadSize config.ByteSize
24+
SharedWithAllUsers bool
2425
}
2526

2627
func (c *AsyncCache) Close() error {
@@ -112,5 +113,6 @@ func NewAsyncCache(cfg config.Cache, maxExecutionTime time.Duration) (*AsyncCach
112113
TransactionRegistry: transaction,
113114
graceTime: graceTime,
114115
MaxPayloadSize: maxPayloadSize,
116+
SharedWithAllUsers: cfg.SharedWithAllUsers,
115117
}, nil
116118
}

cache/key.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,10 +52,13 @@ type Key struct {
5252

5353
// QueryParamsHash must contain hashed value of query params
5454
QueryParamsHash uint32
55+
56+
// UserCredentialHash must contain hashed value of username & password
57+
UserCredentialHash uint32
5558
}
5659

5760
// NewKey construct cache key from provided parameters with default version number
58-
func NewKey(query []byte, originParams url.Values, acceptEncoding string, userParamsHash uint32, queryParamsHash uint32) *Key {
61+
func NewKey(query []byte, originParams url.Values, acceptEncoding string, userParamsHash uint32, queryParamsHash uint32, userCredentialHash uint32) *Key {
5962
return &Key{
6063
Query: query,
6164
AcceptEncoding: acceptEncoding,
@@ -70,6 +73,7 @@ func NewKey(query []byte, originParams url.Values, acceptEncoding string, userPa
7073
UserParamsHash: userParamsHash,
7174
Version: Version,
7275
QueryParamsHash: queryParamsHash,
76+
UserCredentialHash: userCredentialHash,
7377
}
7478
}
7579

@@ -79,9 +83,9 @@ func (k *Key) filePath(dir string) string {
7983

8084
// String returns string representation of the key.
8185
func (k *Key) String() string {
82-
s := fmt.Sprintf("V%d; Query=%q; AcceptEncoding=%q; DefaultFormat=%q; Database=%q; Compress=%q; EnableHTTPCompression=%q; Namespace=%q; MaxResultRows=%q; Extremes=%q; ResultOverflowMode=%q; UserParams=%d; QueryParams=%d",
86+
s := fmt.Sprintf("V%d; Query=%q; AcceptEncoding=%q; DefaultFormat=%q; Database=%q; Compress=%q; EnableHTTPCompression=%q; Namespace=%q; MaxResultRows=%q; Extremes=%q; ResultOverflowMode=%q; UserParams=%d; QueryParams=%d; UserCredentialHash=%d",
8387
k.Version, k.Query, k.AcceptEncoding, k.DefaultFormat, k.Database, k.Compress, k.EnableHTTPCompression, k.Namespace,
84-
k.MaxResultRows, k.Extremes, k.ResultOverflowMode, k.UserParamsHash, k.QueryParamsHash)
88+
k.MaxResultRows, k.Extremes, k.ResultOverflowMode, k.UserParamsHash, k.QueryParamsHash, k.UserCredentialHash)
8589
h := sha256.Sum256([]byte(s))
8690

8791
// The first 16 bytes of the hash should be enough

cache/key_test.go

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,15 @@ func TestKeyString(t *testing.T) {
1515
Query: []byte("SELECT 1 FROM system.numbers LIMIT 10"),
1616
Version: 2,
1717
},
18-
expected: "ef4c039ea06ce6fd95f4ffef551ba029",
18+
expected: "f11e8438adeeb325881c9a4da01925b3",
1919
},
2020
{
2121
key: &Key{
2222
Query: []byte("SELECT 1 FROM system.numbers LIMIT 10"),
2323
AcceptEncoding: "gzip",
2424
Version: 2,
2525
},
26-
expected: "cb83c486eea079a87a6e567ba9869111",
26+
expected: "045cbb29a40a81c42378569cf0bc4078",
2727
},
2828
{
2929
key: &Key{
@@ -32,7 +32,7 @@ func TestKeyString(t *testing.T) {
3232
DefaultFormat: "JSON",
3333
Version: 2,
3434
},
35-
expected: "89edc4ac678557d80063d1060b712808",
35+
expected: "186386850c49c60a49dbf7af89c671c9",
3636
},
3737
{
3838
key: &Key{
@@ -42,7 +42,7 @@ func TestKeyString(t *testing.T) {
4242
Database: "foobar",
4343
Version: 2,
4444
},
45-
expected: "120d73469183ace3a31c941cfcc8dc13",
45+
expected: "68f3231d17cad0a3473e63f419e07580",
4646
},
4747
{
4848
key: &Key{
@@ -53,7 +53,7 @@ func TestKeyString(t *testing.T) {
5353
Namespace: "ns123",
5454
Version: 2,
5555
},
56-
expected: "8441149c2cba1503e201aa94cda949f7",
56+
expected: "8f5e765e69df7c24a58f13cdf752ad2f",
5757
},
5858
{
5959
key: &Key{
@@ -65,23 +65,32 @@ func TestKeyString(t *testing.T) {
6565
Namespace: "ns123",
6666
Version: 2,
6767
},
68-
expected: "882a1cfc54f86e75a3ee89757bd33672",
68+
expected: "93a121f03f438ef7969540c78e943e2c",
6969
},
7070
{
7171
key: &Key{
7272
Query: []byte("SELECT * FROM {table_name:Identifier} LIMIT 10"),
7373
QueryParamsHash: 3825709,
7474
Version: 3,
7575
},
76-
expected: "9d7a76630ca453d120a7349c4b6fa23d",
76+
expected: "7edddc7d9db4bc4036dee36893f57cb1",
7777
},
7878
{
7979
key: &Key{
8080
Query: []byte("SELECT * FROM {table_name:Identifier} LIMIT 10"),
8181
QueryParamsHash: 3825710,
8282
Version: 3,
8383
},
84-
expected: "1899cf94d4c5a3dda9575df7d8734e9b",
84+
expected: "68ba76fb53a6fa71ba8fe63dd34a2201",
85+
},
86+
{
87+
key: &Key{
88+
Query: []byte("SELECT * FROM {table_name:Identifier} LIMIT 10"),
89+
QueryParamsHash: 3825710,
90+
Version: 3,
91+
UserCredentialHash: 234324,
92+
},
93+
expected: "c5b58ecb4ff026e62ee846dc63c749d5",
8594
},
8695
}
8796

config/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@ grace_time: <duration>
8282

8383
# Maximum total size of request payload for caching. The default value
8484
# is set to 1 Petabyte.
85+
# The default value set so high is to allow users who do not use response size limitations virtually unlimited cache.
8586
max_payload_size: <byte_size>
87+
88+
# Whether a query cached by a user can be used by another user
89+
shared_with_all_users: <bool> | default = false [optional]
8690
```
8791
8892
### <distributed_cache_config>
@@ -122,6 +126,9 @@ grace_time: <duration>
122126
# is set to 1 Petabyte.
123127
# The default value set so high is to allow users who do not use response size limitations virtually unlimited cache.
124128
max_payload_size: <byte_size>
129+
130+
# Whether a query cached by a user can be used by another user
131+
shared_with_all_users: <bool> | default = false [optional]
125132
```
126133
127134
### <param_groups_config>

config/config.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,9 @@ type Cache struct {
665665

666666
// Maximum total size of request payload for caching
667667
MaxPayloadSize ByteSize `yaml:"max_payload_size,omitempty"`
668+
669+
// Whether a query cached by a user could be used by another user
670+
SharedWithAllUsers bool `yaml:"shared_with_all_users,omitempty"`
668671
}
669672

670673
type FileSystemCacheConfig struct {

config/config_test.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@ var fullConfig = Config{
2121
Dir: "/path/to/longterm/cachedir",
2222
MaxSize: ByteSize(100 << 30),
2323
},
24-
Expire: Duration(time.Hour),
25-
GraceTime: Duration(20 * time.Second),
26-
MaxPayloadSize: ByteSize(100 << 30),
24+
Expire: Duration(time.Hour),
25+
GraceTime: Duration(20 * time.Second),
26+
MaxPayloadSize: ByteSize(100 << 30),
27+
SharedWithAllUsers: false,
2728
},
2829
{
2930
Name: "shortterm",
@@ -32,8 +33,9 @@ var fullConfig = Config{
3233
Dir: "/path/to/shortterm/cachedir",
3334
MaxSize: ByteSize(100 << 20),
3435
},
35-
Expire: Duration(10 * time.Second),
36-
MaxPayloadSize: ByteSize(100 << 20),
36+
Expire: Duration(10 * time.Second),
37+
MaxPayloadSize: ByteSize(100 << 20),
38+
SharedWithAllUsers: true,
3739
},
3840
},
3941
HackMePlease: true,
@@ -851,6 +853,7 @@ caches:
851853
dir: /path/to/shortterm/cachedir
852854
max_size: 104857600
853855
max_payload_size: 104857600
856+
shared_with_all_users: true
854857
param_groups:
855858
- name: cron-job
856859
params:

config/testdata/full.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ caches:
4747
max_size: 100Mb
4848
dir: "/path/to/shortterm/cachedir"
4949
max_payload_size: 100Mb
50+
shared_with_all_users: true
5051
expire: 10s
5152

5253
# Optional network lists, might be used as values for `allowed_networks`.

docs/content/en/configuration/caching.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,15 @@ When Clickhouse responds to the firstly arrived query, existing key is updated a
4848
- if succeeded, as completed
4949
- if failed, as failed along with the exception message prepended with `[concurrent query failed]`.
5050

51-
Transaction is kept for the duration of 2 * grace_time or 2 * max_execution_time, depending if grace time is specified.
51+
Transaction is kept for the duration of 2 * grace_time or 2 * max_execution_time, depending if grace time is specified.
52+
53+
#### Cache shared with all users
54+
Until version 1.19.0, the cache is shared with all users.
55+
It means that if:
56+
- a user X does a query A,
57+
- then the result is cached,
58+
- then a user Y does the same query A
59+
User Y will get the cached response from user X's query.
60+
61+
Since 1.20.0, the cache is specific for each user by default since it's better in terms of security.
62+
It's possible to use the previous behavior by setting the following property of the cache in the config file `shared_with_all_users = true`

0 commit comments

Comments
 (0)