1package util
2
3import (
4 "fmt"
5 "io/ioutil"
6 "os"
7 "path/filepath"
8)
9
10type PersistedLamport struct {
11 LamportClock
12 filePath string
13}
14
15func NewPersistedLamport(filePath string) *PersistedLamport {
16 clock := &PersistedLamport{
17 filePath: filePath,
18 }
19 return clock
20}
21
22func LoadPersistedLamport(filePath string) (*PersistedLamport, error) {
23 clock := &PersistedLamport{
24 filePath: filePath,
25 }
26
27 err := clock.read()
28 if err != nil {
29 return nil, err
30 }
31
32 return clock, nil
33}
34
35func (c *PersistedLamport) Witness(time LamportTime) error {
36 c.LamportClock.Witness(time)
37 return c.Write()
38}
39
40func (c *PersistedLamport) Time() LamportTime {
41 // Equivalent to:
42 //
43 // res = c.LamportClock.Time()
44 // bugClock.Increment()
45 //
46 // ... but thread safe
47 return c.Increment() - 1
48}
49
50func (c *PersistedLamport) read() error {
51 content, err := ioutil.ReadFile(c.filePath)
52 if err != nil {
53 return err
54 }
55
56 var value uint64
57 n, err := fmt.Sscanf(string(content), "%d", &value)
58
59 if err != nil {
60 return err
61 }
62
63 if n != 1 {
64 return fmt.Errorf("could not read the clock")
65 }
66
67 c.LamportClock = NewLamportClockWithTime(value)
68
69 return nil
70}
71
72func (c *PersistedLamport) Write() error {
73 dir := filepath.Dir(c.filePath)
74 err := os.MkdirAll(dir, 0777)
75 if err != nil {
76 return err
77 }
78
79 data := []byte(fmt.Sprintf("%d", c.LamportClock.Time()))
80 return ioutil.WriteFile(c.filePath, data, 0644)
81}