diff --git a/enterprise/suppress-user/internal/repository/badgerdb.go b/enterprise/suppress-user/internal/repository/badgerdb.go new file mode 100644 index 00000000000..46186aae552 --- /dev/null +++ b/enterprise/suppress-user/internal/repository/badgerdb.go @@ -0,0 +1,210 @@ +package repository + +import ( + "errors" + "fmt" + "io" + "strings" + "sync" + "time" + + badger "github.com/dgraph-io/badger/v3" + "github.com/dgraph-io/badger/v3/options" + "github.com/rudderlabs/rudder-server/utils/logger" +) + +const tokenKey = "__token__" + +type badgerRepository struct { + restoreLock sync.RWMutex + log logger.Logger + path string + db *badger.DB + maxGoroutines int + started bool + done chan struct{} +} + +func NewBadgerRepository(path string, log logger.Logger) Repository { + b := &badgerRepository{ + log: log, + path: path, + maxGoroutines: 1, + } + return b +} + +func (b *badgerRepository) GetToken() ([]byte, error) { + b.restoreLock.RLock() + defer b.restoreLock.RUnlock() + if b.db == nil { + return nil, ErrNotInitialized + } + var token []byte + err := b.db.View(func(txn *badger.Txn) error { + item, err := txn.Get([]byte(tokenKey)) + if err != nil { + return err + } + err = item.Value(func(val []byte) error { + token = val + return nil + }) + return err + }) + if err != nil && !errors.Is(err, badger.ErrKeyNotFound) { + return nil, err + } + return token, nil +} + +func (b *badgerRepository) Suppress(userID, workspaceID, sourceID string) (bool, error) { + b.restoreLock.RLock() + defer b.restoreLock.RUnlock() + if b.db == nil { + return false, ErrNotInitialized + } + key := fmt.Sprintf("%s:%s", workspaceID, userID) + var value []string + + err := b.db.View(func(txn *badger.Txn) error { + item, err := txn.Get([]byte(key)) + if err != nil { + return err + } + err = item.Value(func(val []byte) error { + if len(val) > 0 { + value = strings.Split(string(val), ",") + } + return nil + }) + return err + }) + if err != nil { + if err == badger.ErrKeyNotFound { + return false, nil + } + return false, err + } + if len(value) == 0 { + return true, nil + } + for _, v := range value { + if v == sourceID { + return true, nil + } + } + return false, err +} + +func (b *badgerRepository) Add(suppressions []Suppression, token []byte) error { + b.restoreLock.RLock() + defer b.restoreLock.RUnlock() + if b.db == nil { + return ErrNotInitialized + } + wb := b.db.NewWriteBatch() + defer wb.Cancel() + for i := range suppressions { + suppression := suppressions[i] + key := fmt.Sprintf("%s:%s", suppression.WorkspaceID, suppression.UserID) + var err error + if suppression.Canceled { + err = wb.Delete([]byte(key)) + } else { + err = wb.Set([]byte(key), []byte(strings.Join(suppression.SourceIDs, ","))) + } + if err != nil { + return err + } + } + if err := wb.Set([]byte(tokenKey), token); err != nil { + return err + } + err := wb.Flush() + return err +} + +func (b *badgerRepository) Start() error { + if b.started { + return nil + } + b.done = make(chan struct{}) + opts := badger. + DefaultOptions(b.path). + WithLogger(blogger{b.log}). + WithCompression(options.None). + WithNumMemtables(1). + WithMemTableSize(16 << 20). + WithNumLevelZeroTables(2). + WithNumLevelZeroTablesStall(4). + WithIndexCacheSize(10 << 20). + WithNumGoroutines(b.maxGoroutines) + var err error + b.db, err = badger.Open(opts) + if err != nil { + return err + } + b.started = true + go func() { + ticker := time.NewTicker(5 * time.Minute) + defer ticker.Stop() + for { + select { + case <-b.done: + return + case <-ticker.C: + } + again: + err := b.db.RunValueLogGC(0.7) + if err == nil { + goto again + } + } + }() + return nil +} + +func (b *badgerRepository) Stop() error { + if b.db != nil { + close(b.done) + err := b.db.Close() + b.started = false + b.db = nil + return err + } + return nil +} + +func (b *badgerRepository) Backup(w io.Writer) error { + b.restoreLock.RLock() + defer b.restoreLock.RUnlock() + _, err := b.db.Backup(w, 0) + return err +} + +func (b *badgerRepository) Restore(r io.Reader) (err error) { + b.restoreLock.Lock() + defer b.restoreLock.Unlock() + defer func() { + if r := recover(); r != nil { + err = fmt.Errorf("panic during restore: %v", r) + } + }() + return b.db.Load(r, b.maxGoroutines) +} + +func NewBadgerTestHelper(r Repository) (*BadgerTestHelper, error) { + if br, ok := r.(*badgerRepository); ok { + return &BadgerTestHelper{br}, nil + } + return nil, fmt.Errorf("repository is not a badger repository") +} + +type BadgerTestHelper struct { + b *badgerRepository +} + +func (h *BadgerTestHelper) StopBadgerDB() error { + return h.b.Stop() +} diff --git a/enterprise/suppress-user/internal/repository/badgerdb_backup_bench_test.go b/enterprise/suppress-user/internal/repository/badgerdb_backup_bench_test.go new file mode 100644 index 00000000000..66a77bc6727 --- /dev/null +++ b/enterprise/suppress-user/internal/repository/badgerdb_backup_bench_test.go @@ -0,0 +1,72 @@ +package repository_test + +import ( + "bufio" + "fmt" + "os" + "path" + "runtime" + "runtime/debug" + "testing" + "time" + + "github.com/rudderlabs/rudder-server/enterprise/suppress-user/internal/repository" + "github.com/rudderlabs/rudder-server/utils/logger" + "github.com/stretchr/testify/require" +) + +// BenchmarkBackupRestore benchmarks the backup and restore time of the badger repository +// after seeding it with a very large number of suppressions. +func BenchmarkBackupRestore(b *testing.B) { + debug.SetMemoryLimit(1 << 30) // 1GB + totalSuppressions := 50_000_000 + batchSize := 5000 + backupFilename := path.Join(b.TempDir(), "backup.badger") + + b.Run("backup", func(b *testing.B) { + repo := repository.NewBadgerRepository(path.Join(b.TempDir(), "repo-1"), logger.NOP) + require.NoError(b, repo.Start()) + defer func() { _ = repo.Stop() }() + for i := 0; i < totalSuppressions/batchSize; i++ { + suppressions := generateSuppressions(i*batchSize/2, batchSize/2) + token := []byte(fmt.Sprintf("token%d", i)) + require.NoError(b, repo.Add(suppressions, token)) + } + debug.FreeOSMemory() + var m runtime.MemStats + runtime.ReadMemStats(&m) + b.Logf("before backup memory: %d MB", m.Sys/1024/1024) + + start := time.Now() + f, err := os.Create(backupFilename) + w := bufio.NewWriter(f) + defer func() { _ = f.Close() }() + require.NoError(b, err) + require.NoError(b, repo.Backup(w)) + dur := time.Since(start) + fileInfo, err := f.Stat() + require.NoError(b, err) + b.ReportMetric(float64(fileInfo.Size()/1024/1024), "filesize(MB)") + b.ReportMetric(dur.Seconds(), "duration(sec)") + collectMemStats(b) + }) + + b.Run("restore", func(b *testing.B) { + repo := repository.NewBadgerRepository(path.Join(b.TempDir(), "repo-2"), logger.NOP) + require.NoError(b, repo.Start()) + defer func() { _ = repo.Stop() }() + + start := time.Now() + f, err := os.Open(backupFilename) + require.NoError(b, err) + r := bufio.NewReader(f) + fileInfo, err := f.Stat() + require.NoError(b, err) + b.ReportMetric(float64(fileInfo.Size()/1024/1024), "filesize(MB)") + + defer func() { _ = f.Close() }() + require.NoError(b, repo.Restore(r)) + b.ReportMetric(time.Since(start).Seconds(), "duration(sec)") + collectMemStats(b) + }) +} diff --git a/enterprise/suppress-user/internal/repository/badgerdb_bench_test.go b/enterprise/suppress-user/internal/repository/badgerdb_bench_test.go new file mode 100644 index 00000000000..3ff42134aaf --- /dev/null +++ b/enterprise/suppress-user/internal/repository/badgerdb_bench_test.go @@ -0,0 +1,97 @@ +package repository_test + +import ( + "fmt" + "math/rand" + "runtime" + "runtime/debug" + "testing" + "time" + + "github.com/rudderlabs/rudder-server/enterprise/suppress-user/internal/repository" + "github.com/rudderlabs/rudder-server/utils/logger" + "github.com/stretchr/testify/require" +) + +func BenchmarkAddAndSuppress(b *testing.B) { + debug.SetMemoryLimit(1 << 30) // 1GB + totalSuppressions := 20_000_000 + totalReads := 10_000 + batchSize := 5000 + + runAddSuppressionsBenchmark := func(b *testing.B, repo repository.Repository, batchSize, totalSuppressions int) { + require.NoError(b, repo.Start()) + var totalTime time.Duration + var totalAddSuppressions int + for i := 0; i < totalSuppressions/batchSize; i++ { + suppressions1 := generateSuppressions(i*batchSize/2, batchSize/2) + suppressions2 := generateSuppressions(i*batchSize/2, batchSize/2) + token := []byte(fmt.Sprintf("token%d", i)) + start := time.Now() + require.NoError(b, repo.Add(suppressions1, token)) + require.NoError(b, repo.Add(suppressions2, token)) + totalTime += time.Since(start) + totalAddSuppressions += batchSize + } + b.ReportMetric(float64(totalSuppressions)/totalTime.Seconds(), "suppressions/s(add)") + } + + runSuppressBenchmark := func(b *testing.B, repo repository.Repository, totalSuppressions, totalReads int) { + require.NoError(b, repo.Start()) + var totalTime time.Duration + for i := 0; i < totalReads; i++ { + start := time.Now() + idx := randomInt(totalSuppressions) + _, err := repo.Suppress(fmt.Sprintf("user%d", idx), fmt.Sprintf("workspace%d", idx), fmt.Sprintf("source%d", idx)) + require.NoError(b, err) + totalTime += time.Since(start) + } + b.ReportMetric(float64(totalSuppressions)/totalTime.Seconds(), "suppressions/s(read)") + } + + runAddAndSuppressBenchmark := func(b *testing.B, repo repository.Repository, totalSuppressions, batchSize, totalReads int) { + runAddSuppressionsBenchmark(b, repo, batchSize, totalSuppressions) + runSuppressBenchmark(b, repo, totalSuppressions, totalReads) + collectMemStats(b) + } + b.Run("badger", func(b *testing.B) { + repo := repository.NewBadgerRepository(b.TempDir(), logger.NOP) + defer func() { _ = repo.Stop() }() + runAddAndSuppressBenchmark(b, repo, totalSuppressions, batchSize, totalReads) + }) + + b.Run("memory", func(b *testing.B) { + repo := repository.NewMemoryRepository(logger.NOP) + defer func() { _ = repo.Stop() }() + runAddAndSuppressBenchmark(b, repo, totalSuppressions, batchSize, totalReads) + }) +} + +func generateSuppressions(startFrom, batchSize int) []repository.Suppression { + var res []repository.Suppression + + for i := startFrom; i < startFrom+batchSize; i++ { + res = append(res, repository.Suppression{ + Canceled: randomInt(2) == 0, + WorkspaceID: fmt.Sprintf("workspace%d", i), + UserID: fmt.Sprintf("user%d", i), + SourceIDs: []string{fmt.Sprintf("source%d", i), "otherSource", "anotherSource"}, + }) + } + return res +} + +func init() { + rand.Seed(time.Now().UnixNano()) +} + +func randomInt(lt int) int { + return rand.Int() % lt +} + +func collectMemStats(b *testing.B) { + debug.FreeOSMemory() + var m runtime.MemStats + runtime.ReadMemStats(&m) + b.ReportMetric(float64(m.Sys/1024/1024), "memory(MB)") +} diff --git a/enterprise/suppress-user/internal/repository/badgerdb_test.go b/enterprise/suppress-user/internal/repository/badgerdb_test.go new file mode 100644 index 00000000000..34dbb88afe2 --- /dev/null +++ b/enterprise/suppress-user/internal/repository/badgerdb_test.go @@ -0,0 +1,190 @@ +package repository_test + +import ( + "bytes" + "testing" + + "github.com/rudderlabs/rudder-server/enterprise/suppress-user/internal/repository" + "github.com/rudderlabs/rudder-server/utils/logger" + "github.com/stretchr/testify/require" +) + +func TestBadgerRepository(t *testing.T) { + path := t.TempDir() + token := []byte("token") + repo := repository.NewBadgerRepository(path, logger.NewLogger().Child("test")) + + t.Run("stopping an non-initialized (started) repository", func(t *testing.T) { + require.NoError(t, repo.Stop(), "it should be able to stop a non-initialized repository without an error") + }) + + t.Run("trying to use a non-initialized (started) repository", func(t *testing.T) { + err := repo.Add([]repository.Suppression{ + { + WorkspaceID: "workspace1", + UserID: "user1", + SourceIDs: []string{}, + }, + { + WorkspaceID: "workspace2", + UserID: "user2", + SourceIDs: []string{"source1"}, + }, + }, token) + require.Error(t, err, "it should return an error when trying to add a suppression to a non-initialized repository") + require.ErrorIs(t, repository.ErrNotInitialized, err) + + _, err = repo.GetToken() + require.Error(t, err, "it should return an error when trying to get the token from a non-initialized repository") + require.ErrorIs(t, repository.ErrNotInitialized, err) + + _, err = repo.Suppress("user2", "workspace2", "source2") + require.Error(t, err, "it should return an error when trying to suppress a user from a non-initialized repository") + require.ErrorIs(t, repository.ErrNotInitialized, err) + }) + + t.Run("starting a repository", func(t *testing.T) { + require.NoError(t, repo.Start(), "it should be able to start the repository without an error") + }) + defer func() { _ = repo.Stop() }() + + t.Run("starting a repository twice", func(t *testing.T) { + require.NoError(t, repo.Start(), "it shouldn't fail when attempting to start the repository again") + }) + + t.Run("get the token before setting anything", func(t *testing.T) { + rtoken, err := repo.GetToken() + require.NoError(t, err) + require.Nil(t, rtoken, "it should return nil when trying to get the token before setting it") + }) + + t.Run("adding suppressions", func(t *testing.T) { + err := repo.Add([]repository.Suppression{ + { + WorkspaceID: "workspace1", + UserID: "user1", + SourceIDs: []string{}, + }, + { + WorkspaceID: "workspace2", + UserID: "user2", + SourceIDs: []string{"source1"}, + }, + }, token) + require.NoError(t, err, "it should be able to add some suppressions without an error") + }) + + t.Run("get token after setting it", func(t *testing.T) { + rtoken, err := repo.GetToken() + require.NoError(t, err) + require.Equal(t, token, rtoken, "it should return the token that was previously set") + }) + + t.Run("wildcard suppression", func(t *testing.T) { + suppressed, err := repo.Suppress("user1", "workspace1", "source1") + require.NoError(t, err) + require.True(t, suppressed, "it should return true when trying to suppress a user that is suppressed by a wildcard suppression") + + suppressed, err = repo.Suppress("user1", "workspace1", "source2") + require.NoError(t, err) + require.True(t, suppressed, "it should return true when trying to suppress a user that is suppressed by a wildcard suppression") + }) + + t.Run("exact suppression", func(t *testing.T) { + suppressed, err := repo.Suppress("user2", "workspace2", "source1") + require.NoError(t, err) + require.True(t, suppressed, "it should return true when trying to suppress a user that is suppressed by an exact suppression") + }) + + t.Run("non matching key", func(t *testing.T) { + suppressed, err := repo.Suppress("user3", "workspace3", "source2") + require.NoError(t, err) + require.False(t, suppressed, "it should return false when trying to suppress a user that is not suppressed") + }) + + t.Run("non matching suppression", func(t *testing.T) { + suppressed, err := repo.Suppress("user2", "workspace2", "source2") + require.NoError(t, err) + require.False(t, suppressed, "it should return false when trying to suppress a user that is suppressed for a different sourceID") + }) + + t.Run("trying to start a second repository using the same path", func(t *testing.T) { + repo2 := repository.NewBadgerRepository(path, logger.NewLogger().Child("test")) + err := repo2.Start() + require.Error(t, err, "it should return an error when trying to start a second repository using the same path") + }) + + t.Run("canceling a suppression", func(t *testing.T) { + suppressed, err := repo.Suppress("user1", "workspace1", "source1") + require.NoError(t, err) + require.True(t, suppressed, "it should return true when trying to suppress a user that is suppressed by a wildcard suppression") + + token2 := []byte("token2") + err = repo.Add([]repository.Suppression{ + { + WorkspaceID: "workspace1", + Canceled: true, + UserID: "user1", + SourceIDs: []string{}, + }, + }, token2) + require.NoError(t, err) + rtoken, err := repo.GetToken() + require.NoError(t, err) + require.Equal(t, token2, rtoken) + + suppressed, err = repo.Suppress("user1", "workspace1", "source1") + require.NoError(t, err) + require.False(t, suppressed, "it should return false when trying to suppress a user that was suppressed by a wildcard suppression after the suppression has been canceled") + }) + + t.Run("stopping and starting the repository again", func(t *testing.T) { + token, err := repo.GetToken() + require.NoError(t, err) + require.NoError(t, repo.Stop(), "it should be able to stop the repository without an error") + require.NoError(t, repo.Start(), "it should be able to start the repository again without an error") + + suppressed, err := repo.Suppress("user2", "workspace2", "source1") + require.NoError(t, err) + require.True(t, suppressed, "it should retain the existing suppressions after stopping and starting the repository again") + + rtoken, err := repo.GetToken() + require.NoError(t, err) + require.Equal(t, token, rtoken, "it should retain the existing token after stopping and starting the repository again") + }) + + backup := []byte{} + buffer := bytes.NewBuffer(backup) + t.Run("backup", func(t *testing.T) { + require.NoError(t, repo.Backup(buffer), "it should be able to backup the repository without an error") + }) + + t.Run("restore", func(t *testing.T) { + require.NoError(t, repo.Restore(buffer), "it should be able to restore the repository without an error") + }) + + t.Run("try to restore invalid data", func(t *testing.T) { + r := bytes.NewBuffer([]byte("invalid data")) + require.Error(t, repo.Restore(r), "it should return an error when trying to restore invalid data") + }) + + t.Run("badgerdb errors", func(t *testing.T) { + th, err := repository.NewBadgerTestHelper(repo) + require.NoError(t, err) + require.NoError(t, th.StopBadgerDB(), "it should be able to stop the badgerdb instance without an error") + + _, err = repo.Suppress("user1", "workspace1", "") + require.Error(t, err) + + _, err = repo.GetToken() + require.Error(t, err) + + require.Error(t, repo.Add([]repository.Suppression{}, []byte(""))) + + require.Error(t, repo.Add([]repository.Suppression{{ + WorkspaceID: "workspace1", + UserID: "user1", + SourceIDs: []string{}, + }}, []byte("token"))) + }) +} diff --git a/enterprise/suppress-user/internal/repository/memory.go b/enterprise/suppress-user/internal/repository/memory.go new file mode 100644 index 00000000000..5483970aecd --- /dev/null +++ b/enterprise/suppress-user/internal/repository/memory.go @@ -0,0 +1,85 @@ +package repository + +import ( + "io" + "sync" + + "github.com/rudderlabs/rudder-server/utils/logger" +) + +type memRepository struct { + log logger.Logger + token []byte + suppressionsMu sync.RWMutex + suppressions map[string]map[string][]string +} + +func NewMemoryRepository(log logger.Logger) Repository { + m := &memRepository{ + log: log, + suppressions: make(map[string]map[string][]string), + } + return m +} + +func (m *memRepository) GetToken() ([]byte, error) { + return m.token, nil +} + +func (m *memRepository) Suppress(userID, workspaceID, sourceID string) (bool, error) { + m.suppressionsMu.RLock() + defer m.suppressionsMu.RUnlock() + workspace, ok := m.suppressions[workspaceID] + if !ok { + return false, nil + } + sourceIDs, ok := workspace[userID] + if !ok { + return false, nil + } + if len(sourceIDs) == 0 { + return true, nil + } + for _, id := range sourceIDs { + if id == sourceID { + return true, nil + } + } + return false, nil +} + +func (m *memRepository) Add(suppressions []Suppression, token []byte) error { + m.suppressionsMu.Lock() + defer m.suppressionsMu.Unlock() + for i := range suppressions { + suppression := suppressions[i] + workspace, ok := m.suppressions[suppression.WorkspaceID] + if !ok { + workspace = make(map[string][]string) + m.suppressions[suppression.WorkspaceID] = workspace + } + if suppression.Canceled { + delete(workspace, suppression.UserID) + } else { + workspace[suppression.UserID] = suppression.SourceIDs + } + } + m.token = token + return nil +} + +func (*memRepository) Start() error { + return nil +} + +func (*memRepository) Stop() error { + return nil +} + +func (*memRepository) Backup(w io.Writer) error { + return nil +} + +func (*memRepository) Restore(r io.Reader) error { + return nil +} diff --git a/enterprise/suppress-user/internal/repository/model.go b/enterprise/suppress-user/internal/repository/model.go new file mode 100644 index 00000000000..46ebaa33134 --- /dev/null +++ b/enterprise/suppress-user/internal/repository/model.go @@ -0,0 +1,18 @@ +package repository + +import "github.com/rudderlabs/rudder-server/utils/logger" + +type Suppression struct { + WorkspaceID string `json:"workspaceId"` + Canceled bool `json:"canceled"` + UserID string `json:"userId"` + SourceIDs []string `json:"sourceIds"` +} + +type blogger struct { + logger.Logger +} + +func (l blogger) Warningf(fmt string, args ...interface{}) { + l.Warnf(fmt, args...) +} diff --git a/enterprise/suppress-user/internal/repository/repository.go b/enterprise/suppress-user/internal/repository/repository.go new file mode 100644 index 00000000000..b6e8b5cf2ac --- /dev/null +++ b/enterprise/suppress-user/internal/repository/repository.go @@ -0,0 +1,18 @@ +package repository + +import ( + "errors" + "io" +) + +var ErrNotInitialized = errors.New("repository not initialized") + +type Repository interface { + Start() error + Stop() error + GetToken() ([]byte, error) + Add(regulations []Suppression, token []byte) error + Suppress(userID, workspaceID, sourceID string) (bool, error) + Backup(w io.Writer) error + Restore(r io.Reader) error +} diff --git a/go.mod b/go.mod index 1baac7509f6..65e317f09c9 100644 --- a/go.mod +++ b/go.mod @@ -106,7 +106,7 @@ require ( github.com/coreos/go-systemd/v22 v22.3.2 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect github.com/davecgh/go-spew v1.1.1 // indirect - github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de // indirect + github.com/dgraph-io/ristretto v0.1.1 // indirect github.com/dgryski/go-farm v0.0.0-20200201041132-a6ae2369ad13 // indirect github.com/docker/cli v20.10.14+incompatible // indirect github.com/docker/docker v20.10.13+incompatible // indirect @@ -187,7 +187,7 @@ require ( go.uber.org/multierr v1.8.0 // indirect golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect golang.org/x/exp v0.0.0-20210220032938-85be41e4509f // indirect - golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec // indirect + golang.org/x/sys v0.0.0-20221010170243-090e33056c14 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect google.golang.org/appengine v1.6.7 // indirect @@ -198,7 +198,11 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) +require github.com/dgraph-io/badger/v3 v3.2103.3 + require ( + github.com/cespare/xxhash/v2 v2.1.2 // indirect + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b // indirect github.com/golang/protobuf v1.5.2 // indirect github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect ) diff --git a/go.sum b/go.sum index 01867c6d8e1..89b0fb9e2e3 100644 --- a/go.sum +++ b/go.sum @@ -288,6 +288,7 @@ github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6 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 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw= github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M= @@ -466,8 +467,11 @@ github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27 github.com/denverdino/aliyungo v0.0.0-20190125010748-a747050bb1ba/go.mod h1:dV8lFg6daOBZbT6/BDGIz6Y3WFGn8juu6G+CQ6LHtl0= github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o= github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk= -github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA= +github.com/dgraph-io/badger/v3 v3.2103.3 h1:s63J1pisDhKpzWslXFe+ChuthuZptpwTE6qEKoczPb4= +github.com/dgraph-io/badger/v3 v3.2103.3/go.mod h1:4MPiseMeDQ3FNCYwRbbcBOGJLf5jsE0PPFzRiKjtcdw= github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E= +github.com/dgraph-io/ristretto v0.1.1 h1:6CWw5tJNgpegArSHpNHJKldNeq03FQCwYvfMVWajOK8= +github.com/dgraph-io/ristretto v0.1.1/go.mod h1:S1GPSBCYCIhmVNfcth17y2zZtQT6wzkzgwUve0VDWWA= github.com/dgrijalva/jwt-go v0.0.0-20170104182250-a601269ab70c/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= @@ -650,6 +654,7 @@ github.com/golang-migrate/migrate/v4 v4.15.2/go.mod h1:f2toGLkYqD3JH+Todi4aZ2Zdb github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -699,6 +704,7 @@ github.com/gomodule/redigo v1.8.5/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUz github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA= +github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/flatbuffers v2.0.0+incompatible h1:dicJ2oXwypfwUGnB2/TYWYEKiuk9eYQlQO/AnOHl5mI= github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= @@ -1832,8 +1838,8 @@ golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec h1:BkDtF2Ih9xZ7le9ndzTA7KJow28VbQW3odyk/8drmuI= -golang.org/x/sys v0.0.0-20220928140112-f11e5e49a4ec/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14 h1:k5II8e6QD8mITdi+okbbmR/cIyEbeXLBhy5Ha4nevyc= +golang.org/x/sys v0.0.0-20221010170243-090e33056c14/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=