github.com/sunvim/utils@v0.1.0/lamport/persisted_clock.go (about) 1 package lamport 2 3 import ( 4 "errors" 5 "fmt" 6 "io/ioutil" 7 "os" 8 9 "github.com/go-git/go-billy/v5" 10 "github.com/go-git/go-billy/v5/util" 11 ) 12 13 var ErrClockNotExist = errors.New("clock doesn't exist") 14 15 type PersistedClock struct { 16 *MemClock 17 root billy.Filesystem 18 filePath string 19 } 20 21 // NewPersistedClock create a new persisted Lamport clock 22 func NewPersistedClock(root billy.Filesystem, filePath string) (*PersistedClock, error) { 23 clock := &PersistedClock{ 24 MemClock: NewMemClock(), 25 root: root, 26 filePath: filePath, 27 } 28 29 err := clock.Write() 30 if err != nil { 31 return nil, err 32 } 33 34 return clock, nil 35 } 36 37 // LoadPersistedClock load a persisted Lamport clock from a file 38 func LoadPersistedClock(root billy.Filesystem, filePath string) (*PersistedClock, error) { 39 clock := &PersistedClock{ 40 root: root, 41 filePath: filePath, 42 } 43 44 err := clock.read() 45 if err != nil { 46 return nil, err 47 } 48 49 return clock, nil 50 } 51 52 // Increment is used to return the value of the lamport clock and increment it afterwards 53 func (pc *PersistedClock) Increment() (Time, error) { 54 time, err := pc.MemClock.Increment() 55 if err != nil { 56 return 0, err 57 } 58 return time, pc.Write() 59 } 60 61 // Witness is called to update our local clock if necessary after 62 // witnessing a clock value received from another process 63 func (pc *PersistedClock) Witness(time Time) error { 64 // TODO: rework so that we write only when the clock was actually updated 65 err := pc.MemClock.Witness(time) 66 if err != nil { 67 return err 68 } 69 return pc.Write() 70 } 71 72 func (pc *PersistedClock) read() error { 73 f, err := pc.root.Open(pc.filePath) 74 if os.IsNotExist(err) { 75 return ErrClockNotExist 76 } 77 if err != nil { 78 return err 79 } 80 defer f.Close() 81 82 content, err := ioutil.ReadAll(f) 83 if err != nil { 84 return err 85 } 86 87 var value uint64 88 n, err := fmt.Sscanf(string(content), "%d", &value) 89 if err != nil { 90 return err 91 } 92 93 if n != 1 { 94 return fmt.Errorf("could not read the clock") 95 } 96 97 pc.MemClock = NewMemClockWithTime(value) 98 99 return nil 100 } 101 102 func (pc *PersistedClock) Write() error { 103 data := []byte(fmt.Sprintf("%d", pc.counter)) 104 return util.WriteFile(pc.root, pc.filePath, data, 0644) 105 }