From 4ab05592633ae75de5a39d16495f57eb6ea263a2 Mon Sep 17 00:00:00 2001 From: jakka Date: Sat, 12 Apr 2025 19:30:05 +0300 Subject: reimplemented database in badger so it actually works --- .gitignore | 1 + cmd/cmd.go | 25 +++--- cmd/init.go | 4 +- cmd/main.go | 2 +- files/database.go | 250 ++++++++++++++++++++++++++++++++++------------------ files/index.go | 56 ------------ files/operations.go | 143 ++++++++++++++++++++++++++++++ files/types.go | 6 +- go.mod | 26 +++--- go.sum | 70 +++++++++------ 10 files changed, 384 insertions(+), 199 deletions(-) delete mode 100644 files/index.go create mode 100644 files/operations.go diff --git a/.gitignore b/.gitignore index 6f72f89..a80ed40 100644 --- a/.gitignore +++ b/.gitignore @@ -23,3 +23,4 @@ go.work.sum # env file .env +.vscode/launch.json diff --git a/cmd/cmd.go b/cmd/cmd.go index 82a9cd5..974770d 100644 --- a/cmd/cmd.go +++ b/cmd/cmd.go @@ -5,33 +5,24 @@ import ( "os" "os/signal" - "github.com/justjakka/reencoder/files" - "github.com/tidwall/buntdb" + badger "github.com/dgraph-io/badger/v4" "github.com/urfave/cli/v2" + + "github.com/justjakka/reencoder/files" ) func runCmd(cCtx *cli.Context) error { - ctx, err := initCmd(cCtx) + ctx, err := initArgs(cCtx) if err != nil { return err } - db, err := buntdb.Open(ctx.Value("dbfile").(string)) + db, err := badger.Open(files.Options(ctx.Value("dbfile").(string))) if err != nil { return err } defer db.Close() - if err := db.Shrink(); err != nil { - return err - } - - if err := db.CreateIndex("process", "*", buntdb.IndexJSON("process")); err != nil { - if err != buntdb.ErrIndexExists { - return err - } - } - ctx = context.WithValue(ctx, "database", db) ctx, stop := signal.NotifyContext(ctx, os.Interrupt) @@ -41,6 +32,10 @@ func runCmd(cCtx *cli.Context) error { return err } + if err = files.ReencodeFlacs(ctx); err != nil { + return err + } + return nil /* @@ -63,7 +58,7 @@ func runCmd(cCtx *cli.Context) error { return cCtx.Err() */ } -func start() { +func Start() { app := &cli.App{ Name: "reencoder", Usage: "reencodes and stores info", diff --git a/cmd/init.go b/cmd/init.go index 18e3b65..2459315 100644 --- a/cmd/init.go +++ b/cmd/init.go @@ -34,7 +34,7 @@ func getDb(cCtx *cli.Context) (context.Context, error) { return context.WithValue(cCtx.Context, "dbfile", ""), errors.New("failed to locate application data folder") } - return context.WithValue(cCtx.Context, "dbfile", filepath.Join(localFolder, "reencoder.db")), nil + return context.WithValue(cCtx.Context, "dbfile", filepath.Join(localFolder, "reencoder")), nil } if _, err := os.Stat(cCtx.Path("dbfile")); err != nil { return context.WithValue(cCtx.Context, "dbfile", ""), err @@ -52,7 +52,7 @@ func checkTools() error { return nil } -func initCmd(cCtx *cli.Context) (context.Context, error) { +func initArgs(cCtx *cli.Context) (context.Context, error) { if err := checkTools(); err != nil { return nil, err } diff --git a/cmd/main.go b/cmd/main.go index 6d4c482..52cefc8 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,5 +1,5 @@ package main func main() { - start() + Start() } diff --git a/files/database.go b/files/database.go index 24bd5af..1ad40aa 100644 --- a/files/database.go +++ b/files/database.go @@ -2,125 +2,201 @@ package files import ( "context" - "crypto/sha256" "encoding/json" - "fmt" - "io" - "io/fs" - "os" - "os/exec" - "path/filepath" - "regexp" - "strings" - - "github.com/tidwall/buntdb" -) + "time" -func evaluateFile(database *buntdb.DB, hashsum string, filedata FileInfo) error { - return database.View(func(tx *buntdb.Tx) error { - data, err := tx.Get(hashsum) - if err != nil { - return err - } + badger "github.com/dgraph-io/badger/v4" + "github.com/dgraph-io/badger/v4/options" + "golang.org/x/sync/errgroup" +) - var info FileInfo - if err := json.Unmarshal([]byte(data), &info); err != nil { +func decodeDbInfo(item *badger.Item) (*FileInfo, error) { + var info FileInfo + if err := item.Value(func(val []byte) error { + if err := json.Unmarshal(val, &info); err != nil { return err } - if info == filedata { - return UpToDate - } - switch info.Modtime == filedata.Modtime { - case true: - if info.AbsPath == filedata.AbsPath { - if info.Process { - return NeedsReencode - } - return UpToDate - } - if info.Process { - return NeedsReencode - } - return MovedFile - default: - return nil - } - }) -} - -func getEncoderVer(path string) (string, error) { - out, err := exec.Command("metaflac", "--show-vendor-tag", path).Output() - if err != nil { - return "", err - } - - r := regexp.MustCompile("libFLAC \\d\\.\\d\\.\\d") - encoder := r.FindString(string(out)) - switch encoder { - case "": - return "", nil - default: - return strings.Split(encoder, " ")[1], nil + return nil + }); err != nil { + return nil, err } + return &info, nil } -func updateFile(database *buntdb.DB, hashsum string, filedata FileInfo) error { - return database.Update(func(tx *buntdb.Tx) error { - data, err := json.Marshal(filedata) +func getInfoFromDb(database *badger.DB, hashsum []byte) (*FileInfo, error) { + var info *FileInfo + if err := database.View(func(txn *badger.Txn) error { + item, err := txn.Get(hashsum) if err != nil { return err } - if _, _, err := tx.Set(hashsum, string(data), nil); err != nil { + + info, err = decodeDbInfo(item) + if err != nil { return err } return nil - }) + }); err != nil { + return nil, err + } + return info, nil } -func ProcessFile(ctx context.Context, path string, info fs.DirEntry) error { - tmp, err := info.Info() +func (filedata *FileInfo) evaluateFile(database *badger.DB, hashsum []byte, encoder string) error { + info, err := getInfoFromDb(database, hashsum) if err != nil { return err } - modtime := tmp.ModTime() - - database := ctx.Value("database").(*buntdb.DB) - - file, err := os.Open(path) - if err != nil { - return err + if info.Process { + return ReencodeNeeded } - defer file.Close() - - hash := sha256.New() - if _, err := io.Copy(hash, file); err != nil { - return err + if filedata.Encoder != encoder { + return ReencodeNeeded } - hashsum := fmt.Sprintf("%x", hash.Sum(nil)) - - abspath, err := filepath.Abs(path) - if err != nil { - return err + if info.AbsPath != filedata.AbsPath { + return FileMoved } + return ReencodeNotNeeded +} - encoder, err := getEncoderVer(path) +func (filedata *FileInfo) updateFile(database *badger.DB, hashsum []byte) error { + return database.Update(func(txn *badger.Txn) error { + encoded, err := json.Marshal(filedata) + if err != nil { + return err + } + return txn.Set(hashsum, encoded) + }) +} - filedata := FileInfo{AbsPath: abspath, Modtime: modtime, Encoder: encoder, Process: true} +func (filedata *FileInfo) IndexFile(ctx context.Context, hashsum []byte) error { + database := ctx.Value("database").(*badger.DB) + encoder := ctx.Value("encoder").(string) - err = evaluateFile(database, hashsum, filedata) + err := filedata.evaluateFile(database, hashsum, encoder) switch err { - case MovedFile, UpToDate: - if filedata.Encoder == ctx.Value("encoder").(string) { - return nil - } - case buntdb.ErrNotFound, NeedsReencode: + case FileMoved, ReencodeNotNeeded: + filedata.Process = false + case ReencodeNeeded, badger.ErrKeyNotFound: default: return err } - if err := updateFile(database, hashsum, filedata); err != nil { + if err := filedata.updateFile(database, hashsum); err != nil { return err } return nil } + +func ReencodeFlacs(ctx context.Context) error { + db := ctx.Value("database").(*badger.DB) + wg := new(errgroup.Group) + wg.SetLimit(4) + err := db.View(func(txn *badger.Txn) error { + opts := badger.DefaultIteratorOptions + opts.PrefetchSize = 10 + it := txn.NewIterator(opts) + defer it.Close() + + for it.Rewind(); it.Valid(); it.Next() { + /* item := it.Item() + key := item.Key() + info, err := decodeDbInfo(item) + if err != nil { + return err + } + if err := info.reencodeFile(ctx); err != nil { + return err + } + if err := info.updateFile(db, key); err != nil { + return err + } */ + select { + case <-ctx.Done(): + return nil + default: + item := it.Item() + key := item.Key() + info, err := decodeDbInfo(item) + if err != nil { + return err + } + wg.Go(func() error { + select { + case <-ctx.Done(): + return nil + default: + if err := info.reencodeFile(ctx); err != nil { + return err + } + if err := info.updateFile(db, key); err != nil { + return err + } + return nil + } + }) + } + } + return nil + }) + wg.Wait() + return err +} + +func Options(path string) badger.Options { + return badger.Options{ + Dir: path, + ValueDir: path, + + MemTableSize: 64 << 20, + BaseTableSize: 2 << 20, + BaseLevelSize: 10 << 20, + TableSizeMultiplier: 2, + LevelSizeMultiplier: 10, + MaxLevels: 7, + NumGoroutines: 8, + MetricsEnabled: true, + + NumCompactors: 4, // Run at least 2 compactors. Zero-th compactor prioritizes L0. + NumLevelZeroTables: 5, + NumLevelZeroTablesStall: 15, + NumMemtables: 5, + BloomFalsePositive: 0.01, + BlockSize: 4 * 1024, + SyncWrites: false, + NumVersionsToKeep: 1, + CompactL0OnClose: false, + VerifyValueChecksum: false, + Compression: options.Snappy, + BlockCacheSize: 256 << 20, + IndexCacheSize: 0, + + // The following benchmarks were done on a 4 KB block size (default block size). The + // compression is ratio supposed to increase with increasing compression level but since the + // input for compression algorithm is small (4 KB), we don't get significant benefit at + // level 3. + // NOTE: The benchmarks are with DataDog ZSTD that requires CGO. Hence, no longer valid. + // no_compression-16 10 502848865 ns/op 165.46 MB/s - + // zstd_compression/level_1-16 7 739037966 ns/op 112.58 MB/s 2.93 + // zstd_compression/level_3-16 7 756950250 ns/op 109.91 MB/s 2.72 + // zstd_compression/level_15-16 1 11135686219 ns/op 7.47 MB/s 4.38 + // Benchmark code can be found in table/builder_test.go file + ZSTDCompressionLevel: 1, + + // (2^30 - 1)*2 when mmapping < 2^31 - 1, max int32. + // -1 so 2*ValueLogFileSize won't overflow on 32-bit systems. + ValueLogFileSize: 1<<30 - 1, + + ValueLogMaxEntries: 1000000, + + VLogPercentile: 0.0, + ValueThreshold: (1 << 20), + + Logger: nil, + EncryptionKey: []byte{}, + EncryptionKeyRotationDuration: 10 * 24 * time.Hour, // Default 10 days. + DetectConflicts: true, + NamespaceOffset: -1, + } +} diff --git a/files/index.go b/files/index.go deleted file mode 100644 index ea05dc4..0000000 --- a/files/index.go +++ /dev/null @@ -1,56 +0,0 @@ -package files - -import ( - "context" - "io/fs" - "path/filepath" - "time" - - "github.com/briandowns/spinner" - "golang.org/x/sync/errgroup" -) - -func IndexFlacs(ctx context.Context) error { - spin := spinner.New(spinner.CharSets[9], 100*time.Millisecond) - spin.Suffix = " Indexing flacs..." - - spin.Start() - - wg := new(errgroup.Group) - wg.SetLimit(100) - - if err := filepath.WalkDir(ctx.Value("path").(string), func(path string, info fs.DirEntry, err error) error { - select { - case <-ctx.Done(): - spin.FinalMSG = "Stopping...\n" - spin.Stop() - return nil - default: - if err != nil { - return err - } - if !info.IsDir() { - if filepath.Ext(path) == ".flac" { - wg.Go(func() error { - select { - case <-ctx.Done(): - return nil - default: - return ProcessFile(ctx, path, info) - } - }) - } - - } - return nil - } - - }); err != nil { - return err - } - - wg.Wait() - spin.FinalMSG = "Done indexing flacs" - spin.Stop() - return nil -} diff --git a/files/operations.go b/files/operations.go new file mode 100644 index 0000000..3da6586 --- /dev/null +++ b/files/operations.go @@ -0,0 +1,143 @@ +package files + +import ( + "context" + "crypto/sha256" + "fmt" + "io" + "io/fs" + "os" + "os/exec" + "path/filepath" + "regexp" + "strings" + "time" + + "github.com/briandowns/spinner" + "golang.org/x/sync/errgroup" +) + +func (file *FileInfo) reencodeFile(ctx context.Context) error { + /* cmd := exec.Command("flac", "-8", "-f", file.AbsPath) + if err := cmd.Run(); err != nil { + log.Printf("%s\n", err.Error()) + return err + } + file.Encoder = ctx.Value("encoder").(string) */ + fmt.Println(file) + return nil +} + +func getEncoderVer(path string) (string, error) { + out, err := exec.Command("metaflac", "--show-vendor-tag", path).Output() + if err != nil { + return "", err + } + + r := regexp.MustCompile("libFLAC \\d\\.\\d\\.\\d") + encoder := r.FindString(string(out)) + switch encoder { + case "": + return "", nil + default: + return strings.Split(encoder, " ")[1], nil + } +} + +func getInfoFromFile(path string, info fs.DirEntry) (*FileInfo, error) { + var filedata FileInfo + + filedata.Process = true + + tmp, err := info.Info() + if err != nil { + return nil, err + } + + filedata.Modtime = tmp.ModTime() + + abspath, err := filepath.Abs(path) + if err != nil { + return nil, err + } + + filedata.AbsPath = abspath + + encoder, err := getEncoderVer(path) + if err != nil { + return nil, err + } + + filedata.Encoder = encoder + + return &filedata, nil +} + +func getSha256(path string) ([]byte, error) { + file, err := os.Open(path) + if err != nil { + return nil, err + } + defer file.Close() + + hash := sha256.New() + if _, err := io.Copy(hash, file); err != nil { + return nil, err + } + return hash.Sum(nil), nil +} + +func IndexFlacs(ctx context.Context) error { + spin := spinner.New(spinner.CharSets[9], 100*time.Millisecond) + spin.Suffix = " Indexing flacs..." + + spin.Start() + + wg := new(errgroup.Group) + wg.SetLimit(100) + + if err := filepath.WalkDir(ctx.Value("path").(string), func(path string, info fs.DirEntry, err error) error { + select { + case <-ctx.Done(): + spin.FinalMSG = "Stopping...\n" + spin.Stop() + return filepath.SkipAll + default: + if err != nil { + return err + } + if !info.IsDir() { + if filepath.Ext(path) == ".flac" { + wg.Go(func() error { + select { + case <-ctx.Done(): + return nil + default: + data, err := getInfoFromFile(path, info) + if err != nil { + return err + } + + hashsum, err := getSha256(path) + if err != nil { + return err + } + + return data.IndexFile(ctx, hashsum) + } + }) + } + + } + return nil + } + + }); err != nil { + return err + } + + wg.Wait() + spin.FinalMSG = "Done indexing flacs\n" + spin.Stop() + return nil +} diff --git a/files/types.go b/files/types.go index 54d8563..87ae6e1 100644 --- a/files/types.go +++ b/files/types.go @@ -6,9 +6,9 @@ import ( ) var ( - UpToDate = errors.New("file is up to date") - MovedFile = errors.New("file was moved") - NeedsReencode = errors.New("file needs to be reencoded") + ReencodeNotNeeded = errors.New("file is up to date") + FileMoved = errors.New("file was moved") + ReencodeNeeded = errors.New("file needs to be reencoded") ) type FileInfo struct { diff --git a/go.mod b/go.mod index 0c1e6dd..e7345d0 100644 --- a/go.mod +++ b/go.mod @@ -5,25 +5,31 @@ go 1.24.2 require github.com/urfave/cli/v2 v2.27.6 require ( + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect + github.com/dustin/go-humanize v1.0.1 // indirect github.com/fatih/color v1.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-logr/stdr v1.2.2 // indirect + github.com/google/flatbuffers v25.2.10+incompatible // indirect + github.com/klauspost/compress v1.18.0 // indirect github.com/mattn/go-colorable v0.1.2 // indirect github.com/mattn/go-isatty v0.0.20 // indirect - github.com/tidwall/btree v1.4.2 // indirect - github.com/tidwall/gjson v1.14.3 // indirect - github.com/tidwall/grect v0.1.4 // indirect - github.com/tidwall/match v1.1.1 // indirect - github.com/tidwall/pretty v1.2.0 // indirect - github.com/tidwall/rtred v0.1.2 // indirect - github.com/tidwall/tinyqueue v0.1.1 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/term v0.28.0 // indirect + go.opentelemetry.io/auto/sdk v1.1.0 // indirect + go.opentelemetry.io/otel v1.35.0 // indirect + go.opentelemetry.io/otel/metric v1.35.0 // indirect + go.opentelemetry.io/otel/trace v1.35.0 // indirect + golang.org/x/net v0.38.0 // indirect + golang.org/x/sys v0.31.0 // indirect + golang.org/x/term v0.30.0 // indirect + google.golang.org/protobuf v1.36.6 // indirect ) require ( github.com/briandowns/spinner v1.23.2 github.com/cpuguy83/go-md2man/v2 v2.0.5 // indirect + github.com/dgraph-io/badger/v4 v4.7.0 github.com/russross/blackfriday/v2 v2.1.0 // indirect - github.com/tidwall/buntdb v1.3.2 github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect golang.org/x/sync v0.13.0 ) diff --git a/go.sum b/go.sum index c088acc..1723f5b 100644 --- a/go.sum +++ b/go.sum @@ -1,46 +1,66 @@ github.com/briandowns/spinner v1.23.2 h1:Zc6ecUnI+YzLmJniCfDNaMbW0Wid1d5+qcTq4L2FW8w= github.com/briandowns/spinner v1.23.2/go.mod h1:LaZeM4wm2Ywy6vO571mvhQNRcWfRUnXOs0RcKV0wYKM= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +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/dgraph-io/badger/v4 v4.7.0 h1:Q+J8HApYAY7UMpL8d9owqiB+odzEc0zn/aqOD9jhc6Y= +github.com/dgraph-io/badger/v4 v4.7.0/go.mod h1:He7TzG3YBy3j4f5baj5B7Zl2XyfNe5bl4Udl0aPemVA= +github.com/dgraph-io/ristretto/v2 v2.2.0 h1:bkY3XzJcXoMuELV8F+vS8kzNgicwQFAaGINAEJdWGOM= +github.com/dgraph-io/ristretto/v2 v2.2.0/go.mod h1:RZrm63UmcBAaYWC1DotLYBmTvgkrs0+XhBd7Npn7/zI= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38= +github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw= +github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= +github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys= github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= +github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= +github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/google/flatbuffers v25.2.10+incompatible h1:F3vclr7C3HpB1k9mxCGRMXq6FdUalZ6H/pNX4FP1v0Q= +github.com/google/flatbuffers v25.2.10+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= +github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= +github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/mattn/go-colorable v0.1.2 h1:/bC9yWikZXAL9uJdulbSfyVNIR3n3trXl+v8+1sx8mU= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/tidwall/assert v0.1.0 h1:aWcKyRBUAdLoVebxo95N7+YZVTFF/ASTr7BN4sLP6XI= -github.com/tidwall/assert v0.1.0/go.mod h1:QLYtGyeqse53vuELQheYl9dngGCJQ+mTtlxcktb+Kj8= -github.com/tidwall/btree v1.4.2 h1:PpkaieETJMUxYNADsjgtNRcERX7mGc/GP2zp/r5FM3g= -github.com/tidwall/btree v1.4.2/go.mod h1:LGm8L/DZjPLmeWGjv5kFrY8dL4uVhMmzmmLYmsObdKE= -github.com/tidwall/buntdb v1.3.2 h1:qd+IpdEGs0pZci37G4jF51+fSKlkuUTMXuHhXL1AkKg= -github.com/tidwall/buntdb v1.3.2/go.mod h1:lZZrZUWzlyDJKlLQ6DKAy53LnG7m5kHyrEHvvcDmBpU= -github.com/tidwall/gjson v1.12.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/gjson v1.14.3 h1:9jvXn7olKEHU1S9vwoMGliaT8jq1vJ7IH/n9zD9Dnlw= -github.com/tidwall/gjson v1.14.3/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= -github.com/tidwall/grect v0.1.4 h1:dA3oIgNgWdSspFzn1kS4S/RDpZFLrIxAZOdJKjYapOg= -github.com/tidwall/grect v0.1.4/go.mod h1:9FBsaYRaR0Tcy4UwefBX/UDcDcDy9V5jUcxHzv2jd5Q= -github.com/tidwall/lotsa v1.0.2 h1:dNVBH5MErdaQ/xd9s769R31/n2dXavsQ0Yf4TMEHHw8= -github.com/tidwall/lotsa v1.0.2/go.mod h1:X6NiU+4yHA3fE3Puvpnn1XMDrFZrE9JO2/w+UMuqgR8= -github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= -github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= -github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= -github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= -github.com/tidwall/rtred v0.1.2 h1:exmoQtOLvDoO8ud++6LwVsAMTu0KPzLTUrMln8u1yu8= -github.com/tidwall/rtred v0.1.2/go.mod h1:hd69WNXQ5RP9vHd7dqekAz+RIdtfBogmglkZSRxCHFQ= -github.com/tidwall/tinyqueue v0.1.1 h1:SpNEvEggbpyN5DIReaJ2/1ndroY8iyEGxPYxoSaymYE= -github.com/tidwall/tinyqueue v0.1.1/go.mod h1:O/QNHwrnjqr6IHItYrzoHAKYhBkLI67Q096fQP5zMYw= +github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/urfave/cli/v2 v2.27.6 h1:VdRdS98FNhKZ8/Az8B7MTyGQmpIr36O1EHybx/LaZ4g= github.com/urfave/cli/v2 v2.27.6/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ= +go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y= +go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M= +go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE= +go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs= +go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= +golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= +golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= -golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= +golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= +golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y= +golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -- cgit v1.3.1