Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/stellar-rpc/internal/rpcv2/backfill/txindex.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func buildTxhashIndex(ctx context.Context, w geometry.TxHashIndexID, lo, hi chun

// one-write:create — write from scratch (BuildColdIndex truncates any crashed
// partial). MkdirAll is idempotent, so the index dir is created on demand.
indexDir := layout.TxHashIndexDir(w)
indexDir := layout.TxHashIndexDir(cov)
if mkErr := os.MkdirAll(indexDir, 0o755); mkErr != nil {
return fmt.Errorf("buildTxhashIndex mkdir %s: %w", indexDir, mkErr)
}
Expand Down
18 changes: 15 additions & 3 deletions cmd/stellar-rpc/internal/rpcv2/backfill/txindex_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"os"
"path/filepath"
"sort"
"strings"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -210,6 +211,8 @@ func TestBuildThenSweep_RollingPredecessorDemotedNotSwept(t *testing.T) {
require.True(t, ok)
require.Equal(t, chunk.ID(0), frozen.Lo)
require.Equal(t, hi, frozen.Hi)
require.True(t, strings.HasPrefix(cat.Layout().TxHashIndexFilePath(frozen), cat.Layout().HotRoot()),
"a window still filling keeps its index with the hot tier")

// The predecessors linger as "pruning" debris: the old .idx is
// query-visible, so its deletion waits for a lifecycle run's grace-
Expand Down Expand Up @@ -279,6 +282,8 @@ func TestBuildThenSweep_TerminalDemotesAndSweepsAllInputs(t *testing.T) {
require.True(t, ok)
require.True(t, cat.TxHashIndexLayout().IsTerminalCoverage(frozen))
require.Equal(t, chunk.ID(3), frozen.Hi)
require.True(t, strings.HasPrefix(cat.Layout().TxHashIndexFilePath(frozen), cat.Layout().TxHashIndexRoot()),
"a terminal index is a cold artifact")

// Every in-window txhash key was demoted AND swept: key absent => .bin gone.
for c := chunk.ID(0); c <= 3; c++ {
Expand Down Expand Up @@ -462,7 +467,8 @@ func TestBuildCrashMatrix_AfterCommitBeforeSweep(t *testing.T) {
}
// A predecessor [0,2] so the commit has a coverage to demote too.
require.NoError(t, buildThenSweep(context.Background(), IndexBuild{Index: 0, Lo: 0, Hi: 2}, cfg))
predPath := cat.Layout().TxHashIndexFilePath(geometry.TxHashIndexCoverage{Index: 0, Lo: 0, Hi: 2})
pred := geometry.TxHashIndexCoverage{Index: 0, Lo: 0, Hi: 2, Key: geometry.TxHashIndexKey(0, 0, 2)}
predPath := cat.Layout().TxHashIndexFilePath(pred)

// Reconstruct the "crash after commit, before the eager sweep" of the terminal
// build [0,3]: buildTxhashIndex commits WITHOUT sweeping (the sweep is
Expand All @@ -481,7 +487,7 @@ func TestBuildCrashMatrix_AfterCommitBeforeSweep(t *testing.T) {
for _, k := range keys {
states[k.Key] = k.State
}
require.Equal(t, geometry.StatePruning, states[geometry.TxHashIndexKey(0, 0, 2)], "predecessor demoted, not yet swept")
require.Equal(t, geometry.StatePruning, states[pred.Key], "predecessor demoted, not yet swept")
for c := chunk.ID(0); c <= 3; c++ {
s, serr := cat.State(c, geometry.KindTxHash)
require.NoError(t, serr)
Expand Down Expand Up @@ -513,7 +519,13 @@ func TestBuildCrashMatrix_AfterCommitBeforeSweep(t *testing.T) {
states[k.Key] = k.State
}
require.Equal(t, geometry.StateFrozen, states[geometry.TxHashIndexKey(0, 0, 3)])
require.Equal(t, geometry.StatePruning, states[geometry.TxHashIndexKey(0, 0, 2)])
require.Equal(t, geometry.StatePruning, states[pred.Key])

// The lifecycle's destroy takes the predecessor's file and its hot-tier
// directory; the terminal index stays in the cold root.
require.NoError(t, cat.DestroyTxHashIndexKey(pred))
require.NoDirExists(t, cat.Layout().TxHashIndexDir(pred))
require.FileExists(t, cat.Layout().TxHashIndexFilePath(frozen))
}

// Row "mid-sweep": a "pruning" key whose durable unlink completed but whose key
Expand Down
3 changes: 1 addition & 2 deletions cmd/stellar-rpc/internal/rpcv2/bench/bench_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,7 @@ func readCSV(t *testing.T, path string) map[string]map[string]int64 {
// index .idx (both chunks inside one window, as every test range here is).
func txhashIndexPath(t *testing.T, layout geometry.Layout, lo, hi chunk.ID) string {
t.Helper()
txLayout, err := geometry.NewTxHashIndexLayout(geometry.ChunksPerTxhashIndex)
require.NoError(t, err)
txLayout := layout.TxHashIndex()
w := txLayout.TxHashIndexID(lo)
require.Equal(t, w, txLayout.TxHashIndexID(hi), "test range must stay inside one index window")
return layout.TxHashIndexFilePath(geometry.TxHashIndexCoverage{Index: w, Lo: lo, Hi: hi})
Expand Down
2 changes: 1 addition & 1 deletion cmd/stellar-rpc/internal/rpcv2/bench/dataset.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func openDatasetCatalog(layout geometry.Layout, logger *supportlog.Entry) (*cata
if err != nil {
return nil, err
}
cat, err := catalog.Open(layout.CatalogPath(), layout, txLayout, logger)
cat, err := catalog.Open(layout.CatalogPath(), layout.WithTxHashIndex(txLayout), logger)
if err != nil {
return nil, fmt.Errorf("open dataset catalog %s: %w", layout.CatalogPath(), err)
}
Expand Down
25 changes: 11 additions & 14 deletions cmd/stellar-rpc/internal/rpcv2/catalog/catalog.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,22 @@ import (
// concurrency guard: the design's Concurrency model guarantees one writer per
// key (see the header note in catalog_protocol.go).
type Catalog struct {
store *rocksdb.Store
logger *supportlog.Entry
layout geometry.Layout
txhashIndex geometry.TxHashIndexLayout
secret [32]byte // cold-index secret, minted once at Open then read-only
store *rocksdb.Store
logger *supportlog.Entry
layout geometry.Layout
secret [32]byte // cold-index secret, minted once at Open then read-only
}

// Open opens the catalog's backing KV store at path (created if absent) and
// binds the catalog to it, the on-disk layout, and the tx-hash-index
// arithmetic. path and logger are required (rocksdb.New validates both). The
// catalog owns the store: Close releases it.
func Open(
path string, layout geometry.Layout, txhashIndex geometry.TxHashIndexLayout, logger *supportlog.Entry,
) (*Catalog, error) {
// binds the catalog to it and the on-disk layout, whose tx-hash index
// arithmetic it uses. path and logger are required (rocksdb.New validates
// both). The catalog owns the store: Close releases it.
func Open(path string, layout geometry.Layout, logger *supportlog.Entry) (*Catalog, error) {
store, err := rocksdb.New(rocksdb.Config{Path: path, Logger: logger})
if err != nil {
return nil, err
}
c := &Catalog{store: store, logger: logger, layout: layout, txhashIndex: txhashIndex}
c := &Catalog{store: store, logger: logger, layout: layout}
// Census before the secret mint below: a catalog holding entries outside
// this binary's vocabulary (a newer binary's formats, or corruption) is
// refused here, so Open writes no catalog entry of its own into a tree it
Expand Down Expand Up @@ -116,7 +113,7 @@ func (c *Catalog) Logger() *supportlog.Entry { return c.logger }

func (c *Catalog) Layout() geometry.Layout { return c.layout }

func (c *Catalog) TxHashIndexLayout() geometry.TxHashIndexLayout { return c.txhashIndex }
func (c *Catalog) TxHashIndexLayout() geometry.TxHashIndexLayout { return c.layout.TxHashIndex() }

// ---------------------------------------------------------------------------
// Typed artifact-state accessors.
Expand Down Expand Up @@ -244,7 +241,7 @@ func (c *Catalog) FrozenIndexCoversRange(w geometry.TxHashIndexID, lo, hi chunk.
// window is the only one that can cover it — the degenerate single-chunk case of
// FrozenIndexCoversRange.
func (c *Catalog) FrozenIndexCovers(ch chunk.ID) (bool, error) {
return c.FrozenIndexCoversRange(c.txhashIndex.TxHashIndexID(ch), ch, ch)
return c.FrozenIndexCoversRange(c.TxHashIndexLayout().TxHashIndexID(ch), ch, ch)
}

// ---------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion cmd/stellar-rpc/internal/rpcv2/catalog/catalog_protocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ func (c *Catalog) CommitTxHashIndex(cov geometry.TxHashIndexCoverage) error {
}

var txhashKeys []string
if c.txhashIndex.IsTerminalCoverage(cov) {
if c.TxHashIndexLayout().IsTerminalCoverage(cov) {
txhashKeys, err = c.txhashIndexChunkKeysPresent(cov.Lo, cov.Hi)
if err != nil {
return err
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ func TestCommitIndexTerminalDemotesTxhashKeys(t *testing.T) {
// Terminal build covers the whole index [0,999] => hi == last chunk.
cov, err := cat.MarkTxHashIndexFreezing(0, 0, 999)
require.NoError(t, err)
require.True(t, cat.txhashIndex.IsTerminalCoverage(cov))
require.True(t, cat.TxHashIndexLayout().IsTerminalCoverage(cov))
require.NoError(t, cat.CommitTxHashIndex(cov))

// Every present txhash key in the index demoted to "pruning".
Expand Down Expand Up @@ -110,7 +110,7 @@ func TestCommitIndexNonTerminalLeavesTxhashKeys(t *testing.T) {
// Non-terminal: hi (5) < index's last chunk (999).
cov, err := cat.MarkTxHashIndexFreezing(0, 0, 5)
require.NoError(t, err)
require.False(t, cat.txhashIndex.IsTerminalCoverage(cov))
require.False(t, cat.TxHashIndexLayout().IsTerminalCoverage(cov))
require.NoError(t, cat.CommitTxHashIndex(cov))

// txhash key NOT demoted — the index is still filling.
Expand Down Expand Up @@ -139,7 +139,7 @@ func TestCommitIndexTerminalDemotesOnlyCoverageRange(t *testing.T) {
// A TERMINAL coverage starting after the index's first chunk: [5500,5999].
cov, err := cat.MarkTxHashIndexFreezing(5, 5500, 5999)
require.NoError(t, err)
require.True(t, cat.txhashIndex.IsTerminalCoverage(cov))
require.True(t, cat.TxHashIndexLayout().IsTerminalCoverage(cov))
require.NoError(t, cat.CommitTxHashIndex(cov))

// .bin inputs inside [Lo,Hi] are demoted...
Expand Down
2 changes: 1 addition & 1 deletion cmd/stellar-rpc/internal/rpcv2/catalog/catalog_sweep.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func (c *Catalog) DestroyTxHashIndexKey(cov geometry.TxHashIndexCoverage) error
if err := durable.DeleteFileIfExists(path); err != nil {
return err
}
dir := c.layout.TxHashIndexDir(cov.Index)
dir := c.layout.TxHashIndexDir(cov)
if err := durable.FsyncDir(dir); err != nil { // unlink durable BEFORE key delete
return err
}
Expand Down
2 changes: 2 additions & 0 deletions cmd/stellar-rpc/internal/rpcv2/catalog/catalog_sweep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package catalog
import (
"os"
"path/filepath"
"strings"
"testing"

"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -89,6 +90,7 @@ func TestSweepIndexKey(t *testing.T) {
cov, err := cat.MarkTxHashIndexFreezing(5, 5100, 5349)
require.NoError(t, err)
idxPath := cat.layout.TxHashIndexFilePath(cov)
require.True(t, strings.HasPrefix(idxPath, cat.layout.HotRoot()), "a window still filling lives with the hot tier")
writeArtifact(t, idxPath)
require.NoError(t, cat.CommitTxHashIndex(cov))

Expand Down
4 changes: 2 additions & 2 deletions cmd/stellar-rpc/internal/rpcv2/catalog/census.go
Original file line number Diff line number Diff line change
Expand Up @@ -96,8 +96,8 @@ func (c *Catalog) censusArtifactEntry(key, value string) (string, bool) {
// The builder only ever covers chunks of the key's own index, so a
// cross-window coverage is something no binary wrote. Left accepted,
// a corrupt frozen one would suppress legitimate index rebuilds.
if c.txhashIndex.TxHashIndexID(cov.Lo) != cov.Index ||
c.txhashIndex.TxHashIndexID(cov.Hi) != cov.Index {
if c.TxHashIndexLayout().TxHashIndexID(cov.Lo) != cov.Index ||
c.TxHashIndexLayout().TxHashIndexID(cov.Hi) != cov.Index {
return "index coverage endpoints outside the key's own index", false
}
if !geometry.IsKnownState(geometry.State(value)) {
Expand Down
7 changes: 7 additions & 0 deletions cmd/stellar-rpc/internal/rpcv2/catalog/crashsafety_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ func TestCrashSafety_FileWrittenKeyNotFlipped(t *testing.T) {
require.NoError(t, durable.BarrierNewFile(idxPath))
// <-- crash here: no CommitTxHashIndex.

// The same for a terminal coverage, whose file is under the cold root.
terminal, err := cat.MarkTxHashIndexFreezing(6, 6000, 6999)
require.NoError(t, err)
terminalPath := cat.layout.TxHashIndexFilePath(terminal)
writeArtifact(t, terminalPath)
require.NoError(t, durable.BarrierNewFile(terminalPath))

// INV-3 (disk -> meta): every file on disk has its key.
assertEveryFileHasKey(t, cat, root)

Expand Down
17 changes: 8 additions & 9 deletions cmd/stellar-rpc/internal/rpcv2/catalog/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,7 @@ func testCatalog(t *testing.T) (*Catalog, string) {
metaDir := t.TempDir()
artifactRoot := t.TempDir()

idxLayout, err := geometry.NewTxHashIndexLayout(geometry.ChunksPerTxhashIndex)
require.NoError(t, err)

cat, err := Open(filepath.Join(metaDir, "rocksdb"), geometry.NewLayout(artifactRoot), idxLayout, silentLogger())
cat, err := Open(filepath.Join(metaDir, "rocksdb"), geometry.NewLayout(artifactRoot), silentLogger())
require.NoError(t, err)
t.Cleanup(func() { _ = cat.Close() })

Expand Down Expand Up @@ -76,20 +73,22 @@ func assertEveryFileHasKey(t *testing.T, cat *Catalog, root string) {
func keyForArtifactFile(t *testing.T, cat *Catalog, path string) (string, bool) {
t.Helper()

// Index file: txhash/index/{w}/{lo}-{hi}.idx
dir := filepath.Dir(path)
// Index file: {lo}-{hi}.idx, under the cold index root once terminal and
// under the hot root before; lo names the window either way.
base := filepath.Base(path)
if filepath.Ext(base) == ".idx" {
w, errW := geometry.ParsePadded(filepath.Base(dir))
require.NoError(t, errW)
name := strings.TrimSuffix(base, ".idx")
loStr, hiStr, found := strings.Cut(name, "-")
require.True(t, found, "bad idx name %q", base)
lo, errLo := geometry.ParsePadded(loStr)
require.NoError(t, errLo)
hi, errHi := geometry.ParsePadded(hiStr)
require.NoError(t, errHi)
return geometry.TxHashIndexKey(geometry.TxHashIndexID(w), chunk.ID(lo), chunk.ID(hi)), true
cov := geometry.TxHashIndexCoverage{
Index: cat.TxHashIndexLayout().TxHashIndexID(chunk.ID(lo)), Lo: chunk.ID(lo), Hi: chunk.ID(hi),
}
require.Equal(t, cat.layout.TxHashIndexFilePath(cov), path, "an .idx outside its coverage's directory")
return geometry.TxHashIndexKey(cov.Index, cov.Lo, cov.Hi), true
}

// Per-chunk files: identify by reconstructing each kind's path for the
Expand Down
11 changes: 3 additions & 8 deletions cmd/stellar-rpc/internal/rpcv2/catalog/kv_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,7 @@ import (
// cases); the artifact layout is irrelevant to the KV tests.
func openKVAt(t *testing.T, path string) (*Catalog, error) {
t.Helper()
idxLayout, err := geometry.NewTxHashIndexLayout(geometry.ChunksPerTxhashIndex)
require.NoError(t, err)
return Open(path, geometry.NewLayout(t.TempDir()), idxLayout, silentLogger())
return Open(path, geometry.NewLayout(t.TempDir()), silentLogger())
}

func openTestKV(t *testing.T) *Catalog {
Expand Down Expand Up @@ -54,13 +52,10 @@ func kvGetMiss(t *testing.T, c *Catalog, key string) {
}

func TestOpen_ValidatesInputs(t *testing.T) {
idxLayout, err := geometry.NewTxHashIndexLayout(geometry.ChunksPerTxhashIndex)
require.NoError(t, err)

_, err = Open("", geometry.NewLayout(t.TempDir()), idxLayout, silentLogger())
_, err := Open("", geometry.NewLayout(t.TempDir()), silentLogger())
require.ErrorIs(t, err, rocksdb.ErrInvalidConfig)

_, err = Open(t.TempDir(), geometry.NewLayout(t.TempDir()), idxLayout, nil)
_, err = Open(t.TempDir(), geometry.NewLayout(t.TempDir()), nil)
require.ErrorIs(t, err, rocksdb.ErrInvalidConfig)
}

Expand Down
4 changes: 2 additions & 2 deletions cmd/stellar-rpc/internal/rpcv2/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -500,8 +500,8 @@ func TestRoots_AllDistinct(t *testing.T) {
cfg, err := ParseConfig([]byte(minimalValidConfig))
require.NoError(t, err)
roots := cfg.ResolvePaths().Roots()
// Meta store + five immutable trees + hot storage = seven roots. The
// events pack and its index are separate trees so a deployment can put
// Meta store + five immutable trees + hot storage = seven roots.
// The events pack and its index are separate trees so a deployment can put
// the randomly-probed index on faster storage than the bulk pack.
require.Len(t, roots, 7)
assert.NotContains(t, roots, "/data", "the data dir parent is not itself a root")
Expand Down
11 changes: 7 additions & 4 deletions cmd/stellar-rpc/internal/rpcv2/config/rpc-v2-sample-config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,16 +33,19 @@
default_data_dir = "/var/stellar/rpc-v2"
# Per-store paths, for putting stores on different disks. Relative paths
# resolve against the working directory, and two stores cannot share a path.
# events and events_index move independently. The indexes are small and read
# randomly, so putting events_index on fast local disk speeds up filtered
# With a local NVMe disk and a slower durable volume, put hot and txhash_raw
# (and [ingestion] captive_core_storage_path) on the NVMe disk and keep the
# catalog on the durable volume. The other stores can sit on the slower
# volume. events and events_index move independently: the indexes are small
# and read randomly, so putting events_index on fast disk speeds up filtered
# event queries over wide ranges.
#catalog = "" # {default_data_dir}/catalog/rocksdb (catalog RocksDB)
#ledgers = "" # {default_data_dir}/ledgers (ledger packs)
#events = "" # {default_data_dir}/events/data (event packs)
#events_index = "" # {default_data_dir}/events/index (event indexes)
#txhash_raw = "" # {default_data_dir}/txhash/raw (unindexed tx hashes)
#txhash_index = "" # {default_data_dir}/txhash/index (txhash indexes)
#hot = "" # {default_data_dir}/hot (recent chunks)
#txhash_index = "" # {default_data_dir}/txhash/index (terminal txhash indexes)
#hot = "" # {default_data_dir}/hot (recent chunks, the txhash index still being rebuilt, build scratch)

# -----------------------------------------------------------------------------
# [retention]: how much history this daemon keeps
Expand Down
2 changes: 1 addition & 1 deletion cmd/stellar-rpc/internal/rpcv2/daemon.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ func openCatalog(paths config.Paths, opts daemonOptions, logger *supportlog.Entr
if err != nil {
return nil, err
}
cat, err := catalog.Open(paths.Catalog, config.NewLayoutFromPaths(paths), txLayout, logger)
cat, err := catalog.Open(paths.Catalog, config.NewLayoutFromPaths(paths).WithTxHashIndex(txLayout), logger)
if err != nil {
return nil, fmt.Errorf("open catalog %q: %w", paths.Catalog, err)
}
Expand Down
5 changes: 1 addition & 4 deletions cmd/stellar-rpc/internal/rpcv2/daemon_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,7 @@ import (
// read-back assertions (closed via t.Cleanup).
func openCatalogAt(t *testing.T, dataDir string) *catalog.Catalog {
t.Helper()
txLayout, err := geometry.NewTxHashIndexLayout(geometry.ChunksPerTxhashIndex)
require.NoError(t, err)
cat, err := catalog.Open(
filepath.Join(dataDir, "catalog", "rocksdb"), geometry.NewLayout(dataDir), txLayout, silentLogger())
cat, err := catalog.Open(filepath.Join(dataDir, "catalog", "rocksdb"), geometry.NewLayout(dataDir), silentLogger())
require.NoError(t, err)
t.Cleanup(func() { _ = cat.Close() })
return cat
Expand Down
2 changes: 1 addition & 1 deletion cmd/stellar-rpc/internal/rpcv2/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -528,7 +528,7 @@ func e2eReadCatalog(t *testing.T, dataDir string) (*catalog.Catalog, func()) {
paths := config.Config{Storage: config.StorageConfig{DefaultDataDir: dataDir}}.WithDefaults().ResolvePaths()
windows, err := geometry.NewTxHashIndexLayout(1) // matches chunksPerTxhashIndex = 1
require.NoError(t, err)
cat, err := catalog.Open(paths.Catalog, config.NewLayoutFromPaths(paths), windows, silentLogger())
cat, err := catalog.Open(paths.Catalog, config.NewLayoutFromPaths(paths).WithTxHashIndex(windows), silentLogger())
require.NoError(t, err)
return cat, func() { _ = cat.Close() }
}
Expand Down
20 changes: 17 additions & 3 deletions cmd/stellar-rpc/internal/rpcv2/geometry/keys_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"github.com/stretchr/testify/require"

"github.com/stellar/stellar-rpc/cmd/stellar-rpc/internal/rpcv2/chunk"
"github.com/stellar/stellar-rpc/cmd/stellar-rpc/internal/rpcv2/stores/event"
)

// ---------------------------------------------------------------------------
Expand Down Expand Up @@ -57,13 +58,26 @@ func TestKeyToPathBijection(t *testing.T) {
"/data/events/index/00005/00005350-index.pack",
"/data/events/index/00005/00005350-index.hash",
}, l.EventsPaths(5350))
require.Equal(t, []string{"/data/events/index/00005/00005350-index.runs"}, l.ScratchPaths(5350, KindEvents))
require.Equal(t, []string{"/data/hot/scratch/00005350-index.runs"}, l.ScratchPaths(5350, KindEvents))
require.Equal(t, event.ColdDirs{
Data: "/data/events/data/00005", Index: "/data/events/index/00005", Scratch: "/data/hot/scratch",
}, l.EventsColdDirs(5350))
require.Nil(t, l.ScratchPaths(5350, KindLedgers))
require.Equal(t, "/data/hot/00005350", l.HotChunkPath(5350))

// A window still being rebuilt lives with the hot tier; its terminal
// index is a cold artifact.
cov := TxHashIndexCoverage{Index: 5, Lo: 5100, Hi: 5349}
require.Equal(t, "/data/txhash/index/00000005", l.TxHashIndexDir(cov.Index))
require.Equal(t, "/data/txhash/index/00000005/00005100-00005349.idx", l.TxHashIndexFilePath(cov))
require.Equal(t, "/data/hot/txhash-index-00000005", l.TxHashIndexDir(cov))
require.Equal(t, "/data/hot/txhash-index-00000005/00005100-00005349.idx", l.TxHashIndexFilePath(cov))
terminal := TxHashIndexCoverage{Index: 5, Lo: 5100, Hi: 5999}
require.Equal(t, "/data/txhash/index/00000005", l.TxHashIndexDir(terminal))
require.Equal(t, "/data/txhash/index/00000005/00005100-00005999.idx", l.TxHashIndexFilePath(terminal))
// The width decides what is terminal, so it decides the placement.
w4, err := NewTxHashIndexLayout(4)
require.NoError(t, err)
require.Equal(t, "/data/txhash/index/00000001",
l.WithTxHashIndex(w4).TxHashIndexDir(TxHashIndexCoverage{Index: 1, Lo: 4, Hi: 7}))
}

func TestParseRejectsMalformed(t *testing.T) {
Expand Down
Loading
Loading