syncthing/lib/protocol/vector.go

197 lines
4.9 KiB
Go
Raw Normal View History

2015-03-20 01:58:32 -07:00
// Copyright (C) 2015 The Protocol Authors.
package protocol
2015-09-22 12:51:05 -07:00
// The Vector type represents a version vector. The zero value is a usable
2015-03-20 01:58:32 -07:00
// version vector. The vector has slice semantics and some operations on it
2015-09-22 11:34:24 -07:00
// are "append-like" in that they may return the same vector modified, or v
2015-03-20 01:58:32 -07:00
// new allocated Vector with the modified contents.
2015-09-22 12:51:05 -07:00
// Counter represents a single counter in the version vector.
2015-03-20 01:58:32 -07:00
2015-09-22 12:51:05 -07:00
// Update returns a Vector with the index for the specific ID incremented by
2015-03-20 01:58:32 -07:00
// one. If it is possible, the vector v is updated and returned. If it is not,
2015-09-22 12:51:05 -07:00
// a copy will be created, updated and returned.
func (v Vector) Update(id ShortID) Vector {
for i := range v.Counters {
if v.Counters[i].ID == id {
2015-03-20 01:58:32 -07:00
// Update an existing index
v.Counters[i].Value++
2015-03-20 01:58:32 -07:00
return v
} else if v.Counters[i].ID > id {
2015-09-22 12:51:05 -07:00
// Insert a new index
nv := make([]Counter, len(v.Counters)+1)
copy(nv, v.Counters[:i])
nv[i].ID = id
2015-03-20 01:58:32 -07:00
nv[i].Value = 1
copy(nv[i+1:], v.Counters[i:])
return Vector{nv}
2015-03-20 01:58:32 -07:00
}
}
2015-09-22 12:51:05 -07:00
// Append a new index
return Vector{append(v.Counters, Counter{id, 1})}
2015-03-20 01:58:32 -07:00
}
2015-09-22 11:34:24 -07:00
// Merge returns the vector containing the maximum indexes from v and b. If it
2015-09-22 12:51:05 -07:00
// is possible, the vector v is updated and returned. If it is not, a copy
2015-03-20 01:58:32 -07:00
// will be created, updated and returned.
2015-09-22 11:34:24 -07:00
func (v Vector) Merge(b Vector) Vector {
var vi, bi int
for bi < len(b.Counters) {
if vi == len(v.Counters) {
2015-09-22 11:34:24 -07:00
// We've reach the end of v, all that remains are appends
return Vector{append(v.Counters, b.Counters[bi:]...)}
2015-03-20 01:58:32 -07:00
}
if v.Counters[vi].ID > b.Counters[bi].ID {
2015-03-20 01:58:32 -07:00
// The index from b should be inserted here
n := make([]Counter, len(v.Counters)+1)
copy(n, v.Counters[:vi])
n[vi] = b.Counters[bi]
copy(n[vi+1:], v.Counters[vi:])
v.Counters = n
2015-03-20 01:58:32 -07:00
}
if v.Counters[vi].ID == b.Counters[bi].ID {
if val := b.Counters[bi].Value; val > v.Counters[vi].Value {
v.Counters[vi].Value = val
2015-03-20 01:58:32 -07:00
}
}
if bi < len(b.Counters) && v.Counters[vi].ID == b.Counters[bi].ID {
2015-03-20 01:58:32 -07:00
bi++
}
2015-09-22 11:34:24 -07:00
vi++
2015-03-20 01:58:32 -07:00
}
2015-09-22 11:34:24 -07:00
return v
2015-03-20 01:58:32 -07:00
}
// Copy returns an identical vector that is not shared with v.
func (v Vector) Copy() Vector {
nv := make([]Counter, len(v.Counters))
copy(nv, v.Counters)
return Vector{nv}
2015-03-20 01:58:32 -07:00
}
// Equal returns true when the two vectors are equivalent.
2015-09-22 11:34:24 -07:00
func (v Vector) Equal(b Vector) bool {
return v.Compare(b) == Equal
2015-03-20 01:58:32 -07:00
}
2015-09-22 11:34:24 -07:00
// LesserEqual returns true when the two vectors are equivalent or v is Lesser
2015-03-20 01:58:32 -07:00
// than b.
2015-09-22 11:34:24 -07:00
func (v Vector) LesserEqual(b Vector) bool {
comp := v.Compare(b)
2015-03-20 01:58:32 -07:00
return comp == Lesser || comp == Equal
}
2015-09-22 11:34:24 -07:00
// GreaterEqual returns true when the two vectors are equivalent or v is Greater
2015-03-20 01:58:32 -07:00
// than b.
2015-09-22 11:34:24 -07:00
func (v Vector) GreaterEqual(b Vector) bool {
comp := v.Compare(b)
2015-03-20 01:58:32 -07:00
return comp == Greater || comp == Equal
}
// Concurrent returns true when the two vectors are concurrent.
2015-09-22 11:34:24 -07:00
func (v Vector) Concurrent(b Vector) bool {
comp := v.Compare(b)
2015-03-20 01:58:32 -07:00
return comp == ConcurrentGreater || comp == ConcurrentLesser
}
2015-04-09 03:51:21 -07:00
// Counter returns the current value of the given counter ID.
func (v Vector) Counter(id ShortID) uint64 {
for _, c := range v.Counters {
2015-04-09 03:51:21 -07:00
if c.ID == id {
return c.Value
}
}
return 0
}
// Ordering represents the relationship between two Vectors.
type Ordering int
const (
Equal Ordering = iota
Greater
Lesser
ConcurrentLesser
ConcurrentGreater
)
// There's really no such thing as "concurrent lesser" and "concurrent
// greater" in version vectors, just "concurrent". But it's useful to be able
// to get a strict ordering between versions for stable sorts and so on, so we
// return both variants. The convenience method Concurrent() can be used to
// check for either case.
// Compare returns the Ordering that describes a's relation to b.
func (v Vector) Compare(b Vector) Ordering {
var ai, bi int // index into a and b
var av, bv Counter // value at current index
result := Equal
for ai < len(v.Counters) || bi < len(b.Counters) {
var aMissing, bMissing bool
if ai < len(v.Counters) {
av = v.Counters[ai]
} else {
av = Counter{}
aMissing = true
}
if bi < len(b.Counters) {
bv = b.Counters[bi]
} else {
bv = Counter{}
bMissing = true
}
switch {
case av.ID == bv.ID:
// We have a counter value for each side
if av.Value > bv.Value {
if result == Lesser {
return ConcurrentLesser
}
result = Greater
} else if av.Value < bv.Value {
if result == Greater {
return ConcurrentGreater
}
result = Lesser
}
case !aMissing && av.ID < bv.ID || bMissing:
// Value is missing on the b side
if av.Value > 0 {
if result == Lesser {
return ConcurrentLesser
}
result = Greater
}
case !bMissing && bv.ID < av.ID || aMissing:
// Value is missing on the a side
if bv.Value > 0 {
if result == Greater {
return ConcurrentGreater
}
result = Lesser
}
}
if ai < len(v.Counters) && (av.ID <= bv.ID || bMissing) {
ai++
}
if bi < len(b.Counters) && (bv.ID <= av.ID || aMissing) {
bi++
}
}
return result
}