The module was declared as github.com/zzg/fathom, which is not where this repo lives and never has been. Nothing is published at that path, so `go get github.com/zzg/fathom` resolves to a 404 while the import paths in every file assert otherwise. git.z.gd is a real module path rather than a cosmetic correction: Gitea serves the go-import meta tag for it, <meta name="go-import" content="git.z.gd/zzg/fathom git https://git.z.gd/zzg/fathom.git"> and the repo answers unauthenticated over HTTPS, so `go get git.z.gd/zzg/fathom` resolves where the old path could not. Mechanical: the module line plus 46 import paths across 23 files. There is no go.sum to churn, since fathom has no third-party dependencies. go build, go vet, gofmt and the full test suite are clean under the new path, and the built binary still runs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
97 lines
2.9 KiB
Go
97 lines
2.9 KiB
Go
package store
|
|
|
|
import (
|
|
"git.z.gd/zzg/fathom/internal/model"
|
|
)
|
|
|
|
// The exported read surface. Scans go through these rather than through the
|
|
// query engine when the caller wants whole records — the trace list and the
|
|
// trace detail view both do, since neither is expressible as an aggregate.
|
|
|
|
// ReadSpan materialises row i of a chunk as a Span, without its blobs.
|
|
func ReadSpan(c *Chunk, i int) model.Span { return readSpan(c, i) }
|
|
|
|
// ReadLog materialises row i of a chunk as a LogRecord, without its body.
|
|
func ReadLog(c *Chunk, i int) model.LogRecord { return readLog(c, i) }
|
|
|
|
// InputRef, OutputRef, and BodyRef return a row's blob references so callers
|
|
// can defer the read until someone actually looks at the content.
|
|
func InputRef(c *Chunk, i int) BlobRef { return blobAt(c, ColInput, i) }
|
|
func OutputRef(c *Chunk, i int) BlobRef { return blobAt(c, ColOutput, i) }
|
|
func BodyRef(c *Chunk, i int) BlobRef { return blobAt(c, ColBody, i) }
|
|
|
|
// ScanSpans visits every span in a time range, oldest shard first.
|
|
//
|
|
// The callback receives the shard so it can resolve blob references lazily. It
|
|
// returns false to stop early, which is what lets a bounded trace lookup avoid
|
|
// reading the rest of the range once it has what it came for.
|
|
func (s *Store) ScanSpans(minTS, maxTS int64, fn func(sp model.Span, sh *Shard, c *Chunk, i int) bool) (Scanned, error) {
|
|
return s.scan(model.TableSpans, minTS, maxTS, func(sh *Shard, c *Chunk, i int) bool {
|
|
sp := readSpan(c, i)
|
|
if sp.StartTS < minTS || sp.StartTS > maxTS {
|
|
return true
|
|
}
|
|
return fn(sp, sh, c, i)
|
|
})
|
|
}
|
|
|
|
// ScanLogs visits every log record in a time range.
|
|
func (s *Store) ScanLogs(minTS, maxTS int64, fn func(rec model.LogRecord, sh *Shard, c *Chunk, i int) bool) (Scanned, error) {
|
|
return s.scan(model.TableLogs, minTS, maxTS, func(sh *Shard, c *Chunk, i int) bool {
|
|
rec := readLog(c, i)
|
|
if rec.TS < minTS || rec.TS > maxTS {
|
|
return true
|
|
}
|
|
return fn(rec, sh, c, i)
|
|
})
|
|
}
|
|
|
|
// Scanned reports how much a scan read, so callers can show the cost honestly
|
|
// rather than implying an index did the work.
|
|
type Scanned struct {
|
|
Shards int
|
|
Chunks int
|
|
Rows int
|
|
}
|
|
|
|
var errStopScan = stopScan{}
|
|
|
|
type stopScan struct{}
|
|
|
|
func (stopScan) Error() string { return "scan stopped" }
|
|
|
|
func (s *Store) scan(table string, minTS, maxTS int64, fn func(*Shard, *Chunk, int) bool) (Scanned, error) {
|
|
var sc Scanned
|
|
|
|
shards, err := s.ShardsOverlapping(table, minTS, maxTS)
|
|
if err != nil {
|
|
return sc, err
|
|
}
|
|
sc.Shards = len(shards)
|
|
|
|
for _, info := range shards {
|
|
sh, err := s.OpenShardForRead(info.Table, info.Date)
|
|
if err != nil {
|
|
// One unreadable shard should cost that shard, not the query.
|
|
continue
|
|
}
|
|
err = sh.Chunks(func(c *Chunk) error {
|
|
sc.Chunks++
|
|
sc.Rows += c.Rows
|
|
for i := 0; i < c.Rows; i++ {
|
|
if !fn(sh, c, i) {
|
|
return errStopScan
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
if err == errStopScan {
|
|
return sc, nil
|
|
}
|
|
if err != nil {
|
|
continue
|
|
}
|
|
}
|
|
return sc, nil
|
|
}
|