carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package registry
2
3import (
4 "path/filepath"
5 "sync"
6 "testing"
7 "time"
8)
9
10// A generation is never handed out twice by one registry file, across a
11// close and reopen (an agent restart) and whatever the clock says: a
12// rollback resumed after a restart compares and lifts by the generation it
13// stored before it, so a later fence must never carry the same number.
14func TestNextFenceGenerationIsUniqueAcrossRestarts(t *testing.T) {
15 path := filepath.Join(t.TempDir(), "registry.db")
16 reg, err := Open(path)
17 if err != nil {
18 t.Fatal(err)
19 }
20 now := time.Unix(1_800_000_000, 0)
21 before := map[uint64]bool{}
22 var last uint64
23 for i := 0; i < 5; i++ {
24 g, err := reg.NextFenceGeneration(now) // the same instant: still distinct
25 if err != nil {
26 t.Fatal(err)
27 }
28 if g == 0 || g <= last {
29 t.Fatalf("generation %d after %d: want nonzero and rising", g, last)
30 }
31 before[g], last = true, g
32 }
33 if err := reg.Close(); err != nil {
34 t.Fatal(err)
35 }
36
37 reg, err = Open(path)
38 if err != nil {
39 t.Fatal(err)
40 }
41 defer reg.Close()
42 // The clock went back across the restart (a box that booted before NTP
43 // synced): the generations still rise past every one handed out before.
44 for _, at := range []time.Time{now.Add(-time.Hour), now, time.Unix(0, 0), now.Add(-time.Nanosecond)} {
45 g, err := reg.NextFenceGeneration(at)
46 if err != nil {
47 t.Fatal(err)
48 }
49 if before[g] || g <= last {
50 t.Fatalf("after the restart, at %v: generation %d (last before %d)", at, g, last)
51 }
52 last = g
53 }
54 // A clock ahead of every earlier generation is followed: generations
55 // stay in wall-clock nanoseconds, the space the layout pass and the
56 // moves cut draw theirs from.
57 later := now.Add(time.Hour)
58 if g, err := reg.NextFenceGeneration(later); err != nil || g != uint64(later.UnixNano()) {
59 t.Fatalf("a clock ahead: generation %d, %v; want %d", g, err, later.UnixNano())
60 }
61}
62
63func TestNextFenceGenerationConcurrentCallersNeverShare(t *testing.T) {
64 reg := openTestRegistry(t)
65 now := time.Unix(1_800_000_000, 0)
66 const n = 40
67 gens := make(chan uint64, n)
68 var wg sync.WaitGroup
69 for i := 0; i < n; i++ {
70 wg.Add(1)
71 go func() {
72 defer wg.Done()
73 g, err := reg.NextFenceGeneration(now)
74 if err != nil {
75 t.Error(err)
76 return
77 }
78 gens <- g
79 }()
80 }
81 wg.Wait()
82 close(gens)
83 seen := map[uint64]bool{}
84 for g := range gens {
85 if seen[g] {
86 t.Fatalf("generation %d handed out twice", g)
87 }
88 seen[g] = true
89 }
90}
91