Skip to content

Commit

Permalink
ISFR op attribution
Browse files Browse the repository at this point in the history
  • Loading branch information
gritzko committed Mar 21, 2024
1 parent 95df2aa commit ef16376
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 67 deletions.
13 changes: 0 additions & 13 deletions chotki.go
Original file line number Diff line number Diff line change
Expand Up @@ -316,19 +316,6 @@ var WriteOptions = pebble.WriteOptions{Sync: false}

var ErrBadIRecord = errors.New("bad id-ref record")

func ReadRX(op []byte) (ref ID, exec, rest []byte, err error) {
ref, rest, err = TakeIDWary('R', op)
if err != nil {
return
}
var lit byte
lit, exec, rest = toytlv.TakeAnyRecord(rest)
if lit < 'A' {
err = ErrBadIRecord
}
return
}

var ErrBadPacket = errors.New("bad packet")
var ErrBadEPacket = errors.New("bad E packet")
var ErrBadVPacket = errors.New("bad V packet")
Expand Down
83 changes: 48 additions & 35 deletions lww.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import (
// Common LWW functions

// for bad format, value==nil (an empty value is an empty slice)
func LWWparse(bulk []byte) (rev int64, src uint64, value []byte) {
func IsfrParse(bulk []byte) (rev int64, src uint64, value []byte) {
lit, hlen, blen := toytlv.ProbeHeader(bulk)
if lit != 'T' && lit != '0' || hlen+blen > len(bulk) {
return
Expand All @@ -20,15 +20,15 @@ func LWWparse(bulk []byte) (rev int64, src uint64, value []byte) {
return
}

func LWWtlv(rev int64, src uint64, value []byte) (bulk []byte) {
func IsfrTlv(rev int64, src uint64, value []byte) (bulk []byte) {
time := ZipIntUint64Pair(rev, src)
bulk = make([]byte, 0, len(time)+len(value)+2)
bulk = toytlv.AppendTiny(bulk, 'T', time)
bulk = append(bulk, value...)
return
}

func LWWmerge(tlvs [][]byte) (tlv []byte) {
func IsfrMerge(tlvs [][]byte) (tlv []byte) {
var winrec []byte
var winrev int64
var winsrc uint64
Expand Down Expand Up @@ -64,8 +64,8 @@ func LWWmerge(tlvs [][]byte) (tlv []byte) {
return winrec
}

func LWWdiff(tlv []byte, vvdiff VV) []byte {
_, src, _ := LWWparse(tlv)
func IsfrDiff(tlv []byte, vvdiff VV) []byte {
_, src, _ := IsfrParse(tlv)
_, ok := vvdiff[src]
if ok {
return tlv
Expand All @@ -74,6 +74,19 @@ func LWWdiff(tlv []byte, vvdiff VV) []byte {
}
}

func IsfrReSource(bare []byte, src uint64) (res []byte, err error) {
time, s, value := IsfrParse(bare)
if value == nil {
return nil, ErrBadPacket
}
if s != src { // ensure correct attribution
res = IsfrTlv(time, src, value)
} else {
res = bare
}
return
}

// I is a last-write-wins int64

// produce a text form (for REPL mostly)
Expand All @@ -90,41 +103,41 @@ func Iparse(txt string) (tlv []byte) {

// convert native golang value into a TLV form
func Itlv(i int64) (tlv []byte) {
return LWWtlv(0, 0, ZipInt64(i))
return IsfrTlv(0, 0, ZipInt64(i))
}

// convert a TLV value to a native golang value
func Inative(tlv []byte) int64 {
_, _, val := LWWparse(tlv)
_, _, val := IsfrParse(tlv)
return UnzipInt64(val)
}

// merge TLV values
func Imerge(tlvs [][]byte) (tlv []byte) {
return LWWmerge(tlvs)
return IsfrMerge(tlvs)
}

// produce an op that turns the old value into the new one
func Idelta(tlv []byte, new_val int64) (tlv_delta []byte) {
rev, _, val := LWWparse(tlv)
rev, _, val := IsfrParse(tlv)
if rev < 0 {
rev = -rev
}
nv := ZipInt64(new_val)
if bytes.Compare(val, nv) != 0 {
tlv_delta = LWWtlv(rev+1, 0, nv)
tlv_delta = IsfrTlv(rev+1, 0, nv)
}
return
}

// checks a TLV value for validity (format violations)
func Ivalid(tlv []byte) bool {
_, src, val := LWWparse(tlv)
_, src, val := IsfrParse(tlv)
return val != nil && len(val) <= 8 && src <= MaxSrc
}

func Idiff(tlv []byte, vvdiff VV) []byte {
return LWWdiff(tlv, vvdiff)
return IsfrDiff(tlv, vvdiff)
}

// S is a last-write-wins UTF-8 string
Expand All @@ -134,7 +147,7 @@ const hex = "0123456789abcdef"
// produce a text form (for REPL mostly)
func Sstring(tlv []byte) (txt string) {
dst := make([]byte, 0, len(tlv)*2)
_, _, val := LWWparse(tlv)
_, _, val := IsfrParse(tlv)
dst = append(dst, '"')
for _, b := range val {
switch b {
Expand Down Expand Up @@ -165,46 +178,46 @@ func Sparse(txt string) (tlv []byte) {
}
unq := txt[1 : len(txt)-1]
unesc, _ := Unescape([]byte(unq), nil)
return LWWtlv(0, 0, unesc)
return IsfrTlv(0, 0, unesc)
}

// convert native golang value into a TLV form
func Stlv(s string) (tlv []byte) {
return LWWtlv(0, 0, []byte(s))
return IsfrTlv(0, 0, []byte(s))
}

// convert a TLV value to a native golang value
func Snative(tlv []byte) string {
_, _, val := LWWparse(tlv)
_, _, val := IsfrParse(tlv)
return string(val)
}

// merge TLV values
func Smerge(tlvs [][]byte) (tlv []byte) {
return LWWmerge(tlvs)
return IsfrMerge(tlvs)
}

// produce an op that turns the old value into the new one
func Sdelta(tlv []byte, new_val string) (tlv_delta []byte) {
rev, _, val := LWWparse(tlv)
rev, _, val := IsfrParse(tlv)
if rev < 0 {
rev = -rev
}
nv := []byte(new_val)
if bytes.Compare(val, nv) != 0 {
tlv_delta = LWWtlv(rev+1, 0, nv)
tlv_delta = IsfrTlv(rev+1, 0, nv)
}
return
}

// checks a TLV value for validity (format violations)
func Svalid(tlv []byte) bool {
_, src, val := LWWparse(tlv)
_, src, val := IsfrParse(tlv)
return val != nil && src <= MaxSrc
}

func Sdiff(tlv []byte, vvdiff VV) []byte {
return LWWdiff(tlv, vvdiff)
return IsfrDiff(tlv, vvdiff)
}

// R is a last-write-wins ID
Expand All @@ -222,42 +235,42 @@ func Rparse(txt string) (tlv []byte) {

// convert native golang value into a TLV form
func Rtlv(i ID) (tlv []byte) {
return LWWtlv(0, 0, i.ZipBytes())
return IsfrTlv(0, 0, i.ZipBytes())
}

// convert a TLV value to a native golang value
func Rnative(tlv []byte) ID {
_, _, val := LWWparse(tlv)
_, _, val := IsfrParse(tlv)
return IDFromZipBytes(val)
}

// merge TLV values
func Rmerge(tlvs [][]byte) (tlv []byte) {
return LWWmerge(tlvs)
return IsfrMerge(tlvs)
}

// produce an op that turns the old value into the new one
func Rdelta(tlv []byte, new_val ID) (tlv_delta []byte) {
rev, _, val := LWWparse(tlv)
rev, _, val := IsfrParse(tlv)
if rev < 0 {
rev = -rev
}
nv := new_val.ZipBytes()
if bytes.Compare(val, nv) != 0 {
tlv_delta = LWWtlv(rev+1, 0, nv)
tlv_delta = IsfrTlv(rev+1, 0, nv)
}
return
}

// checks a TLV value for validity (format violations)
func Rvalid(tlv []byte) bool {
_, src, val := LWWparse(tlv)
_, src, val := IsfrParse(tlv)
return val != nil && src <= MaxSrc
// todo correct sizes
}

func Rdiff(tlv []byte, vvdiff VV) []byte {
return LWWdiff(tlv, vvdiff)
return IsfrDiff(tlv, vvdiff)
}

// F is a last-write-wins float64
Expand All @@ -276,39 +289,39 @@ func Fparse(txt string) (tlv []byte) {

// convert native golang value into a TLV form
func Ftlv(i float64) (tlv []byte) {
return LWWtlv(0, 0, ZipFloat64(i))
return IsfrTlv(0, 0, ZipFloat64(i))
}

// convert a TLV value to a native golang value
func Fnative(tlv []byte) float64 {
_, _, val := LWWparse(tlv)
_, _, val := IsfrParse(tlv)
return UnzipFloat64(val)
}

// merge TLV values
func Fmerge(tlvs [][]byte) (tlv []byte) {
return LWWmerge(tlvs)
return IsfrMerge(tlvs)
}

// produce an op that turns the old value into the new one
func Fdelta(tlv []byte, new_val float64) (tlv_delta []byte) {
rev, _, val := LWWparse(tlv)
rev, _, val := IsfrParse(tlv)
if rev < 0 {
rev = -rev
}
nv := ZipFloat64(new_val)
if bytes.Compare(val, nv) != 0 {
tlv_delta = LWWtlv(rev+1, 0, nv)
tlv_delta = IsfrTlv(rev+1, 0, nv)
}
return
}

// checks a TLV value for validity (format violations)
func Fvalid(tlv []byte) bool {
_, src, val := LWWparse(tlv)
_, src, val := IsfrParse(tlv)
return val != nil && src <= MaxSrc && len(val) <= 8
}

func Fdiff(tlv []byte, vvdiff VV) []byte {
return LWWdiff(tlv, vvdiff)
return IsfrDiff(tlv, vvdiff)
}
14 changes: 7 additions & 7 deletions lww_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import (

func TestTLV(t *testing.T) {
body := []byte("test")
tlv := LWWtlv(234, 123, body)
time, src, val := LWWparse(tlv)
tlv := IsfrTlv(234, 123, body)
time, src, val := IsfrParse(tlv)
assert.Equal(t, 234, int(time))
assert.Equal(t, 123, int(src))
assert.Equal(t, body, val)

doc := LWWtlv(4, 5, ZipInt64(-11))
doc := IsfrTlv(4, 5, ZipInt64(-11))
assert.Equal(t, []byte{0x32, 0x08, 0x05, 0x15}, doc)
}

Expand Down Expand Up @@ -83,12 +83,12 @@ func TestIMerge(t *testing.T) {
}

func TestLWWTie(t *testing.T) {
a := LWWtlv(4, 8, ZipInt64(1))
b := LWWtlv(4, 7, ZipInt64(2))
c := LWWtlv(4, 5, ZipInt64(2))
a := IsfrTlv(4, 8, ZipInt64(1))
b := IsfrTlv(4, 7, ZipInt64(2))
c := IsfrTlv(4, 5, ZipInt64(2))
d := Imerge(toyqueue.Records{a, b, c})
assert.Equal(t, int64(2), Inative(d))
rev, src, _ := LWWparse(d)
rev, src, _ := IsfrParse(d)
assert.Equal(t, int64(4), rev)
assert.Equal(t, uint64(7), src)
}
Loading

0 comments on commit ef16376

Please sign in to comment.