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  }