Skip to content

Commit

Permalink
Make paths adhere to the spec, and reason about them in tile-space (#38)
Browse files Browse the repository at this point in the history
  • Loading branch information
AlCutter authored Jul 8, 2024
1 parent 2e3620b commit ce560a3
Show file tree
Hide file tree
Showing 2 changed files with 75 additions and 32 deletions.
50 changes: 28 additions & 22 deletions api/layout/paths.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,40 +19,46 @@ package layout

import (
"fmt"
"path/filepath"
)

const (
// CheckpointPath is the location of the file containing the log checkpoint.
CheckpointPath = "checkpoint"
)

// EntriesPath builds the local path at which the leaf with the given index lives in.
// EntriesPathForLogIndex builds the local path at which the leaf with the given index lives in.
// Note that this will be an entry bundle containing up to 256 entries and thus multiple
// indices can map to the same output path.
//
// TODO(mhutchinson): revisit to consider how partial tile suffixes should be added.
func EntriesPath(seq uint64) string {
seq = seq / 256
frag := []string{
"tile",
"entries",
fmt.Sprintf("x%03x", (seq>>16)&0xff),
fmt.Sprintf("x%03x", (seq>>8)&0xff),
fmt.Sprintf("%03x", seq&0xff),
}
return filepath.Join(frag...)
func EntriesPathForLogIndex(seq uint64) string {
return EntriesPath(seq / 256)
}

// EntriesPath returns the local path for the Nth entry bundle.
func EntriesPath(N uint64) string {
return fmt.Sprintf("tile/entries%s", fmtN(N))
}

// TilePath builds the path to the subtree tile with the given level and index.
func TilePath(level, index uint64) string {
seq := index / 256
frag := []string{
"tile",
fmt.Sprintf("%d", level),
fmt.Sprintf("x%03x", (seq>>16)&0xff),
fmt.Sprintf("x%03x", (seq>>8)&0xff),
fmt.Sprintf("%03x", seq&0xff),
// TilePath builds the path to the subtree tile with the given level and index in tile space.
func TilePath(tileLevel, tileIndex uint64) string {
return fmt.Sprintf("tile/%d%s", tileLevel, fmtN(tileIndex))
}

// fmtN returns the "N" part of a Tiles-spec path.
//
// N is grouped into chunks of 3 decimal digits, starting with the most significant digit, and
// padding with zeroes as necessary.
// Digit groups are prefixed with "x", except for the least-significant group which has no prefix,
// and separated with slashes.
//
// See https://github.com/C2SP/C2SP/blob/main/tlog-tiles.md#:~:text=index%201234067%20will%20be%20encoded%20as%20x001/x234/067
func fmtN(N uint64) string {
n := fmt.Sprintf("/%03d", N%1000)
N /= 1000
for N > 0 {
n = fmt.Sprintf("/x%03d%s", N%1000, n)
N /= 1000
}
return filepath.Join(frag...)
return n
}
57 changes: 47 additions & 10 deletions api/layout/paths_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,28 +19,57 @@ import (
"testing"
)

func TestEntriesPath(t *testing.T) {
func TestEntriesPathForLogIndex(t *testing.T) {
for _, test := range []struct {
seq uint64
wantPath string
}{
{
seq: 0,
wantPath: "tile/entries/x000/x000/000",
wantPath: "tile/entries/000",
}, {
seq: 255,
wantPath: "tile/entries/x000/x000/000",
wantPath: "tile/entries/000",
}, {
seq: 256,
wantPath: "tile/entries/x000/x000/001",
wantPath: "tile/entries/001",
}, {
seq: 0xffeeddccbb,
wantPath: "tile/entries/x0ee/x0dd/0cc",
seq: 123456789 * 256,
wantPath: "tile/entries/x123/x456/789",
},
} {
desc := fmt.Sprintf("seq %d", test.seq)
t.Run(desc, func(t *testing.T) {
gotPath := EntriesPath(test.seq)
gotPath := EntriesPathForLogIndex(test.seq)
if gotPath != test.wantPath {
t.Errorf("got file %q want %q", gotPath, test.wantPath)
}
})
}
}

func TestEntriesPath(t *testing.T) {
for _, test := range []struct {
N uint64
wantPath string
}{
{
N: 0,
wantPath: "tile/entries/000",
}, {
N: 255,
wantPath: "tile/entries/255",
}, {
N: 256,
wantPath: "tile/entries/256",
}, {
N: 123456789000,
wantPath: "tile/entries/x123/x456/x789/000",
},
} {
desc := fmt.Sprintf("N %d", test.N)
t.Run(desc, func(t *testing.T) {
gotPath := EntriesPath(test.N)
if gotPath != test.wantPath {
t.Errorf("got file %q want %q", gotPath, test.wantPath)
}
Expand All @@ -57,11 +86,19 @@ func TestTilePath(t *testing.T) {
{
level: 0,
index: 0,
wantPath: "tile/0/x000/x000/000",
wantPath: "tile/0/000",
}, {
level: 15,
index: 455667,
wantPath: "tile/15/x455/667",
}, {
level: 3,
index: 1234567,
wantPath: "tile/3/x001/x234/567",
}, {
level: 15,
index: 0x455667,
wantPath: "tile/15/x000/x045/056",
index: 123456789,
wantPath: "tile/15/x123/x456/789",
},
} {
desc := fmt.Sprintf("level %x index %x", test.level, test.index)
Expand Down

0 comments on commit ce560a3

Please sign in to comment.