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		LamportClock: NewLamportClock(),
18		filePath:     filePath,
19	}
20	return clock
21}
22
23func LoadPersistedLamport(filePath string) (*PersistedLamport, error) {
24	clock := &PersistedLamport{
25		filePath: filePath,
26	}
27
28	err := clock.read()
29	if err != nil {
30		return nil, err
31	}
32
33	return clock, nil
34}
35
36func (c *PersistedLamport) Increment() (LamportTime, error) {
37	time := c.LamportClock.Increment()
38	return time, c.Write()
39}
40
41func (c *PersistedLamport) Witness(time LamportTime) error {
42	// TODO: rework so that we write only when the clock was actually updated
43	c.LamportClock.Witness(time)
44	return c.Write()
45}
46
47func (c *PersistedLamport) read() error {
48	content, err := ioutil.ReadFile(c.filePath)
49	if err != nil {
50		return err
51	}
52
53	var value uint64
54	n, err := fmt.Sscanf(string(content), "%d", &value)
55
56	if err != nil {
57		return err
58	}
59
60	if n != 1 {
61		return fmt.Errorf("could not read the clock")
62	}
63
64	c.LamportClock = NewLamportClockWithTime(value)
65
66	return nil
67}
68
69func (c *PersistedLamport) Write() error {
70	dir := filepath.Dir(c.filePath)
71	err := os.MkdirAll(dir, 0777)
72	if err != nil {
73		return err
74	}
75
76	data := []byte(fmt.Sprintf("%d", c.counter))
77	return ioutil.WriteFile(c.filePath, data, 0644)
78}