replace Redis with an embedded SQLite string->string KV store (group commit, in-tx events, SQL search)
Build and Push Docker Image / build (push) Successful in 2m44s
Build and Push Docker Image / build (push) Successful in 2m44s
This commit is contained in:
+28
-35
@@ -1,52 +1,45 @@
|
||||
package storage
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
// CountRoots returns the number of metadata roots in the file index.
|
||||
//
|
||||
// SCARD, not SMEMBERS: GetAllHashIDs ships every member over the wire (~3MB
|
||||
// and rising on an 88k-record box) just so the caller can take len(). A
|
||||
// dashboard tile that polls needs the number, never the list.
|
||||
// CountRoots returns the number of metadata roots in the root index — one
|
||||
// range count over idx:roots/, never the list itself.
|
||||
func (c *Client) CountRoots() (int64, error) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
if c.client == nil {
|
||||
return 0, fmt.Errorf("not connected")
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
n, err := c.client.SCard(ctx, c.buildIndexKey()).Result()
|
||||
s, err := c.kv()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("scard failed: %w", err)
|
||||
return 0, err
|
||||
}
|
||||
return n, nil
|
||||
ctx, cancel := opCtx()
|
||||
defer cancel()
|
||||
return s.Count(ctx, rootsNS)
|
||||
}
|
||||
|
||||
// CountKeys returns DBSIZE — every key in the Redis database, not just the
|
||||
// ones meta-core owns. It is the denominator for "how much of Redis is
|
||||
// records": ~3.1M keys against ~89k roots means the flat per-field keys
|
||||
// (file:{root}/{field}) dominate, which is expected.
|
||||
// keyCountTTL bounds how stale CountKeys may be. Counting every row is a full
|
||||
// table scan (~a second at millions of keys), and the only reader is a polled
|
||||
// dashboard tile — it needs a number, not a fresh one every few seconds.
|
||||
const keyCountTTL = 60 * time.Second
|
||||
|
||||
// CountKeys returns the number of rows in the database — every key, not just
|
||||
// records. It is the denominator for "how much of the store is records": the
|
||||
// flat per-field keys (file:{root}/{field}) dominate, which is expected.
|
||||
func (c *Client) CountKeys() (int64, error) {
|
||||
c.mu.RLock()
|
||||
defer c.mu.RUnlock()
|
||||
|
||||
if c.client == nil {
|
||||
return 0, fmt.Errorf("not connected")
|
||||
c.keysMu.Lock()
|
||||
defer c.keysMu.Unlock()
|
||||
if !c.keysAt.IsZero() && time.Since(c.keysAt) < keyCountTTL {
|
||||
return c.keysCount, nil
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
n, err := c.client.DBSize(ctx).Result()
|
||||
s, err := c.kv()
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("dbsize failed: %w", err)
|
||||
return 0, err
|
||||
}
|
||||
ctx, cancel := opCtx()
|
||||
defer cancel()
|
||||
n, err := s.CountAll(ctx)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
c.keysCount, c.keysAt = n, time.Now()
|
||||
return n, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user