mirror of
https://github.com/tailscale/tailscale.git
synced 2025-10-09 08:01:31 +00:00
tka: implement filesystem-based tailchonk implementation
FS implements Chonk, and given the expected load characteristics (frequent use of AUM() + ChildAUMs(), and infrequent use of Heads() + CommitVerifiedAUMs()), the implementation avoids scanning the filesystem to service AUM() and ChildAUMs(). Signed-off-by: Tom DNetto <tom@tailscale.com>
This commit is contained in:
@@ -5,6 +5,9 @@
|
||||
package tka
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"github.com/google/go-cmp/cmp"
|
||||
@@ -20,35 +23,38 @@ func randHash(t *testing.T, seed int64) [blake2s.Size]byte {
|
||||
}
|
||||
|
||||
func TestImplementsChonk(t *testing.T) {
|
||||
impls := []Chonk{&Mem{}}
|
||||
impls := []Chonk{&Mem{}, &FS{}}
|
||||
t.Logf("chonks: %v", impls)
|
||||
}
|
||||
|
||||
func TestTailchonkMem_ChildAUMs(t *testing.T) {
|
||||
chonk := Mem{}
|
||||
parentHash := randHash(t, 1)
|
||||
data := []AUM{
|
||||
{
|
||||
MessageKind: AUMRemoveKey,
|
||||
KeyID: []byte{1, 2},
|
||||
PrevAUMHash: parentHash[:],
|
||||
},
|
||||
{
|
||||
MessageKind: AUMRemoveKey,
|
||||
KeyID: []byte{3, 4},
|
||||
PrevAUMHash: parentHash[:],
|
||||
},
|
||||
}
|
||||
func TestTailchonk_ChildAUMs(t *testing.T) {
|
||||
for _, chonk := range []Chonk{&Mem{}, &FS{base: t.TempDir()}} {
|
||||
t.Run(fmt.Sprintf("%T", chonk), func(t *testing.T) {
|
||||
parentHash := randHash(t, 1)
|
||||
data := []AUM{
|
||||
{
|
||||
MessageKind: AUMRemoveKey,
|
||||
KeyID: []byte{1, 2},
|
||||
PrevAUMHash: parentHash[:],
|
||||
},
|
||||
{
|
||||
MessageKind: AUMRemoveKey,
|
||||
KeyID: []byte{3, 4},
|
||||
PrevAUMHash: parentHash[:],
|
||||
},
|
||||
}
|
||||
|
||||
if err := chonk.CommitVerifiedAUMs(data); err != nil {
|
||||
t.Fatalf("CommitVerifiedAUMs failed: %v", err)
|
||||
}
|
||||
stored, err := chonk.ChildAUMs(parentHash)
|
||||
if err != nil {
|
||||
t.Fatalf("ChildAUMs failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(data, stored); diff != "" {
|
||||
t.Errorf("stored AUM differs (-want, +got):\n%s", diff)
|
||||
if err := chonk.CommitVerifiedAUMs(data); err != nil {
|
||||
t.Fatalf("CommitVerifiedAUMs failed: %v", err)
|
||||
}
|
||||
stored, err := chonk.ChildAUMs(parentHash)
|
||||
if err != nil {
|
||||
t.Fatalf("ChildAUMs failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(data, stored); diff != "" {
|
||||
t.Errorf("stored AUM differs (-want, +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,50 +85,74 @@ func TestTailchonkMem_Orphans(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestTailchonkMem_ReadChainFromHead(t *testing.T) {
|
||||
chonk := Mem{}
|
||||
genesis := AUM{MessageKind: AUMRemoveKey, KeyID: []byte{1, 2}}
|
||||
gHash := genesis.Hash()
|
||||
intermediate := AUM{PrevAUMHash: gHash[:]}
|
||||
iHash := intermediate.Hash()
|
||||
leaf := AUM{PrevAUMHash: iHash[:]}
|
||||
func TestTailchonk_ReadChainFromHead(t *testing.T) {
|
||||
for _, chonk := range []Chonk{&Mem{}, &FS{base: t.TempDir()}} {
|
||||
|
||||
commitSet := []AUM{
|
||||
genesis,
|
||||
intermediate,
|
||||
leaf,
|
||||
}
|
||||
if err := chonk.CommitVerifiedAUMs(commitSet); err != nil {
|
||||
t.Fatalf("CommitVerifiedAUMs failed: %v", err)
|
||||
}
|
||||
// t.Logf("genesis hash = %X", genesis.Hash())
|
||||
// t.Logf("intermediate hash = %X", intermediate.Hash())
|
||||
// t.Logf("leaf hash = %X", leaf.Hash())
|
||||
t.Run(fmt.Sprintf("%T", chonk), func(t *testing.T) {
|
||||
genesis := AUM{MessageKind: AUMRemoveKey, KeyID: []byte{1, 2}}
|
||||
gHash := genesis.Hash()
|
||||
intermediate := AUM{PrevAUMHash: gHash[:]}
|
||||
iHash := intermediate.Hash()
|
||||
leaf := AUM{PrevAUMHash: iHash[:]}
|
||||
|
||||
// Read the chain from the leaf backwards.
|
||||
gotLeafs, err := chonk.Heads()
|
||||
if err != nil {
|
||||
t.Fatalf("Heads failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff([]AUM{leaf}, gotLeafs); diff != "" {
|
||||
t.Fatalf("leaf AUM differs (-want, +got):\n%s", diff)
|
||||
}
|
||||
commitSet := []AUM{
|
||||
genesis,
|
||||
intermediate,
|
||||
leaf,
|
||||
}
|
||||
if err := chonk.CommitVerifiedAUMs(commitSet); err != nil {
|
||||
t.Fatalf("CommitVerifiedAUMs failed: %v", err)
|
||||
}
|
||||
// t.Logf("genesis hash = %X", genesis.Hash())
|
||||
// t.Logf("intermediate hash = %X", intermediate.Hash())
|
||||
// t.Logf("leaf hash = %X", leaf.Hash())
|
||||
|
||||
parent, _ := gotLeafs[0].Parent()
|
||||
gotIntermediate, err := chonk.AUM(parent)
|
||||
if err != nil {
|
||||
t.Fatalf("AUM(<intermediate>) failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(intermediate, gotIntermediate); diff != "" {
|
||||
t.Errorf("intermediate AUM differs (-want, +got):\n%s", diff)
|
||||
}
|
||||
// Read the chain from the leaf backwards.
|
||||
gotLeafs, err := chonk.Heads()
|
||||
if err != nil {
|
||||
t.Fatalf("Heads failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff([]AUM{leaf}, gotLeafs); diff != "" {
|
||||
t.Fatalf("leaf AUM differs (-want, +got):\n%s", diff)
|
||||
}
|
||||
|
||||
parent, _ = gotIntermediate.Parent()
|
||||
gotGenesis, err := chonk.AUM(parent)
|
||||
if err != nil {
|
||||
t.Fatalf("AUM(<genesis>) failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(genesis, gotGenesis); diff != "" {
|
||||
t.Errorf("genesis AUM differs (-want, +got):\n%s", diff)
|
||||
parent, _ := gotLeafs[0].Parent()
|
||||
gotIntermediate, err := chonk.AUM(parent)
|
||||
if err != nil {
|
||||
t.Fatalf("AUM(<intermediate>) failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(intermediate, gotIntermediate); diff != "" {
|
||||
t.Errorf("intermediate AUM differs (-want, +got):\n%s", diff)
|
||||
}
|
||||
|
||||
parent, _ = gotIntermediate.Parent()
|
||||
gotGenesis, err := chonk.AUM(parent)
|
||||
if err != nil {
|
||||
t.Fatalf("AUM(<genesis>) failed: %v", err)
|
||||
}
|
||||
if diff := cmp.Diff(genesis, gotGenesis); diff != "" {
|
||||
t.Errorf("genesis AUM differs (-want, +got):\n%s", diff)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestTailchonkFS_Commit(t *testing.T) {
|
||||
chonk := &FS{base: t.TempDir()}
|
||||
parentHash := randHash(t, 1)
|
||||
aum := AUM{MessageKind: AUMNoOp, PrevAUMHash: parentHash[:]}
|
||||
|
||||
if err := chonk.CommitVerifiedAUMs([]AUM{aum}); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if got, want := chonk.filename(aum.Hash()), "HJX3LPJJQVRFSQX4QONESBU4DUO5JPORA66ZUCFS6NHZWDZTP4"; got != want {
|
||||
t.Errorf("aum filename = %q, want %q", got, want)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(chonk.base, "ad", "HJX3LPJJQVRFSQX4QONESBU4DUO5JPORA66ZUCFS6NHZWDZTP4")); err != nil {
|
||||
t.Errorf("stat of AUM file failed: %v", err)
|
||||
}
|
||||
if _, err := os.Stat(filepath.Join(chonk.base, "67", "226TIYPDKQWKFD5MXUI3GRVDSDFXRBABNINTFIT5ADMCLZ464U")); err != nil {
|
||||
t.Errorf("stat of AUM parent failed: %v", err)
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user