diff options
Diffstat (limited to 'util/lamport/persisted_clock.go')
-rw-r--r-- | util/lamport/persisted_clock.go | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/util/lamport/persisted_clock.go b/util/lamport/persisted_clock.go new file mode 100644 index 00000000..e70b01ef --- /dev/null +++ b/util/lamport/persisted_clock.go @@ -0,0 +1,100 @@ +package lamport + +import ( + "errors" + "fmt" + "io/ioutil" + "os" + "path/filepath" +) + +var ErrClockNotExist = errors.New("clock doesn't exist") + +type PersistedClock struct { + *MemClock + filePath string +} + +// NewPersistedClock create a new persisted Lamport clock +func NewPersistedClock(filePath string) (*PersistedClock, error) { + clock := &PersistedClock{ + MemClock: NewMemClock(), + filePath: filePath, + } + + dir := filepath.Dir(filePath) + err := os.MkdirAll(dir, 0777) + if err != nil { + return nil, err + } + + err = clock.Write() + if err != nil { + return nil, err + } + + return clock, nil +} + +// LoadPersistedClock load a persisted Lamport clock from a file +func LoadPersistedClock(filePath string) (*PersistedClock, error) { + clock := &PersistedClock{ + filePath: filePath, + } + + err := clock.read() + if err != nil { + return nil, err + } + + return clock, nil +} + +// Increment is used to return the value of the lamport clock and increment it afterwards +func (pc *PersistedClock) Increment() (Time, error) { + time, err := pc.MemClock.Increment() + if err != nil { + return 0, err + } + return time, pc.Write() +} + +// Witness is called to update our local clock if necessary after +// witnessing a clock value received from another process +func (pc *PersistedClock) Witness(time Time) error { + // TODO: rework so that we write only when the clock was actually updated + err := pc.MemClock.Witness(time) + if err != nil { + return err + } + return pc.Write() +} + +func (pc *PersistedClock) read() error { + content, err := ioutil.ReadFile(pc.filePath) + if os.IsNotExist(err) { + return ErrClockNotExist + } + if err != nil { + return err + } + + var value uint64 + n, err := fmt.Sscanf(string(content), "%d", &value) + if err != nil { + return err + } + + if n != 1 { + return fmt.Errorf("could not read the clock") + } + + pc.MemClock = NewMemClockWithTime(value) + + return nil +} + +func (pc *PersistedClock) Write() error { + data := []byte(fmt.Sprintf("%d", pc.counter)) + return ioutil.WriteFile(pc.filePath, data, 0644) +} |