-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathversions.go
106 lines (90 loc) · 2.98 KB
/
versions.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
package honu
import (
"errors"
"fmt"
"net"
"github.com/rotationalio/honu/config"
pb "github.com/rotationalio/honu/object"
)
// NewVersionManager creates a new manager for handling lamport scalar versions.
func NewVersionManager(conf config.ReplicaConfig) (v *VersionManager, err error) {
// Make sure we don't create a VersionManager that is unable to do its job.
if conf.PID == 0 || conf.Region == "" {
return nil, errors.New("improperly configured: version manager requires PID and Region")
}
v = &VersionManager{PID: conf.PID, Region: conf.Region}
// Compute the owner name
if conf.Name != "" {
// The common name
v.Owner = fmt.Sprintf("%d:%s", conf.PID, conf.Name)
} else {
// Check to see if there is a domain name in the bindaddr
var host string
if host, _, err = net.SplitHostPort(conf.BindAddr); err == nil {
v.Owner = fmt.Sprintf("%d:%s", conf.PID, host)
} else {
// The owner name is just the pid:region in the last case
v.Owner = fmt.Sprintf("%d:%s", conf.PID, conf.Region)
}
}
return v, nil
}
// VersionManager is configured with information associated with the local Replica in
// order to correctly implement Lamport clocks for sequential, conflict-free replicated
// versions.
type VersionManager struct {
PID uint64
Owner string
Region string
}
// Update the version of an object in place.
// If the object was previously a tombstone (e.g. deleted) then it is "undeleted".
func (v VersionManager) Update(meta *pb.Object) error {
if meta == nil {
return errors.New("cannot update version on empty object")
}
// Update the parent to the current version of the object.
if meta.Version != nil && !meta.Version.IsZero() {
meta.Version.Parent = &pb.Version{
Pid: meta.Version.Pid,
Version: meta.Version.Version,
Region: meta.Version.Region,
}
} else {
// This is the first version of the object. Also set provenance on the object.
meta.Version = &pb.Version{}
meta.Region = v.Region
meta.Owner = v.Owner
}
// Update the version to the new version of the local version manager
meta.Version.Pid = v.PID
meta.Version.Version++
meta.Version.Region = v.Region
// Undelete the version if it was a Tombstone before
meta.Version.Tombstone = false
return nil
}
// Delete creates a tombstone version of the object in place.
func (v VersionManager) Delete(meta *pb.Object) error {
if meta == nil {
return errors.New("cannot create tombstone version on empty object")
}
if meta.Version == nil || meta.Version.IsZero() {
// This is the first version of the object, it cannot be deleted.
return errors.New("cannot delete version that doesn't exist yet")
}
// Cannot delete a tombstone
if meta.Version.Tombstone {
return errors.New("cannot delete an already deleted object")
}
meta.Version.Parent = &pb.Version{
Pid: meta.Version.Pid,
Version: meta.Version.Version,
Region: meta.Version.Region,
}
meta.Version.Pid = v.PID
meta.Version.Version++
meta.Version.Region = v.Region
meta.Version.Tombstone = true
return nil
}