Documentation
¶
Overview ¶
Package record holds the token ledger: the index of nova-tokens' day TSVs in the fleet Redis, one hash per day: a month query reads the day hashes in one pipelined trip, so the ledger keeps one store and no second copy. The rows and the same monthly GROUP BY live here on Redis with no new dependency. The day files stay the record; the ledger is what a month query reads instead of every file.
KEY LAYOUT. tokens:ledger:<YYYY-MM-DD> is a hash. Each field is one row's key, the JSON array ["<card>","<model>","<repo>"], so (day, card, model, repo) is the primary key; each value is the JSON object {"provider","tokens","rough","sources"} whose "tokens" array carries the five types in LedgerTypes order with null for a type no source reported -- never 0, because a dash in the day file is an absence. A month is the day keys of its calendar days, read in one pipelined round trip: no SCAN, no index key to keep true.
Index ¶
- Constants
- Variables
- func CheckLedgerDay(day string, entries []LedgerEntry) error
- func LedgerKey(day string) string
- func MonthDays(month string) ([]string, error)
- func SortLedgerTotals(t []LedgerTotal)
- type LedgerDay
- type LedgerEntry
- type LedgerStore
- type LedgerTotal
- type RedisLedger
- func (s *RedisLedger) Client() *redis.Client
- func (s *RedisLedger) Close() error
- func (s *RedisLedger) LedgerReport(ctx context.Context, month, by string) ([]LedgerTotal, int, int, error)
- func (s *RedisLedger) Ping(ctx context.Context) error
- func (s *RedisLedger) ReplaceLedgerDay(ctx context.Context, day string, entries []LedgerEntry) error
- func (s *RedisLedger) ReplaceLedgerDays(ctx context.Context, days []LedgerDay) error
Constants ¶
const LedgerPrefix = "tokens:ledger:"
LedgerPrefix is the owner prefix of every key this package writes.
Variables ¶
var ErrLedgerKey = errors.New("a ledger row names day, card, model and repo")
ErrLedgerKey is a row that does not name its whole key.
var LedgerGroupings = map[string][]string{
"model": {"model"},
"repo": {"repo"},
"day": {"day"},
"tuple": {"day", "model", "repo"},
}
LedgerGroupings are the --by values the report takes, and the key columns each groups on.
var LedgerTypes = [5]string{"input", "output", "cache_write", "cache_read", "reasoning"}
LedgerTypes are the five token types in the order every row and report prints them.
Functions ¶
func CheckLedgerDay ¶
func CheckLedgerDay(day string, entries []LedgerEntry) error
CheckLedgerDay refuses a day that is not a calendar day (it names a key), and a batch that is not all of that day or repeats a key: a caller that meant two rows under one key meant their sum.
func SortLedgerTotals ¶
func SortLedgerTotals(t []LedgerTotal)
SortLedgerTotals is the report's order: by the key columns ascending.
Types ¶
type LedgerDay ¶
type LedgerDay struct {
Day string
Entries []LedgerEntry
}
LedgerDay is one calendar day's batch of rows for ReplaceLedgerDays.
type LedgerEntry ¶
type LedgerEntry struct {
Day, Card, Model, Repo string
Provider string
Tokens [5]int64
Known [5]bool
Rough int
Sources string
}
LedgerEntry is one ledger row. Tokens[i] counts only when Known[i].
type LedgerStore ¶
type LedgerStore interface {
ReplaceLedgerDay(ctx context.Context, day string, entries []LedgerEntry) error
ReplaceLedgerDays(ctx context.Context, days []LedgerDay) error
LedgerReport(ctx context.Context, month, by string) ([]LedgerTotal, int, int, error)
Close() error
}
LedgerStore is the durable side of the token ledger. ReplaceLedgerDay swaps one day's rows for the given ones atomically, so indexing a day twice is the same ledger as once. ReplaceLedgerDays swaps multiple days' rows in one isolated EVAL round trip. LedgerReport is the monthly GROUP BY; indexed is how many calendar-day keys existed and missing is how many did not.
type LedgerTotal ¶
LedgerTotal is one GROUP BY group: the key columns the report grouped on (empty when not grouped on), how many ledger rows it summed, and each type's sum and whether any row reported it.
func GroupLedger ¶
func GroupLedger(entries []LedgerEntry, by string) ([]LedgerTotal, error)
GroupLedger is the GROUP BY: rows summed per the key columns of by, each type the SUM over the rows that reported it and unknown when none did -- the fold's per-type rule.
type RedisLedger ¶
type RedisLedger struct {
// contains filtered or unexported fields
}
RedisLedger is the ledger on the fleet Redis. It dials nothing itself: the caller opens the client, and Close closes it.
func DialLedger ¶
func DialLedger(addr, user, password string) *RedisLedger
DialLedger opens a client on addr (host:port) as the ACL user with its password ("" for the default user, "" for no password). The fleet Redis has its default user off, so a seat's password without its user is WRONGPASS. It silences go-redis's own logger first: a dial failure otherwise prints the library's untyped, local-time "connection pool: failed to dial after 5 attempts" lines to the process's stderr ahead of the verb's one typed FAILED line. The error they carry is not lost: it is the error the first command returns, which the verb prints.
func NewRedisLedger ¶
func NewRedisLedger(rdb *redis.Client) *RedisLedger
NewRedisLedger wraps a client the caller opened.
func (*RedisLedger) Client ¶
func (s *RedisLedger) Client() *redis.Client
Client returns the underlying redis.Client.
func (*RedisLedger) LedgerReport ¶
func (s *RedisLedger) LedgerReport(ctx context.Context, month, by string) ([]LedgerTotal, int, int, error)
LedgerReport reads every day hash of the month in one pipelined round trip and groups it. A field or value that does not decode is an error naming its key, never a skipped row. It returns the totals, how many calendar-day keys existed (indexed), and how many did not (missing).
func (*RedisLedger) Ping ¶
func (s *RedisLedger) Ping(ctx context.Context) error
Ping is one PING, so a verb names an unreachable store before it reads any file.
func (*RedisLedger) ReplaceLedgerDay ¶
func (s *RedisLedger) ReplaceLedgerDay(ctx context.Context, day string, entries []LedgerEntry) error
ReplaceLedgerDay swaps one day's rows by delegating to ReplaceLedgerDays.
func (*RedisLedger) ReplaceLedgerDays ¶
func (s *RedisLedger) ReplaceLedgerDays(ctx context.Context, days []LedgerDay) error
ReplaceLedgerDays replaces a batch in one isolated EVAL round trip. It validates key types and mutation/restore permissions before deleting any day, and bounds each HSET's argument count. A recoverable mutation error restores prior hash contents; restoration itself still needs a working server and available memory. Redis does not automatically roll back scripts or provide crash recovery here. A server without redis.acl_check_cmd is refused before any mutation.