diff --git a/Makefile b/Makefile index 4655d807864..ff970f1776b 100644 --- a/Makefile +++ b/Makefile @@ -138,5 +138,6 @@ clear-swarm-data: test: go test ./pkg/query-service/app/metrics/... + go test ./pkg/query-service/cache/... go test ./pkg/query-service/app/... go test ./pkg/query-service/converter/... \ No newline at end of file diff --git a/go.mod b/go.mod index cccc9716150..e18f39b14fd 100644 --- a/go.mod +++ b/go.mod @@ -7,6 +7,8 @@ require ( github.com/SigNoz/govaluate v0.0.0-20220522085550-d19c08c206cb github.com/coreos/go-oidc/v3 v3.4.0 github.com/go-kit/log v0.2.1 + github.com/go-redis/redis/v8 v8.11.5 + github.com/go-redis/redismock/v8 v8.11.5 github.com/google/uuid v1.3.0 github.com/gorilla/handlers v1.5.1 github.com/gorilla/mux v1.8.0 @@ -20,6 +22,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 github.com/oklog/oklog v0.3.2 github.com/open-telemetry/opamp-go v0.5.0 + github.com/patrickmn/go-cache v2.1.0+incompatible github.com/pkg/errors v0.9.1 github.com/posthog/posthog-go v0.0.0-20220817142604-0b0bbf0f9c0f github.com/prometheus/common v0.39.0 @@ -69,6 +72,7 @@ require ( github.com/armon/go-metrics v0.4.0 // indirect github.com/beevik/etree v1.1.0 // indirect github.com/cespare/xxhash/v2 v2.2.0 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect github.com/form3tech-oss/jwt-go v3.2.5+incompatible // indirect github.com/gorilla/websocket v1.5.0 // indirect github.com/jonboulle/clockwork v0.2.2 // indirect @@ -128,7 +132,7 @@ require ( go.opentelemetry.io/otel v1.11.2 // indirect go.opentelemetry.io/otel/trace v1.11.2 // indirect go.uber.org/atomic v1.10.0 // indirect - go.uber.org/multierr v1.9.0 // indirect + go.uber.org/multierr v1.9.0 golang.org/x/crypto v0.1.0 golang.org/x/net v0.4.0 golang.org/x/oauth2 v0.3.0 diff --git a/go.sum b/go.sum index 19ef4f20ff2..9ae992d9149 100644 --- a/go.sum +++ b/go.sum @@ -125,6 +125,7 @@ github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= @@ -154,6 +155,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/dennwc/varint v1.0.0 h1:kGNFFSSw8ToIy3obO/kKr8U9GZYUAxQEVuix4zfDWzE= github.com/dennwc/varint v1.0.0/go.mod h1:hnItb35rvZvJrbTALZtY/iQfDs48JKRG1RPpgziApxA= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/digitalocean/godo v1.91.1 h1:1o30VOCu1aC6488qBd0SkQiBeAZ35RSTvLwCA1pQMhc= github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68= github.com/docker/docker v20.10.22+incompatible h1:6jX4yB+NtcbldT90k7vBSaWJDB3i+zkVJT9BEK8kQkk= @@ -185,6 +188,7 @@ github.com/felixge/httpsnoop v1.0.3/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSw github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.5+incompatible h1:/l4kBbb4/vGSsdtB5nUe8L7B9mImVMaBPw9L/0TBHU8= github.com/form3tech-oss/jwt-go v3.2.5+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= @@ -218,11 +222,16 @@ github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUe github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= github.com/go-openapi/swag v0.22.1 h1:S6xFhsBKAtvfphnJwRzeCh3OEGsTL/crXdEetSxLs0Q= github.com/go-openapi/swag v0.22.1/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= +github.com/go-redis/redismock/v8 v8.11.5 h1:RJFIiua58hrBrSpXhnGX3on79AU3S271H4ZhRI1wyVo= +github.com/go-redis/redismock/v8 v8.11.5/go.mod h1:UaAU9dEe1C+eGr+FHV5prCWIt0hafyPWbGMEWE0UWdA= github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 h1:JVrqSeQfdhYRFk24TvhTZWU0q8lfCojxZQFi3Ou7+uY= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0/go.mod h1:fyg7847qk6SyHyPtNmDHnmrv/HOrqktSC+C9fM+CJOE= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= @@ -303,6 +312,7 @@ github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLe github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210122040257-d980be63207e/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210226084205-cbba55b83ad5/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= +github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE= @@ -386,6 +396,7 @@ github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKe github.com/hetznercloud/hcloud-go v1.38.0 h1:K6Pd/mMdcLfBhvwG39qyAaacp4pCS3dKa8gChmLKxLg= github.com/hjson/hjson-go/v4 v4.0.0 h1:wlm6IYYqHjOdXH1gHev4VoXCaW20HdQAGCxdOEEg2cs= github.com/hjson/hjson-go/v4 v4.0.0/go.mod h1:KaYt3bTw3zhBjYqnXkYywcYctk0A2nxeEFTse3rH13E= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU= @@ -497,6 +508,9 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f h1:KUppIJq7/+SVif2QVs3tOP0zanoHgBEVAwHxUSIzRqU= github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk= +github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= +github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE= +github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= github.com/oklog/oklog v0.3.2 h1:wVfs8F+in6nTBMkA7CbRw+zZMIB7nNM825cM1wuzoTk= github.com/oklog/oklog v0.3.2/go.mod h1:FCV+B7mhrz4o+ueLpx+KqkyXRGMWOYEvfiXtdGtbWGs= github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= @@ -504,6 +518,17 @@ github.com/oklog/run v1.1.0 h1:GEenZ1cK0+q0+wsJew9qUg/DyD8k3JzYsZAi5gYi2mA= github.com/oklog/run v1.1.0/go.mod h1:sVPdnTZT1zYwAJeCMu2Th4T21pA3FPOQRfWjQlk7DVU= github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk= +github.com/onsi/ginkgo v1.16.4/go.mod h1:dX+/inL/fNMqNlz0e9LfyB9TswhZpCVdJM/Z6Vvnwo0= +github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE= +github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU= +github.com/onsi/ginkgo/v2 v2.0.0/go.mod h1:vw5CSIxN1JObi/U8gcbwft7ZxR2dgaR70JSE3/PpL4c= +github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY= +github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo= +github.com/onsi/gomega v1.17.0/go.mod h1:HnhC7FXeEQY45zxNK3PPoIUhzk/80Xly9PcubAlGdZY= +github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs= +github.com/onsi/gomega v1.23.0 h1:/oxKu9c2HVap+F3PfKort2Hw5DEU+HGlW8n+tguWsys= github.com/open-telemetry/opamp-go v0.5.0 h1:2YFbb6G4qBkq3yTRdVb5Nfz9hKHW/ldUyex352e1J7g= github.com/open-telemetry/opamp-go v0.5.0/go.mod h1:IMdeuHGVc5CjKSu5/oNV0o+UmiXuahoHvoZ4GOmAI9M= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= @@ -513,6 +538,8 @@ github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYr github.com/ovh/go-ovh v1.3.0 h1:mvZaddk4E4kLcXhzb+cxBsMPYp2pHqiQpWYkInsuZPQ= github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= github.com/pascaldekloe/goe v0.1.0/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc= +github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= +github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/paulmach/orb v0.8.0 h1:W5XAt5yNPNnhaMNEf0xNSkBMJ1LzOzdk2MRlB6EN0Vs= github.com/paulmach/orb v0.8.0/go.mod h1:FWRlTgl88VI1RBx/MkrwWDRhQ96ctqMCh8boXhmqB/A= github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY= @@ -723,6 +750,7 @@ golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91 golang.org/x/mod v0.7.0 h1:LapD9S96VoQRhi/GrNTqeBJFrUjs5UHCAtTlgwA5oZA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -747,6 +775,7 @@ golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/ golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA= @@ -761,6 +790,7 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8= +golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= @@ -816,6 +846,7 @@ golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190129075346-302c3dd5f1cc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -829,12 +860,14 @@ golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191008105621-543471e840be/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -860,6 +893,7 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -967,6 +1001,7 @@ golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82u golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= @@ -1171,6 +1206,7 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/ini.v1 v1.42.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= @@ -1180,6 +1216,8 @@ gopkg.in/segmentio/analytics-go.v3 v3.1.0/go.mod h1:4QqqlTlSSpVlWA9/9nDcPw+FkM2y gopkg.in/square/go-jose.v2 v2.3.1/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/pkg/query-service/cache/cache.go b/pkg/query-service/cache/cache.go new file mode 100644 index 00000000000..f62fe115a52 --- /dev/null +++ b/pkg/query-service/cache/cache.go @@ -0,0 +1,69 @@ +package cache + +import ( + "os" + "time" + + inmemory "go.signoz.io/signoz/pkg/query-service/cache/inmemory" + redis "go.signoz.io/signoz/pkg/query-service/cache/redis" + "go.signoz.io/signoz/pkg/query-service/cache/status" + v3 "go.signoz.io/signoz/pkg/query-service/model/v3" + "gopkg.in/yaml.v2" +) + +type Options struct { + Name string `yaml:"-"` + Provider string `yaml:"provider"` + Redis *redis.Options `yaml:"redis,omitempty"` + InMemory *inmemory.Options `yaml:"inmemory,omitempty"` +} + +// Cache is the interface for the storage backend +type Cache interface { + Connect() error + Store(cacheKey string, data []byte, ttl time.Duration) error + Retrieve(cacheKey string, allowExpired bool) ([]byte, status.RetrieveStatus, error) + SetTTL(cacheKey string, ttl time.Duration) + Remove(cacheKey string) + BulkRemove(cacheKeys []string) + Close() error +} + +// KeyGenerator is the interface for the key generator +// The key generator is used to generate the cache keys for the cache entries +type KeyGenerator interface { + // GenerateKeys generates the cache keys for the given query range params + // The keys are returned as a map where the key is the query name and the value is the cache key + GenerateKeys(*v3.QueryRangeParamsV3) map[string]string +} + +// LoadFromYAMLCacheConfig loads the cache options from the given YAML config bytes +func LoadFromYAMLCacheConfig(yamlConfig []byte) (*Options, error) { + var options Options + err := yaml.Unmarshal(yamlConfig, &options) + if err != nil { + return nil, err + } + return &options, nil +} + +// LoadFromYAMLCacheConfigFile loads the cache options from the given YAML config file +func LoadFromYAMLCacheConfigFile(configFile string) (*Options, error) { + bytes, err := os.ReadFile(configFile) + if err != nil { + return nil, err + } + return LoadFromYAMLCacheConfig(bytes) +} + +// NewCache creates a new cache based on the given options +func NewCache(options *Options) Cache { + switch options.Provider { + case "redis": + return redis.New(options.Redis) + case "inmemory": + return inmemory.New(options.InMemory) + default: + return nil + } +} diff --git a/pkg/query-service/cache/cache_test.go b/pkg/query-service/cache/cache_test.go new file mode 100644 index 00000000000..ea176af459e --- /dev/null +++ b/pkg/query-service/cache/cache_test.go @@ -0,0 +1,52 @@ +package cache + +import "testing" + +func TestNewCacheUnKnownProvider(t *testing.T) { + c := NewCache(&Options{ + Name: "test", + Provider: "unknown", + }) + + if c != nil { + t.Fatalf("expected nil, got %v", c) + } +} + +func TestNewCacheInMemory(t *testing.T) { + c := NewCache(&Options{ + Name: "test", + Provider: "inmemory", + }) + + if c == nil { + t.Fatalf("expected non-nil, got nil") + } +} + +func TestNewCacheRedis(t *testing.T) { + c := NewCache(&Options{ + Name: "test", + Provider: "redis", + }) + + if c == nil { + t.Fatalf("expected non-nil, got nil") + } +} + +func TestLoadFromYAMLCacheConfig(t *testing.T) { + _, err := LoadFromYAMLCacheConfig([]byte(` +provider: inmemory +`)) + if err != nil { + t.Fatalf("unexpected error: %s", err) + } +} + +func TestLoadFromYAMLCacheConfigFile(t *testing.T) { + _, err := LoadFromYAMLCacheConfigFile("testdata/cache.yaml") + if err != nil { + t.Fatalf("unexpected error: %s", err) + } +} diff --git a/pkg/query-service/cache/inmemory/cache.go b/pkg/query-service/cache/inmemory/cache.go new file mode 100644 index 00000000000..af8f200d087 --- /dev/null +++ b/pkg/query-service/cache/inmemory/cache.go @@ -0,0 +1,73 @@ +package inmemory + +import ( + "time" + + go_cache "github.com/patrickmn/go-cache" + "go.signoz.io/signoz/pkg/query-service/cache/status" +) + +// cache implements the Cache interface +type cache struct { + cc *go_cache.Cache +} + +// New creates a new in-memory cache +func New(opts *Options) *cache { + if opts == nil { + opts = defaultOptions() + } + return &cache{cc: go_cache.New(opts.TTL, opts.CleanupInterval)} +} + +// Connect does nothing +func (c *cache) Connect() error { + return nil +} + +// Store stores the data in the cache +func (c *cache) Store(cacheKey string, data []byte, ttl time.Duration) error { + c.cc.Set(cacheKey, data, ttl) + return nil +} + +// Retrieve retrieves the data from the cache +func (c *cache) Retrieve(cacheKey string, allowExpired bool) ([]byte, status.RetrieveStatus, error) { + data, found := c.cc.Get(cacheKey) + if !found { + return nil, status.RetrieveStatusKeyMiss, nil + } + + return data.([]byte), status.RetrieveStatusHit, nil +} + +// SetTTL sets the TTL for the cache entry +func (c *cache) SetTTL(cacheKey string, ttl time.Duration) { + item, found := c.cc.Get(cacheKey) + if !found { + return + } + c.cc.Replace(cacheKey, item, ttl) +} + +// Remove removes the cache entry +func (c *cache) Remove(cacheKey string) { + c.cc.Delete(cacheKey) +} + +// BulkRemove removes the cache entries +func (c *cache) BulkRemove(cacheKeys []string) { + for _, cacheKey := range cacheKeys { + c.cc.Delete(cacheKey) + } +} + +// Close does nothing +func (c *cache) Close() error { + return nil +} + +// Configuration returns the cache configuration +func (c *cache) Configuration() *Options { + return nil +} diff --git a/pkg/query-service/cache/inmemory/cache_test.go b/pkg/query-service/cache/inmemory/cache_test.go new file mode 100644 index 00000000000..cfd350fe9c3 --- /dev/null +++ b/pkg/query-service/cache/inmemory/cache_test.go @@ -0,0 +1,102 @@ +package inmemory + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" + "go.signoz.io/signoz/pkg/query-service/cache/status" +) + +// TestNew tests the New function +func TestNew(t *testing.T) { + opts := &Options{ + TTL: 10 * time.Second, + CleanupInterval: 10 * time.Second, + } + c := New(opts) + assert.NotNil(t, c) + assert.NotNil(t, c.cc) +} + +// TestConnect tests the Connect function +func TestConnect(t *testing.T) { + c := New(nil) + assert.NoError(t, c.Connect()) +} + +// TestStore tests the Store function +func TestStore(t *testing.T) { + c := New(nil) + assert.NoError(t, c.Store("key", []byte("value"), 10*time.Second)) +} + +// TestRetrieve tests the Retrieve function +func TestRetrieve(t *testing.T) { + c := New(nil) + assert.NoError(t, c.Store("key", []byte("value"), 10*time.Second)) + data, retrieveStatus, err := c.Retrieve("key", false) + assert.NoError(t, err) + assert.Equal(t, retrieveStatus, status.RetrieveStatusHit) + assert.Equal(t, data, []byte("value")) +} + +// TestSetTTL tests the SetTTL function +func TestSetTTL(t *testing.T) { + c := New(&Options{TTL: 10 * time.Second, CleanupInterval: 1 * time.Second}) + assert.NoError(t, c.Store("key", []byte("value"), 2*time.Second)) + time.Sleep(3 * time.Second) + data, retrieveStatus, err := c.Retrieve("key", false) + assert.NoError(t, err) + assert.Equal(t, retrieveStatus, status.RetrieveStatusKeyMiss) + assert.Nil(t, data) + + assert.NoError(t, c.Store("key", []byte("value"), 2*time.Second)) + c.SetTTL("key", 4*time.Second) + time.Sleep(3 * time.Second) + data, retrieveStatus, err = c.Retrieve("key", false) + assert.NoError(t, err) + assert.Equal(t, retrieveStatus, status.RetrieveStatusHit) + assert.Equal(t, data, []byte("value")) +} + +// TestRemove tests the Remove function +func TestRemove(t *testing.T) { + c := New(nil) + assert.NoError(t, c.Store("key", []byte("value"), 10*time.Second)) + c.Remove("key") + + data, retrieveStatus, err := c.Retrieve("key", false) + assert.NoError(t, err) + assert.Equal(t, retrieveStatus, status.RetrieveStatusKeyMiss) + assert.Nil(t, data) +} + +// TestBulkRemove tests the BulkRemove function +func TestBulkRemove(t *testing.T) { + c := New(nil) + assert.NoError(t, c.Store("key1", []byte("value"), 10*time.Second)) + assert.NoError(t, c.Store("key2", []byte("value"), 10*time.Second)) + c.BulkRemove([]string{"key1", "key2"}) + + data, retrieveStatus, err := c.Retrieve("key1", false) + assert.NoError(t, err) + assert.Equal(t, retrieveStatus, status.RetrieveStatusKeyMiss) + assert.Nil(t, data) + + data, retrieveStatus, err = c.Retrieve("key2", false) + assert.NoError(t, err) + assert.Equal(t, retrieveStatus, status.RetrieveStatusKeyMiss) + assert.Nil(t, data) +} + +// TestCache tests the cache +func TestCache(t *testing.T) { + c := New(nil) + assert.NoError(t, c.Store("key", []byte("value"), 10*time.Second)) + data, retrieveStatus, err := c.Retrieve("key", false) + assert.NoError(t, err) + assert.Equal(t, retrieveStatus, status.RetrieveStatusHit) + assert.Equal(t, data, []byte("value")) + c.Remove("key") +} diff --git a/pkg/query-service/cache/inmemory/options.go b/pkg/query-service/cache/inmemory/options.go new file mode 100644 index 00000000000..89c2885e3d4 --- /dev/null +++ b/pkg/query-service/cache/inmemory/options.go @@ -0,0 +1,23 @@ +package inmemory + +import ( + "time" + + go_cache "github.com/patrickmn/go-cache" +) + +const ( + defaultTTL = go_cache.NoExpiration + defaultCleanupInterval = 1 * time.Minute +) + +// Options holds the options for the in-memory cache +type Options struct { + // TTL is the time to live for the cache entries + TTL time.Duration `yaml:"ttl,omitempty"` + CleanupInterval time.Duration `yaml:"cleanupInterval,omitempty"` +} + +func defaultOptions() *Options { + return &Options{TTL: defaultTTL, CleanupInterval: defaultCleanupInterval} +} diff --git a/pkg/query-service/cache/redis/options.go b/pkg/query-service/cache/redis/options.go new file mode 100644 index 00000000000..8fc5cffa76c --- /dev/null +++ b/pkg/query-service/cache/redis/options.go @@ -0,0 +1,24 @@ +package redis + +const ( + defaultHost = "localhost" + defaultPort = 6379 + defaultPassword = "" + defaultDB = 0 +) + +type Options struct { + Host string `yaml:"host,omitempty"` + Port int `yaml:"port,omitempty"` + Password string `yaml:"password,omitempty"` + DB int `yaml:"db,omitempty"` +} + +func defaultOptions() *Options { + return &Options{ + Host: defaultHost, + Port: defaultPort, + Password: defaultPassword, + DB: defaultDB, + } +} diff --git a/pkg/query-service/cache/redis/redis.go b/pkg/query-service/cache/redis/redis.go new file mode 100644 index 00000000000..22278c52edc --- /dev/null +++ b/pkg/query-service/cache/redis/redis.go @@ -0,0 +1,126 @@ +package redis + +import ( + "context" + "fmt" + "time" + + "github.com/go-redis/redis/v8" + "go.signoz.io/signoz/pkg/query-service/cache/status" + "go.uber.org/zap" +) + +type cache struct { + client *redis.Client + opts *Options +} + +// New creates a new cache +func New(opts *Options) *cache { + if opts == nil { + opts = defaultOptions() + } + return &cache{opts: opts} +} + +// WithClient creates a new cache with the given client +func WithClient(client *redis.Client) *cache { + return &cache{client: client} +} + +// Connect connects to the redis server +func (c *cache) Connect() error { + c.client = redis.NewClient(&redis.Options{ + Addr: fmt.Sprintf("%s:%d", c.opts.Host, c.opts.Port), + Password: c.opts.Password, + DB: c.opts.DB, + }) + return nil +} + +// Store stores the data in the cache +func (c *cache) Store(cacheKey string, data []byte, ttl time.Duration) error { + return c.client.Set(context.Background(), cacheKey, data, ttl).Err() +} + +// Retrieve retrieves the data from the cache +func (c *cache) Retrieve(cacheKey string, allowExpired bool) ([]byte, status.RetrieveStatus, error) { + data, err := c.client.Get(context.Background(), cacheKey).Bytes() + if err != nil { + if err == redis.Nil { + return nil, status.RetrieveStatusKeyMiss, nil + } + return nil, status.RetrieveStatusError, err + } + return data, status.RetrieveStatusHit, nil +} + +// SetTTL sets the TTL for the cache entry +func (c *cache) SetTTL(cacheKey string, ttl time.Duration) { + err := c.client.Expire(context.Background(), cacheKey, ttl).Err() + if err != nil { + zap.S().Error("error setting TTL for cache key", zap.String("cacheKey", cacheKey), zap.Duration("ttl", ttl), zap.Error(err)) + } +} + +// Remove removes the cache entry +func (c *cache) Remove(cacheKey string) { + err := c.client.Del(context.Background(), cacheKey).Err() + if err != nil { + zap.S().Error("error deleting cache key", zap.String("cacheKey", cacheKey), zap.Error(err)) + } +} + +// BulkRemove removes the cache entries +func (c *cache) BulkRemove(cacheKeys []string) { + for _, cacheKey := range cacheKeys { + c.Remove(cacheKey) + } +} + +// Close closes the connection to the redis server +func (c *cache) Close() error { + return c.client.Close() +} + +// Ping pings the redis server +func (c *cache) Ping() error { + return c.client.Ping(context.Background()).Err() +} + +// GetClient returns the redis client +func (c *cache) GetClient() *redis.Client { + return c.client +} + +// GetOptions returns the options +func (c *cache) GetOptions() *Options { + return c.opts +} + +// GetTTL returns the TTL for the cache entry +func (c *cache) GetTTL(cacheKey string) time.Duration { + ttl, err := c.client.TTL(context.Background(), cacheKey).Result() + if err != nil { + zap.S().Error("error getting TTL for cache key", zap.String("cacheKey", cacheKey), zap.Error(err)) + } + return ttl +} + +// GetKeys returns the keys matching the pattern +func (c *cache) GetKeys(pattern string) ([]string, error) { + return c.client.Keys(context.Background(), pattern).Result() +} + +// GetKeysWithTTL returns the keys matching the pattern with their TTL +func (c *cache) GetKeysWithTTL(pattern string) (map[string]time.Duration, error) { + keys, err := c.GetKeys(pattern) + if err != nil { + return nil, err + } + result := make(map[string]time.Duration) + for _, key := range keys { + result[key] = c.GetTTL(key) + } + return result, nil +} diff --git a/pkg/query-service/cache/redis/redis_test.go b/pkg/query-service/cache/redis/redis_test.go new file mode 100644 index 00000000000..41d96836c80 --- /dev/null +++ b/pkg/query-service/cache/redis/redis_test.go @@ -0,0 +1,92 @@ +package redis + +import ( + "testing" + "time" + + "github.com/go-redis/redismock/v8" + "go.signoz.io/signoz/pkg/query-service/cache/status" +) + +func TestStore(t *testing.T) { + db, mock := redismock.NewClientMock() + c := WithClient(db) + + mock.ExpectSet("key", []byte("value"), 10*time.Second).RedisNil() + c.Store("key", []byte("value"), 10*time.Second) + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} + +func TestRetrieve(t *testing.T) { + db, mock := redismock.NewClientMock() + c := WithClient(db) + mock.ExpectSet("key", []byte("value"), 10*time.Second).RedisNil() + c.Store("key", []byte("value"), 10*time.Second) + + mock.ExpectGet("key").SetVal("value") + data, retrieveStatus, err := c.Retrieve("key", false) + if err != nil { + t.Errorf("unexpected error: %s", err) + } + + if retrieveStatus != status.RetrieveStatusHit { + t.Errorf("expected status %d, got %d", status.RetrieveStatusHit, retrieveStatus) + } + + if string(data) != "value" { + t.Errorf("expected value %s, got %s", "value", string(data)) + } + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} + +func TestSetTTL(t *testing.T) { + db, mock := redismock.NewClientMock() + c := WithClient(db) + mock.ExpectSet("key", []byte("value"), 10*time.Second).RedisNil() + c.Store("key", []byte("value"), 10*time.Second) + + mock.ExpectExpire("key", 4*time.Second).RedisNil() + c.SetTTL("key", 4*time.Second) + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} + +func TestRemove(t *testing.T) { + db, mock := redismock.NewClientMock() + c := WithClient(db) + mock.ExpectSet("key", []byte("value"), 10*time.Second).RedisNil() + c.Store("key", []byte("value"), 10*time.Second) + + mock.ExpectDel("key").RedisNil() + c.Remove("key") + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} + +func TestBulkRemove(t *testing.T) { + db, mock := redismock.NewClientMock() + c := WithClient(db) + mock.ExpectSet("key", []byte("value"), 10*time.Second).RedisNil() + c.Store("key", []byte("value"), 10*time.Second) + + mock.ExpectSet("key2", []byte("value2"), 10*time.Second).RedisNil() + c.Store("key2", []byte("value2"), 10*time.Second) + + mock.ExpectDel("key").RedisNil() + mock.ExpectDel("key2").RedisNil() + c.BulkRemove([]string{"key", "key2"}) + + if err := mock.ExpectationsWereMet(); err != nil { + t.Errorf("there were unfulfilled expectations: %s", err) + } +} diff --git a/pkg/query-service/cache/status/status.go b/pkg/query-service/cache/status/status.go new file mode 100644 index 00000000000..ea7f2233430 --- /dev/null +++ b/pkg/query-service/cache/status/status.go @@ -0,0 +1,33 @@ +package status + +// RetrieveStatus defines the possible status of a cache lookup +type RetrieveStatus int + +const ( + RetrieveStatusHit = RetrieveStatus(iota) + RetrieveStatusPartialHit + RetrieveStatusRangeMiss + RetrieveStatusKeyMiss + RetrieveStatusRevalidated + + RetrieveStatusError +) + +func (s RetrieveStatus) String() string { + switch s { + case RetrieveStatusHit: + return "hit" + case RetrieveStatusPartialHit: + return "partial hit" + case RetrieveStatusRangeMiss: + return "range miss" + case RetrieveStatusKeyMiss: + return "key miss" + case RetrieveStatusRevalidated: + return "revalidated" + case RetrieveStatusError: + return "error" + default: + return "unknown" + } +} diff --git a/pkg/query-service/cache/status/status_test.go b/pkg/query-service/cache/status/status_test.go new file mode 100644 index 00000000000..59f7a7bf156 --- /dev/null +++ b/pkg/query-service/cache/status/status_test.go @@ -0,0 +1,43 @@ +package status + +import ( + "testing" +) + +func TestRetrieveStatusString(t *testing.T) { + tests := []struct { + status RetrieveStatus + want string + }{ + { + status: RetrieveStatusHit, + want: "hit", + }, + { + status: RetrieveStatusPartialHit, + want: "partial hit", + }, + { + status: RetrieveStatusRangeMiss, + want: "range miss", + }, + { + status: RetrieveStatusKeyMiss, + want: "key miss", + }, + { + status: RetrieveStatusRevalidated, + want: "revalidated", + }, + { + status: RetrieveStatusError, + want: "error", + }, + } + + for _, tt := range tests { + if got := tt.status.String(); got != tt.want { + t.Errorf("RetrieveStatus.String() = %v, want %v", got, tt.want) + } + } +} diff --git a/pkg/query-service/cache/testdata/cache.yaml b/pkg/query-service/cache/testdata/cache.yaml new file mode 100644 index 00000000000..14c60f0836b --- /dev/null +++ b/pkg/query-service/cache/testdata/cache.yaml @@ -0,0 +1,2 @@ +name: test +provider: inmemory