all: Rename LocalVersion to Sequence (fixes #3461)

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3462
This commit is contained in:
Jakob Borg 2016-07-29 19:54:24 +00:00 committed by Audrius Butkevicius
parent a022b0cfff
commit 297240facf
14 changed files with 312 additions and 312 deletions

View File

@ -90,8 +90,8 @@ type modelIntf interface {
ConnectedTo(deviceID protocol.DeviceID) bool ConnectedTo(deviceID protocol.DeviceID) bool
GlobalSize(folder string) (nfiles, deleted int, bytes int64) GlobalSize(folder string) (nfiles, deleted int, bytes int64)
LocalSize(folder string) (nfiles, deleted int, bytes int64) LocalSize(folder string) (nfiles, deleted int, bytes int64)
CurrentLocalVersion(folder string) (int64, bool) CurrentSequence(folder string) (int64, bool)
RemoteLocalVersion(folder string) (int64, bool) RemoteSequence(folder string) (int64, bool)
State(folder string) (string, time.Time, error) State(folder string) (string, time.Time, error)
} }
@ -596,10 +596,11 @@ func folderSummary(cfg configIntf, m modelIntf, folder string) map[string]interf
res["error"] = err.Error() res["error"] = err.Error()
} }
lv, _ := m.CurrentLocalVersion(folder) ourSeq, _ := m.CurrentSequence(folder)
rv, _ := m.RemoteLocalVersion(folder) remoteSeq, _ := m.RemoteSequence(folder)
res["version"] = lv + rv res["version"] = ourSeq + remoteSeq // legacy
res["sequence"] = ourSeq + remoteSeq // new name
ignorePatterns, _, _ := m.GetIgnores(folder) ignorePatterns, _, _ := m.GetIgnores(folder)
res["ignorePatterns"] = false res["ignorePatterns"] = false
@ -1187,7 +1188,7 @@ func (f jsonFileInfo) MarshalJSON() ([]byte, error) {
"invalid": f.Invalid, "invalid": f.Invalid,
"noPermissions": f.NoPermissions, "noPermissions": f.NoPermissions,
"modified": time.Unix(f.Modified, 0), "modified": time.Unix(f.Modified, 0),
"localVersion": f.LocalVersion, "sequence": f.Sequence,
"numBlocks": len(f.Blocks), "numBlocks": len(f.Blocks),
"version": jsonVersionVector(f.Version), "version": jsonVersionVector(f.Version),
}) })
@ -1205,7 +1206,7 @@ func (f jsonDBFileInfo) MarshalJSON() ([]byte, error) {
"invalid": f.Invalid, "invalid": f.Invalid,
"noPermissions": f.NoPermissions, "noPermissions": f.NoPermissions,
"modified": time.Unix(f.Modified, 0), "modified": time.Unix(f.Modified, 0),
"localVersion": f.LocalVersion, "sequence": f.Sequence,
}) })
} }

View File

@ -103,11 +103,11 @@ func (m *mockedModel) LocalSize(folder string) (nfiles, deleted int, bytes int64
return 0, 0, 0 return 0, 0, 0
} }
func (m *mockedModel) CurrentLocalVersion(folder string) (int64, bool) { func (m *mockedModel) CurrentSequence(folder string) (int64, bool) {
return 0, false return 0, false
} }
func (m *mockedModel) RemoteLocalVersion(folder string) (int64, bool) { func (m *mockedModel) RemoteSequence(folder string) (int64, bool) {
return 0, false return 0, false
} }

View File

@ -22,15 +22,15 @@ import (
) )
type FileSet struct { type FileSet struct {
localVersion int64 // Our local version counter sequence int64 // Our local sequence number
folder string folder string
db *Instance db *Instance
blockmap *BlockMap blockmap *BlockMap
localSize sizeTracker localSize sizeTracker
globalSize sizeTracker globalSize sizeTracker
remoteLocalVersion map[protocol.DeviceID]int64 // Highest seen local versions for other devices remoteSequence map[protocol.DeviceID]int64 // Highest seen sequence numbers for other devices
updateMutex sync.Mutex // protects remoteLocalVersion and database updates updateMutex sync.Mutex // protects remoteSequence and database updates
} }
// FileIntf is the set of methods implemented by both protocol.FileInfo and // FileIntf is the set of methods implemented by both protocol.FileInfo and
@ -98,11 +98,11 @@ func (s *sizeTracker) Size() (files, deleted int, bytes int64) {
func NewFileSet(folder string, db *Instance) *FileSet { func NewFileSet(folder string, db *Instance) *FileSet {
var s = FileSet{ var s = FileSet{
remoteLocalVersion: make(map[protocol.DeviceID]int64), remoteSequence: make(map[protocol.DeviceID]int64),
folder: folder, folder: folder,
db: db, db: db,
blockmap: NewBlockMap(db, db.folderIdx.ID([]byte(folder))), blockmap: NewBlockMap(db, db.folderIdx.ID([]byte(folder))),
updateMutex: sync.NewMutex(), updateMutex: sync.NewMutex(),
} }
s.db.checkGlobals([]byte(folder), &s.globalSize) s.db.checkGlobals([]byte(folder), &s.globalSize)
@ -111,16 +111,16 @@ func NewFileSet(folder string, db *Instance) *FileSet {
s.db.withAllFolderTruncated([]byte(folder), func(device []byte, f FileInfoTruncated) bool { s.db.withAllFolderTruncated([]byte(folder), func(device []byte, f FileInfoTruncated) bool {
copy(deviceID[:], device) copy(deviceID[:], device)
if deviceID == protocol.LocalDeviceID { if deviceID == protocol.LocalDeviceID {
if f.LocalVersion > s.localVersion { if f.Sequence > s.sequence {
s.localVersion = f.LocalVersion s.sequence = f.Sequence
} }
s.localSize.addFile(f) s.localSize.addFile(f)
} else if f.LocalVersion > s.remoteLocalVersion[deviceID] { } else if f.Sequence > s.remoteSequence[deviceID] {
s.remoteLocalVersion[deviceID] = f.LocalVersion s.remoteSequence[deviceID] = f.Sequence
} }
return true return true
}) })
l.Debugf("loaded localVersion for %q: %#v", folder, s.localVersion) l.Debugf("loaded sequence for %q: %#v", folder, s.sequence)
return &s return &s
} }
@ -134,17 +134,17 @@ func (s *FileSet) Replace(device protocol.DeviceID, fs []protocol.FileInfo) {
if device == protocol.LocalDeviceID { if device == protocol.LocalDeviceID {
if len(fs) == 0 { if len(fs) == 0 {
s.localVersion = 0 s.sequence = 0
} else { } else {
// Always overwrite LocalVersion on updated files to ensure // Always overwrite Sequence on updated files to ensure
// correct ordering. The caller is supposed to leave it set to // correct ordering. The caller is supposed to leave it set to
// zero anyhow. // zero anyhow.
for i := range fs { for i := range fs {
fs[i].LocalVersion = atomic.AddInt64(&s.localVersion, 1) fs[i].Sequence = atomic.AddInt64(&s.sequence, 1)
} }
} }
} else { } else {
s.remoteLocalVersion[device] = maxLocalVersion(fs) s.remoteSequence[device] = maxSequence(fs)
} }
s.db.replace([]byte(s.folder), device[:], fs, &s.localSize, &s.globalSize) s.db.replace([]byte(s.folder), device[:], fs, &s.localSize, &s.globalSize)
if device == protocol.LocalDeviceID { if device == protocol.LocalDeviceID {
@ -164,7 +164,7 @@ func (s *FileSet) Update(device protocol.DeviceID, fs []protocol.FileInfo) {
discards := make([]protocol.FileInfo, 0, len(fs)) discards := make([]protocol.FileInfo, 0, len(fs))
updates := make([]protocol.FileInfo, 0, len(fs)) updates := make([]protocol.FileInfo, 0, len(fs))
for i, newFile := range fs { for i, newFile := range fs {
fs[i].LocalVersion = atomic.AddInt64(&s.localVersion, 1) fs[i].Sequence = atomic.AddInt64(&s.sequence, 1)
existingFile, ok := s.db.getFile([]byte(s.folder), device[:], []byte(newFile.Name)) existingFile, ok := s.db.getFile([]byte(s.folder), device[:], []byte(newFile.Name))
if !ok || !existingFile.Version.Equal(newFile.Version) { if !ok || !existingFile.Version.Equal(newFile.Version) {
discards = append(discards, existingFile) discards = append(discards, existingFile)
@ -174,7 +174,7 @@ func (s *FileSet) Update(device protocol.DeviceID, fs []protocol.FileInfo) {
s.blockmap.Discard(discards) s.blockmap.Discard(discards)
s.blockmap.Update(updates) s.blockmap.Update(updates)
} else { } else {
s.remoteLocalVersion[device] = maxLocalVersion(fs) s.remoteSequence[device] = maxSequence(fs)
} }
s.db.updateFiles([]byte(s.folder), device[:], fs, &s.localSize, &s.globalSize) s.db.updateFiles([]byte(s.folder), device[:], fs, &s.localSize, &s.globalSize)
} }
@ -248,14 +248,14 @@ func (s *FileSet) Availability(file string) []protocol.DeviceID {
return s.db.availability([]byte(s.folder), []byte(osutil.NormalizedFilename(file))) return s.db.availability([]byte(s.folder), []byte(osutil.NormalizedFilename(file)))
} }
func (s *FileSet) LocalVersion(device protocol.DeviceID) int64 { func (s *FileSet) Sequence(device protocol.DeviceID) int64 {
if device == protocol.LocalDeviceID { if device == protocol.LocalDeviceID {
return atomic.LoadInt64(&s.localVersion) return atomic.LoadInt64(&s.sequence)
} }
s.updateMutex.Lock() s.updateMutex.Lock()
defer s.updateMutex.Unlock() defer s.updateMutex.Unlock()
return s.remoteLocalVersion[device] return s.remoteSequence[device]
} }
func (s *FileSet) LocalSize() (files, deleted int, bytes int64) { func (s *FileSet) LocalSize() (files, deleted int, bytes int64) {
@ -283,15 +283,15 @@ func (s *FileSet) SetIndexID(device protocol.DeviceID, id protocol.IndexID) {
s.db.setIndexID(device[:], []byte(s.folder), id) s.db.setIndexID(device[:], []byte(s.folder), id)
} }
// maxLocalVersion returns the highest of the LocalVersion numbers found in // maxSequence returns the highest of the Sequence numbers found in
// the given slice of FileInfos. This should really be the LocalVersion of // the given slice of FileInfos. This should really be the Sequence of
// the last item, but Syncthing v0.14.0 and other implementations may not // the last item, but Syncthing v0.14.0 and other implementations may not
// implement update sorting.... // implement update sorting....
func maxLocalVersion(fs []protocol.FileInfo) int64 { func maxSequence(fs []protocol.FileInfo) int64 {
var max int64 var max int64
for _, f := range fs { for _, f := range fs {
if f.LocalVersion > max { if f.Sequence > max {
max = f.LocalVersion max = f.Sequence
} }
} }
return max return max

View File

@ -100,11 +100,11 @@ func TestGlobalSet(t *testing.T) {
m := db.NewFileSet("test", ldb) m := db.NewFileSet("test", ldb)
local0 := fileList{ local0 := fileList{
protocol.FileInfo{Name: "a", LocalVersion: 1, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)}, protocol.FileInfo{Name: "a", Sequence: 1, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
protocol.FileInfo{Name: "b", LocalVersion: 2, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(2)}, protocol.FileInfo{Name: "b", Sequence: 2, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(2)},
protocol.FileInfo{Name: "c", LocalVersion: 3, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(3)}, protocol.FileInfo{Name: "c", Sequence: 3, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(3)},
protocol.FileInfo{Name: "d", LocalVersion: 4, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(4)}, protocol.FileInfo{Name: "d", Sequence: 4, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(4)},
protocol.FileInfo{Name: "z", LocalVersion: 5, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(8)}, protocol.FileInfo{Name: "z", Sequence: 5, Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(8)},
} }
local1 := fileList{ local1 := fileList{
protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)}, protocol.FileInfo{Name: "a", Version: protocol.Vector{Counters: []protocol.Counter{{ID: myID, Value: 1000}}}, Blocks: genBlocks(1)},
@ -480,7 +480,7 @@ func TestNeed(t *testing.T) {
} }
} }
func TestLocalVersion(t *testing.T) { func TestSequence(t *testing.T) {
ldb := db.OpenMemory() ldb := db.OpenMemory()
m := db.NewFileSet("test", ldb) m := db.NewFileSet("test", ldb)
@ -501,10 +501,10 @@ func TestLocalVersion(t *testing.T) {
} }
m.Replace(protocol.LocalDeviceID, local1) m.Replace(protocol.LocalDeviceID, local1)
c0 := m.LocalVersion(protocol.LocalDeviceID) c0 := m.Sequence(protocol.LocalDeviceID)
m.Replace(protocol.LocalDeviceID, local2) m.Replace(protocol.LocalDeviceID, local2)
c1 := m.LocalVersion(protocol.LocalDeviceID) c1 := m.Sequence(protocol.LocalDeviceID)
if !(c1 > c0) { if !(c1 > c0) {
t.Fatal("Local version number should have incremented") t.Fatal("Local version number should have incremented")
} }

View File

@ -61,7 +61,7 @@ type FileInfoTruncated struct {
Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"` Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"`
NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"` NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"`
Version protocol.Vector `protobuf:"bytes,9,opt,name=version" json:"version"` Version protocol.Vector `protobuf:"bytes,9,opt,name=version" json:"version"`
LocalVersion int64 `protobuf:"varint,10,opt,name=local_version,json=localVersion,proto3" json:"local_version,omitempty"` Sequence int64 `protobuf:"varint,10,opt,name=sequence,proto3" json:"sequence,omitempty"`
} }
func (m *FileInfoTruncated) Reset() { *m = FileInfoTruncated{} } func (m *FileInfoTruncated) Reset() { *m = FileInfoTruncated{} }
@ -214,10 +214,10 @@ func (m *FileInfoTruncated) MarshalTo(data []byte) (int, error) {
return 0, err return 0, err
} }
i += n2 i += n2
if m.LocalVersion != 0 { if m.Sequence != 0 {
data[i] = 0x50 data[i] = 0x50
i++ i++
i = encodeVarintStructs(data, i, uint64(m.LocalVersion)) i = encodeVarintStructs(data, i, uint64(m.Sequence))
} }
return i, nil return i, nil
} }
@ -303,8 +303,8 @@ func (m *FileInfoTruncated) ProtoSize() (n int) {
} }
l = m.Version.ProtoSize() l = m.Version.ProtoSize()
n += 1 + l + sovStructs(uint64(l)) n += 1 + l + sovStructs(uint64(l))
if m.LocalVersion != 0 { if m.Sequence != 0 {
n += 1 + sovStructs(uint64(m.LocalVersion)) n += 1 + sovStructs(uint64(m.Sequence))
} }
return n return n
} }
@ -740,9 +740,9 @@ func (m *FileInfoTruncated) Unmarshal(data []byte) error {
iNdEx = postIndex iNdEx = postIndex
case 10: case 10:
if wireType != 0 { if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field LocalVersion", wireType) return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType)
} }
m.LocalVersion = 0 m.Sequence = 0
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowStructs return ErrIntOverflowStructs
@ -752,7 +752,7 @@ func (m *FileInfoTruncated) Unmarshal(data []byte) error {
} }
b := data[iNdEx] b := data[iNdEx]
iNdEx++ iNdEx++
m.LocalVersion |= (int64(b) & 0x7F) << shift m.Sequence |= (int64(b) & 0x7F) << shift
if b < 0x80 { if b < 0x80 {
break break
} }
@ -884,31 +884,30 @@ var (
) )
var fileDescriptorStructs = []byte{ var fileDescriptorStructs = []byte{
// 401 bytes of a gzipped FileDescriptorProto // 400 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x51, 0x4f, 0xcb, 0xd3, 0x30, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0x8c, 0x51, 0x4d, 0x6b, 0xe2, 0x40,
0x1c, 0x6e, 0xb7, 0xba, 0xf5, 0x4d, 0xdf, 0x4e, 0x0d, 0x32, 0xca, 0x0e, 0xdd, 0x98, 0x08, 0x22, 0x18, 0x4e, 0x34, 0xab, 0x71, 0xb2, 0xba, 0xbb, 0xc3, 0x22, 0xc1, 0x43, 0x14, 0x61, 0x61, 0x59,
0xd8, 0xe9, 0xc4, 0x8b, 0xc7, 0x1d, 0x06, 0x82, 0x07, 0x29, 0x32, 0x8f, 0xa3, 0x4d, 0xb2, 0x2e, 0xd8, 0xb8, 0xeb, 0xb2, 0x97, 0x1e, 0x3d, 0x08, 0x85, 0x1e, 0x4a, 0x28, 0xf6, 0x58, 0x4c, 0x66,
0xd0, 0x26, 0xa5, 0x49, 0x07, 0xf3, 0x93, 0x78, 0xdc, 0xc7, 0xd9, 0xd1, 0x2f, 0xa0, 0xe8, 0xfc, 0x8c, 0x03, 0xc9, 0x4c, 0x9a, 0x99, 0x08, 0xf6, 0x97, 0xf4, 0xe8, 0xcf, 0xf1, 0xd8, 0x43, 0xcf,
0x22, 0x66, 0x49, 0x3b, 0x7b, 0x7c, 0x0f, 0x81, 0xdf, 0x93, 0xe7, 0xcf, 0xef, 0x21, 0x01, 0xbe, 0xa5, 0xb5, 0x7f, 0xa4, 0xe3, 0x4c, 0x62, 0x73, 0xec, 0x21, 0xf0, 0x3e, 0x79, 0x3e, 0xde, 0x87,
0x90, 0x55, 0x8d, 0xa4, 0x88, 0xca, 0x8a, 0x4b, 0x0e, 0x7b, 0x38, 0x9d, 0xbc, 0xce, 0xa8, 0xdc, 0x79, 0x41, 0x97, 0x8b, 0xbc, 0x88, 0x04, 0xf7, 0xb3, 0x9c, 0x09, 0x06, 0x1b, 0x28, 0x1c, 0xfc,
0xd7, 0x69, 0x84, 0x78, 0xb1, 0xc8, 0x78, 0xc6, 0x17, 0x9a, 0x4a, 0xeb, 0x9d, 0x46, 0x1a, 0xe8, 0x8e, 0x89, 0x58, 0x17, 0xa1, 0x1f, 0xb1, 0x74, 0x12, 0xb3, 0x98, 0x4d, 0x14, 0x15, 0x16, 0x2b,
0xc9, 0x58, 0x26, 0xef, 0x3b, 0x72, 0x71, 0x64, 0x48, 0xee, 0x29, 0xcb, 0x3a, 0x53, 0x4e, 0x53, 0x85, 0x14, 0x50, 0x93, 0xb6, 0x0c, 0xfe, 0xd7, 0xe4, 0x7c, 0x4b, 0x23, 0xb1, 0x26, 0x34, 0xae,
0x93, 0x80, 0x78, 0xbe, 0x48, 0x49, 0x69, 0x6c, 0xf3, 0xaf, 0xc0, 0x5b, 0xd3, 0x9c, 0x6c, 0x48, 0x4d, 0x09, 0x09, 0x75, 0x42, 0xc4, 0x92, 0x49, 0x88, 0x33, 0x6d, 0x1b, 0x5f, 0x03, 0x67, 0x4e,
0x25, 0x28, 0x67, 0xf0, 0x0d, 0x18, 0x1e, 0xcc, 0x18, 0xd8, 0x33, 0xfb, 0xa5, 0xb7, 0x7c, 0x12, 0x12, 0xbc, 0xc0, 0x39, 0x27, 0x8c, 0xc2, 0x3f, 0xa0, 0xbd, 0xd1, 0xa3, 0x6b, 0x8e, 0xcc, 0x9f,
0xb5, 0xa6, 0x68, 0x43, 0x90, 0xe4, 0xd5, 0xca, 0x39, 0xff, 0x9a, 0x5a, 0x71, 0x2b, 0x83, 0x63, 0xce, 0xf4, 0xab, 0x5f, 0x99, 0xfc, 0x05, 0x8e, 0x04, 0xcb, 0x67, 0xd6, 0xfe, 0x69, 0x68, 0x04,
0x30, 0xc0, 0xe4, 0x40, 0x11, 0x09, 0x7a, 0xca, 0x70, 0x1f, 0x37, 0x68, 0xbe, 0x06, 0x5e, 0x13, 0x95, 0x0c, 0xf6, 0x41, 0x0b, 0xe1, 0x0d, 0x89, 0xb0, 0xdb, 0x90, 0x86, 0xcf, 0x41, 0x89, 0xc6,
0xfa, 0x89, 0x0a, 0x09, 0xdf, 0x02, 0xb7, 0x71, 0x08, 0x95, 0xdc, 0x57, 0xc9, 0x8f, 0x23, 0x9c, 0x73, 0xe0, 0x94, 0xa1, 0x17, 0x84, 0x0b, 0xf8, 0x17, 0xd8, 0xa5, 0x83, 0xcb, 0xe4, 0xa6, 0x4c,
0x46, 0x9d, 0xdd, 0x4d, 0xf0, 0x4d, 0xf6, 0xc1, 0xf9, 0x7e, 0x9a, 0x5a, 0xf3, 0x9f, 0x3d, 0xf0, 0xfe, 0xe2, 0xa3, 0xd0, 0xaf, 0xed, 0x2e, 0x83, 0x4f, 0xb2, 0x33, 0xeb, 0x7e, 0x37, 0x34, 0xc6,
0xf4, 0xaa, 0xfa, 0xc8, 0x76, 0xfc, 0x4b, 0x55, 0x33, 0x94, 0x48, 0x82, 0x21, 0x04, 0x0e, 0x4b, 0x8f, 0x0d, 0xf0, 0xed, 0xa8, 0x3a, 0xa7, 0x2b, 0x76, 0x95, 0x17, 0x34, 0x5a, 0x0a, 0x8c, 0x20,
0x0a, 0xa2, 0x4b, 0xde, 0xc5, 0x7a, 0x86, 0xaf, 0x80, 0x23, 0x8f, 0xa5, 0xe9, 0x31, 0x5a, 0x8e, 0x04, 0x16, 0x5d, 0xa6, 0x58, 0x95, 0xec, 0x04, 0x6a, 0x86, 0xbf, 0x80, 0x25, 0xb6, 0x99, 0xee,
0xff, 0x17, 0xbf, 0xd9, 0x15, 0x1b, 0x6b, 0xcd, 0xd5, 0x2f, 0xe8, 0x37, 0x12, 0xf4, 0x95, 0xb6, 0xd1, 0x9b, 0xf6, 0xdf, 0x8b, 0x9f, 0xec, 0x92, 0x0d, 0x94, 0xe6, 0xe8, 0xe7, 0xe4, 0x0e, 0xbb,
0x1f, 0xeb, 0x19, 0xce, 0x80, 0x57, 0x92, 0xaa, 0xa0, 0xc2, 0xb4, 0x74, 0x14, 0xe5, 0xc7, 0xdd, 0x4d, 0xa9, 0x6d, 0x06, 0x6a, 0x86, 0x23, 0xe0, 0x64, 0x38, 0x4f, 0x09, 0xd7, 0x2d, 0x2d, 0x49,
0x2b, 0x38, 0x01, 0x6e, 0xc1, 0x31, 0xdd, 0x51, 0x82, 0x83, 0x47, 0xda, 0x79, 0xc3, 0x30, 0x00, 0x75, 0x83, 0xfa, 0x2f, 0x38, 0x00, 0x76, 0xca, 0x10, 0x59, 0x11, 0x8c, 0xdc, 0x4f, 0xca, 0x79,
0x43, 0x4c, 0x72, 0xa2, 0xca, 0x05, 0x03, 0x45, 0xb9, 0x71, 0x0b, 0xaf, 0x0c, 0x65, 0x87, 0x24, 0xc2, 0xd0, 0x05, 0x6d, 0x84, 0x13, 0x2c, 0xcb, 0xb9, 0x2d, 0x49, 0xd9, 0x41, 0x05, 0x8f, 0x0c,
0xa7, 0x38, 0x18, 0x1a, 0xa6, 0x81, 0xf0, 0x05, 0x18, 0x31, 0xbe, 0xed, 0x2e, 0x75, 0xb5, 0xc0, 0xa1, 0x9b, 0x65, 0x42, 0x90, 0xdb, 0xd6, 0x4c, 0x09, 0xe1, 0x0f, 0xd0, 0xa3, 0xec, 0xa6, 0xbe,
0x67, 0xfc, 0x73, 0x67, 0x6d, 0xe7, 0x53, 0xee, 0x1e, 0xf6, 0x29, 0xcf, 0x81, 0x9f, 0x73, 0x94, 0xd4, 0x56, 0x82, 0x2e, 0x65, 0x97, 0xb5, 0xb5, 0xb5, 0xa3, 0x74, 0x3e, 0x76, 0x14, 0x59, 0x94,
0xe4, 0xdb, 0xd6, 0x07, 0x74, 0xdb, 0x7b, 0x7d, 0xd9, 0xbc, 0xb7, 0x79, 0xdf, 0xd5, 0xb3, 0xf3, 0xe3, 0xdb, 0x02, 0x53, 0x79, 0x16, 0xa0, 0x8b, 0x56, 0x58, 0x3f, 0xeb, 0xec, 0xfb, 0xfe, 0xc5,
0x9f, 0xd0, 0x3a, 0x5f, 0x42, 0xfb, 0x87, 0x3a, 0xbf, 0x2f, 0xa1, 0x75, 0xfa, 0x1b, 0xda, 0xe9, 0x33, 0xf6, 0x07, 0xcf, 0x7c, 0x90, 0xdf, 0xf3, 0xc1, 0x33, 0x76, 0xaf, 0x9e, 0x19, 0xb6, 0x54,
0x40, 0x2f, 0x78, 0xf7, 0x2f, 0x00, 0x00, 0xff, 0xff, 0xe4, 0xb1, 0x7f, 0x07, 0x98, 0x02, 0x00, 0xee, 0xbf, 0xb7, 0x00, 0x00, 0x00, 0xff, 0xff, 0xdf, 0xb3, 0x6f, 0x36, 0x8f, 0x02, 0x00, 0x00,
0x00,
} }

View File

@ -31,5 +31,5 @@ message FileInfoTruncated {
bool invalid = 7; bool invalid = 7;
bool no_permissions = 8; bool no_permissions = 8;
protocol.Vector version = 9 [(gogoproto.nullable) = false]; protocol.Vector version = 9 [(gogoproto.nullable) = false];
int64 local_version = 10; int64 sequence = 10;
} }

View File

@ -189,7 +189,7 @@ func (m *Model) StartFolder(folder string) {
} }
fs := m.folderFiles[folder] fs := m.folderFiles[folder]
v, ok := fs.LocalVersion(protocol.LocalDeviceID), true v, ok := fs.Sequence(protocol.LocalDeviceID), true
indexHasFiles := ok && v > 0 indexHasFiles := ok && v > 0
if !indexHasFiles { if !indexHasFiles {
// It's a blank folder, so this may the first time we're looking at // It's a blank folder, so this may the first time we're looking at
@ -583,7 +583,7 @@ func (m *Model) Index(deviceID protocol.DeviceID, folder string, fs []protocol.F
"device": deviceID.String(), "device": deviceID.String(),
"folder": folder, "folder": folder,
"items": len(fs), "items": len(fs),
"version": files.LocalVersion(deviceID), "version": files.Sequence(deviceID),
}) })
} }
@ -619,7 +619,7 @@ func (m *Model) IndexUpdate(deviceID protocol.DeviceID, folder string, fs []prot
"device": deviceID.String(), "device": deviceID.String(),
"folder": folder, "folder": folder,
"items": len(fs), "items": len(fs),
"version": files.LocalVersion(deviceID), "version": files.Sequence(deviceID),
}) })
runner.IndexUpdated() runner.IndexUpdated()
@ -674,8 +674,8 @@ func (m *Model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
fs := m.folderFiles[folder.ID] fs := m.folderFiles[folder.ID]
myIndexID := fs.IndexID(protocol.LocalDeviceID) myIndexID := fs.IndexID(protocol.LocalDeviceID)
myLocalVersion := fs.LocalVersion(protocol.LocalDeviceID) mySequence := fs.Sequence(protocol.LocalDeviceID)
var startLocalVersion int64 var startSequence int64
for _, dev := range folder.Devices { for _, dev := range folder.Devices {
if bytes.Equal(dev.ID, m.id[:]) { if bytes.Equal(dev.ID, m.id[:]) {
@ -687,7 +687,7 @@ func (m *Model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
// They say they've seen our index ID before, so we can // They say they've seen our index ID before, so we can
// send a delta update only. // send a delta update only.
if dev.MaxLocalVersion > myLocalVersion { if dev.MaxSequence > mySequence {
// Safety check. They claim to have more or newer // Safety check. They claim to have more or newer
// index data than we have - either we have lost // index data than we have - either we have lost
// index data, or reset the index without resetting // index data, or reset the index without resetting
@ -695,19 +695,19 @@ func (m *Model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
// happened. We send a full index to reset the // happened. We send a full index to reset the
// situation. // situation.
l.Infof("Device %v folder %q is delta index compatible, but seems out of sync with reality", deviceID, folder.ID) l.Infof("Device %v folder %q is delta index compatible, but seems out of sync with reality", deviceID, folder.ID)
startLocalVersion = 0 startSequence = 0
continue continue
} }
l.Infof("Device %v folder %q is delta index compatible (mlv=%d)", deviceID, folder.ID, dev.MaxLocalVersion) l.Infof("Device %v folder %q is delta index compatible (mlv=%d)", deviceID, folder.ID, dev.MaxSequence)
startLocalVersion = dev.MaxLocalVersion startSequence = dev.MaxSequence
} else if dev.IndexID != 0 { } else if dev.IndexID != 0 {
// They say they've seen an index ID from us, but it's // They say they've seen an index ID from us, but it's
// not the right one. Either they are confused or we // not the right one. Either they are confused or we
// must have reset our database since last talking to // must have reset our database since last talking to
// them. We'll start with a full index transfer. // them. We'll start with a full index transfer.
l.Infof("Device %v folder %q has mismatching index ID for us (%v != %v)", deviceID, folder.ID, dev.IndexID, myIndexID) l.Infof("Device %v folder %q has mismatching index ID for us (%v != %v)", deviceID, folder.ID, dev.IndexID, myIndexID)
startLocalVersion = 0 startSequence = 0
} }
} else if bytes.Equal(dev.ID, deviceID[:]) && dev.IndexID != 0 { } else if bytes.Equal(dev.ID, deviceID[:]) && dev.IndexID != 0 {
// This is the other side's description of themselves. We // This is the other side's description of themselves. We
@ -743,7 +743,7 @@ func (m *Model) ClusterConfig(deviceID protocol.DeviceID, cm protocol.ClusterCon
} }
} }
go sendIndexes(conn, folder.ID, fs, m.folderIgnores[folder.ID], startLocalVersion, dbLocation) go sendIndexes(conn, folder.ID, fs, m.folderIgnores[folder.ID], startSequence, dbLocation)
} }
m.fmut.Unlock() m.fmut.Unlock()
@ -1216,15 +1216,15 @@ func (m *Model) receivedFile(folder string, file protocol.FileInfo) {
m.folderStatRef(folder).ReceivedFile(file.Name, file.IsDeleted()) m.folderStatRef(folder).ReceivedFile(file.Name, file.IsDeleted())
} }
func sendIndexes(conn protocol.Connection, folder string, fs *db.FileSet, ignores *ignore.Matcher, startLocalVersion int64, dbLocation string) { func sendIndexes(conn protocol.Connection, folder string, fs *db.FileSet, ignores *ignore.Matcher, startSequence int64, dbLocation string) {
deviceID := conn.ID() deviceID := conn.ID()
name := conn.Name() name := conn.Name()
var err error var err error
l.Debugf("sendIndexes for %s-%s/%q starting (slv=%d)", deviceID, name, folder, startLocalVersion) l.Debugf("sendIndexes for %s-%s/%q starting (slv=%d)", deviceID, name, folder, startSequence)
defer l.Debugf("sendIndexes for %s-%s/%q exiting: %v", deviceID, name, folder, err) defer l.Debugf("sendIndexes for %s-%s/%q exiting: %v", deviceID, name, folder, err)
minLocalVer, err := sendIndexTo(startLocalVersion, conn, folder, fs, ignores, dbLocation) minSequence, err := sendIndexTo(startSequence, conn, folder, fs, ignores, dbLocation)
// Subscribe to LocalIndexUpdated (we have new information to send) and // Subscribe to LocalIndexUpdated (we have new information to send) and
// DeviceDisconnected (it might be us who disconnected, so we should // DeviceDisconnected (it might be us who disconnected, so we should
@ -1238,16 +1238,16 @@ func sendIndexes(conn protocol.Connection, folder string, fs *db.FileSet, ignore
return return
} }
// While we have sent a localVersion at least equal to the one // While we have sent a sequence at least equal to the one
// currently in the database, wait for the local index to update. The // currently in the database, wait for the local index to update. The
// local index may update for other folders than the one we are // local index may update for other folders than the one we are
// sending for. // sending for.
if fs.LocalVersion(protocol.LocalDeviceID) <= minLocalVer { if fs.Sequence(protocol.LocalDeviceID) <= minSequence {
sub.Poll(time.Minute) sub.Poll(time.Minute)
continue continue
} }
minLocalVer, err = sendIndexTo(minLocalVer, conn, folder, fs, ignores, dbLocation) minSequence, err = sendIndexTo(minSequence, conn, folder, fs, ignores, dbLocation)
// Wait a short amount of time before entering the next loop. If there // Wait a short amount of time before entering the next loop. If there
// are continuous changes happening to the local index, this gives us // are continuous changes happening to the local index, this gives us
@ -1256,13 +1256,13 @@ func sendIndexes(conn protocol.Connection, folder string, fs *db.FileSet, ignore
} }
} }
func sendIndexTo(minLocalVer int64, conn protocol.Connection, folder string, fs *db.FileSet, ignores *ignore.Matcher, dbLocation string) (int64, error) { func sendIndexTo(minSequence int64, conn protocol.Connection, folder string, fs *db.FileSet, ignores *ignore.Matcher, dbLocation string) (int64, error) {
deviceID := conn.ID() deviceID := conn.ID()
name := conn.Name() name := conn.Name()
batch := make([]protocol.FileInfo, 0, indexBatchSize) batch := make([]protocol.FileInfo, 0, indexBatchSize)
currentBatchSize := 0 currentBatchSize := 0
initial := minLocalVer == 0 initial := minSequence == 0
maxLocalVer := minLocalVer maxSequence := minSequence
var err error var err error
sorter := NewIndexSorter(dbLocation) sorter := NewIndexSorter(dbLocation)
@ -1270,12 +1270,12 @@ func sendIndexTo(minLocalVer int64, conn protocol.Connection, folder string, fs
fs.WithHave(protocol.LocalDeviceID, func(fi db.FileIntf) bool { fs.WithHave(protocol.LocalDeviceID, func(fi db.FileIntf) bool {
f := fi.(protocol.FileInfo) f := fi.(protocol.FileInfo)
if f.LocalVersion <= minLocalVer { if f.Sequence <= minSequence {
return true return true
} }
if f.LocalVersion > maxLocalVer { if f.Sequence > maxSequence {
maxLocalVer = f.LocalVersion maxSequence = f.Sequence
} }
if ignores.Match(f.Name).IsIgnored() || symlinkInvalid(folder, f) { if ignores.Match(f.Name).IsIgnored() || symlinkInvalid(folder, f) {
@ -1323,7 +1323,7 @@ func sendIndexTo(minLocalVer int64, conn protocol.Connection, folder string, fs
} }
} }
return maxLocalVer, err return maxSequence, err
} }
func (m *Model) updateLocalsFromScanning(folder string, fs []protocol.FileInfo) { func (m *Model) updateLocalsFromScanning(folder string, fs []protocol.FileInfo) {
@ -1360,7 +1360,7 @@ func (m *Model) updateLocals(folder string, fs []protocol.FileInfo) {
"folder": folder, "folder": folder,
"items": len(fs), "items": len(fs),
"filenames": filenames, "filenames": filenames,
"version": files.LocalVersion(protocol.LocalDeviceID), "version": files.Sequence(protocol.LocalDeviceID),
}) })
} }
@ -1751,24 +1751,24 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
deviceCfg := m.cfg.Devices()[device] deviceCfg := m.cfg.Devices()[device]
var indexID protocol.IndexID var indexID protocol.IndexID
var maxLocalVersion int64 var maxSequence int64
if device == m.id { if device == m.id {
indexID = fs.IndexID(protocol.LocalDeviceID) indexID = fs.IndexID(protocol.LocalDeviceID)
maxLocalVersion = fs.LocalVersion(protocol.LocalDeviceID) maxSequence = fs.Sequence(protocol.LocalDeviceID)
} else { } else {
indexID = fs.IndexID(device) indexID = fs.IndexID(device)
maxLocalVersion = fs.LocalVersion(device) maxSequence = fs.Sequence(device)
} }
protocolDevice := protocol.Device{ protocolDevice := protocol.Device{
ID: device[:], ID: device[:],
Name: deviceCfg.Name, Name: deviceCfg.Name,
Addresses: deviceCfg.Addresses, Addresses: deviceCfg.Addresses,
Compression: deviceCfg.Compression, Compression: deviceCfg.Compression,
CertName: deviceCfg.CertName, CertName: deviceCfg.CertName,
Introducer: deviceCfg.Introducer, Introducer: deviceCfg.Introducer,
IndexID: indexID, IndexID: indexID,
MaxLocalVersion: maxLocalVersion, MaxSequence: maxSequence,
} }
protocolFolder.Devices = append(protocolFolder.Devices, protocolDevice) protocolFolder.Devices = append(protocolFolder.Devices, protocolDevice)
@ -1823,7 +1823,7 @@ func (m *Model) Override(folder string) {
have.Version = have.Version.Merge(need.Version).Update(m.shortID) have.Version = have.Version.Merge(need.Version).Update(m.shortID)
need = have need = have
} }
need.LocalVersion = 0 need.Sequence = 0
batch = append(batch, need) batch = append(batch, need)
return true return true
}) })
@ -1833,10 +1833,10 @@ func (m *Model) Override(folder string) {
runner.setState(FolderIdle) runner.setState(FolderIdle)
} }
// CurrentLocalVersion returns the change version for the given folder. // CurrentSequence returns the change version for the given folder.
// This is guaranteed to increment if the contents of the local folder has // This is guaranteed to increment if the contents of the local folder has
// changed. // changed.
func (m *Model) CurrentLocalVersion(folder string) (int64, bool) { func (m *Model) CurrentSequence(folder string) (int64, bool) {
m.fmut.RLock() m.fmut.RLock()
fs, ok := m.folderFiles[folder] fs, ok := m.folderFiles[folder]
m.fmut.RUnlock() m.fmut.RUnlock()
@ -1846,13 +1846,13 @@ func (m *Model) CurrentLocalVersion(folder string) (int64, bool) {
return 0, false return 0, false
} }
return fs.LocalVersion(protocol.LocalDeviceID), true return fs.Sequence(protocol.LocalDeviceID), true
} }
// RemoteLocalVersion returns the change version for the given folder, as // RemoteSequence returns the change version for the given folder, as
// sent by remote peers. This is guaranteed to increment if the contents of // sent by remote peers. This is guaranteed to increment if the contents of
// the remote or global folder has changed. // the remote or global folder has changed.
func (m *Model) RemoteLocalVersion(folder string) (int64, bool) { func (m *Model) RemoteSequence(folder string) (int64, bool) {
m.fmut.RLock() m.fmut.RLock()
defer m.fmut.RUnlock() defer m.fmut.RUnlock()
@ -1865,7 +1865,7 @@ func (m *Model) RemoteLocalVersion(folder string) (int64, bool) {
var ver int64 var ver int64
for _, n := range m.folderDevices[folder] { for _, n := range m.folderDevices[folder] {
ver += fs.LocalVersion(n) ver += fs.Sequence(n)
} }
return ver, true return ver, true

View File

@ -179,7 +179,7 @@ func (f *rwFolder) Serve() {
f.setState(FolderIdle) f.setState(FolderIdle)
}() }()
var prevVer int64 var prevSec int64
var prevIgnoreHash string var prevIgnoreHash string
for { for {
@ -188,7 +188,7 @@ func (f *rwFolder) Serve() {
return return
case <-f.remoteIndex: case <-f.remoteIndex:
prevVer = 0 prevSec = 0
f.pullTimer.Reset(0) f.pullTimer.Reset(0)
l.Debugln(f, "remote index updated, rescheduling pull") l.Debugln(f, "remote index updated, rescheduling pull")
@ -210,14 +210,14 @@ func (f *rwFolder) Serve() {
// The ignore patterns have changed. We need to re-evaluate if // The ignore patterns have changed. We need to re-evaluate if
// there are files we need now that were ignored before. // there are files we need now that were ignored before.
l.Debugln(f, "ignore patterns have changed, resetting prevVer") l.Debugln(f, "ignore patterns have changed, resetting prevVer")
prevVer = 0 prevSec = 0
prevIgnoreHash = newHash prevIgnoreHash = newHash
} }
// RemoteLocalVersion() is a fast call, doesn't touch the database. // RemoteSequence() is a fast call, doesn't touch the database.
curVer, ok := f.model.RemoteLocalVersion(f.folderID) curSeq, ok := f.model.RemoteSequence(f.folderID)
if !ok || curVer == prevVer { if !ok || curSeq == prevSec {
l.Debugln(f, "skip (curVer == prevVer)", prevVer, ok) l.Debugln(f, "skip (curSeq == prevSeq)", prevSec, ok)
f.pullTimer.Reset(f.sleep) f.pullTimer.Reset(f.sleep)
continue continue
} }
@ -228,7 +228,7 @@ func (f *rwFolder) Serve() {
continue continue
} }
l.Debugln(f, "pulling", prevVer, curVer) l.Debugln(f, "pulling", prevSec, curSeq)
f.setState(FolderSyncing) f.setState(FolderSyncing)
f.clearErrors() f.clearErrors()
@ -245,19 +245,19 @@ func (f *rwFolder) Serve() {
// sync. Remember the local version number and // sync. Remember the local version number and
// schedule a resync a little bit into the future. // schedule a resync a little bit into the future.
if lv, ok := f.model.RemoteLocalVersion(f.folderID); ok && lv < curVer { if lv, ok := f.model.RemoteSequence(f.folderID); ok && lv < curSeq {
// There's a corner case where the device we needed // There's a corner case where the device we needed
// files from disconnected during the puller // files from disconnected during the puller
// iteration. The files will have been removed from // iteration. The files will have been removed from
// the index, so we've concluded that we don't need // the index, so we've concluded that we don't need
// them, but at the same time we have the local // them, but at the same time we have the local
// version that includes those files in curVer. So we // version that includes those files in curVer. So we
// catch the case that localVersion might have // catch the case that sequence might have
// decreased here. // decreased here.
l.Debugln(f, "adjusting curVer", lv) l.Debugln(f, "adjusting curVer", lv)
curVer = lv curSeq = lv
} }
prevVer = curVer prevSec = curSeq
l.Debugln(f, "next pull in", f.sleep) l.Debugln(f, "next pull in", f.sleep)
f.pullTimer.Reset(f.sleep) f.pullTimer.Reset(f.sleep)
break break
@ -1422,7 +1422,7 @@ loop:
break loop break loop
} }
job.file.LocalVersion = 0 job.file.Sequence = 0
batch = append(batch, job) batch = append(batch, job)
if len(batch) == maxBatchSize { if len(batch) == maxBatchSize {

View File

@ -21,7 +21,7 @@ const (
maxBytesInMemory = 512 << 10 maxBytesInMemory = 512 << 10
) )
// The IndexSorter sorts FileInfos based on their LocalVersion. You use it // The IndexSorter sorts FileInfos based on their Sequence. You use it
// by first Append()ing all entries to be sorted, then calling Sorted() // by first Append()ing all entries to be sorted, then calling Sorted()
// which will iterate over all the items in correctly sorted order. // which will iterate over all the items in correctly sorted order.
type IndexSorter interface { type IndexSorter interface {
@ -88,7 +88,7 @@ func (s *inMemoryIndexSorter) Append(f protocol.FileInfo) {
} }
func (s *inMemoryIndexSorter) Sorted(fn func(protocol.FileInfo) bool) { func (s *inMemoryIndexSorter) Sorted(fn func(protocol.FileInfo) bool) {
sort.Sort(byLocalVersion(s.files)) sort.Sort(bySequence(s.files))
for _, f := range s.files { for _, f := range s.files {
if !fn(f) { if !fn(f) {
break break
@ -109,22 +109,22 @@ func (s *inMemoryIndexSorter) copyTo(dst IndexSorter) {
} }
} }
// byLocalVersion sorts FileInfos by LocalVersion // bySequence sorts FileInfos by Sequence
type byLocalVersion []protocol.FileInfo type bySequence []protocol.FileInfo
func (l byLocalVersion) Len() int { func (l bySequence) Len() int {
return len(l) return len(l)
} }
func (l byLocalVersion) Swap(a, b int) { func (l bySequence) Swap(a, b int) {
l[a], l[b] = l[b], l[a] l[a], l[b] = l[b], l[a]
} }
func (l byLocalVersion) Less(a, b int) bool { func (l bySequence) Less(a, b int) bool {
return l[a].LocalVersion < l[b].LocalVersion return l[a].Sequence < l[b].Sequence
} }
// An onDiskIndexSorter is backed by a LevelDB database in the temporary // An onDiskIndexSorter is backed by a LevelDB database in the temporary
// directory. It relies on the fact that iterating over the database is done // directory. It relies on the fact that iterating over the database is done
// in key order and uses the LocalVersion as key. When done with an // in key order and uses the Sequence as key. When done with an
// onDiskIndexSorter you must call Close() to remove the temporary database. // onDiskIndexSorter you must call Close() to remove the temporary database.
type onDiskIndexSorter struct { type onDiskIndexSorter struct {
db *leveldb.DB db *leveldb.DB
@ -158,7 +158,7 @@ func newOnDiskIndexSorter(location string) *onDiskIndexSorter {
func (s *onDiskIndexSorter) Append(f protocol.FileInfo) { func (s *onDiskIndexSorter) Append(f protocol.FileInfo) {
key := make([]byte, 8) key := make([]byte, 8)
binary.BigEndian.PutUint64(key[:], uint64(f.LocalVersion)) binary.BigEndian.PutUint64(key[:], uint64(f.Sequence))
data, err := f.Marshal() data, err := f.Marshal()
if err != nil { if err != nil {
panic("bug: marshalling FileInfo should never fail: " + err.Error()) panic("bug: marshalling FileInfo should never fail: " + err.Error())

View File

@ -95,17 +95,17 @@ func TestIndexSorter(t *testing.T) {
verifySorted(t, s, nFiles+1) verifySorted(t, s, nFiles+1)
} }
// addFiles adds files with random LocalVersion to the Sorter. // addFiles adds files with random Sequence to the Sorter.
func addFiles(n int, s IndexSorter) { func addFiles(n int, s IndexSorter) {
for i := 0; i < n; i++ { for i := 0; i < n; i++ {
rnd := rand.Int63() rnd := rand.Int63()
f := protocol.FileInfo{ f := protocol.FileInfo{
Name: fmt.Sprintf("file-%d", rnd), Name: fmt.Sprintf("file-%d", rnd),
Size: rand.Int63(), Size: rand.Int63(),
Permissions: uint32(rand.Intn(0777)), Permissions: uint32(rand.Intn(0777)),
Modified: rand.Int63(), Modified: rand.Int63(),
LocalVersion: rnd, Sequence: rnd,
Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: uint64(rand.Int63())}}}, Version: protocol.Vector{Counters: []protocol.Counter{{ID: 42, Value: uint64(rand.Int63())}}},
Blocks: []protocol.BlockInfo{{ Blocks: []protocol.BlockInfo{{
Size: int32(rand.Intn(128 << 10)), Size: int32(rand.Intn(128 << 10)),
Hash: []byte(rand.String(32)), Hash: []byte(rand.String(32)),
@ -115,15 +115,15 @@ func addFiles(n int, s IndexSorter) {
} }
} }
// verifySorted checks that the files are returned sorted by LocalVersion. // verifySorted checks that the files are returned sorted by Sequence.
func verifySorted(t *testing.T, s IndexSorter, expected int) { func verifySorted(t *testing.T, s IndexSorter, expected int) {
prevLocalVer := int64(-1) prevSequence := int64(-1)
seen := 0 seen := 0
s.Sorted(func(f protocol.FileInfo) bool { s.Sorted(func(f protocol.FileInfo) bool {
if f.LocalVersion <= prevLocalVer { if f.Sequence <= prevSequence {
t.Fatalf("Unsorted LocalVer, %d <= %d", f.LocalVersion, prevLocalVer) t.Fatalf("Unsorted Sequence, %d <= %d", f.Sequence, prevSequence)
} }
prevLocalVer = f.LocalVersion prevSequence = f.Sequence
seen++ seen++
return true return true
}) })
@ -134,11 +134,11 @@ func verifySorted(t *testing.T, s IndexSorter, expected int) {
// verifyBreak checks that the Sorter stops iteration once we return false. // verifyBreak checks that the Sorter stops iteration once we return false.
func verifyBreak(t *testing.T, s IndexSorter, expected int) { func verifyBreak(t *testing.T, s IndexSorter, expected int) {
prevLocalVer := int64(-1) prevSequence := int64(-1)
seen := 0 seen := 0
s.Sorted(func(f protocol.FileInfo) bool { s.Sorted(func(f protocol.FileInfo) bool {
if f.LocalVersion <= prevLocalVer { if f.Sequence <= prevSequence {
t.Fatalf("Unsorted LocalVer, %d <= %d", f.LocalVersion, prevLocalVer) t.Fatalf("Unsorted Sequence, %d <= %d", f.Sequence, prevSequence)
} }
if len(f.Blocks) != 1 { if len(f.Blocks) != 1 {
t.Fatalf("incorrect number of blocks %d != 1", len(f.Blocks)) t.Fatalf("incorrect number of blocks %d != 1", len(f.Blocks))
@ -146,7 +146,7 @@ func verifyBreak(t *testing.T, s IndexSorter, expected int) {
if len(f.Version.Counters) != 1 { if len(f.Version.Counters) != 1 {
t.Fatalf("incorrect number of version counters %d != 1", len(f.Version.Counters)) t.Fatalf("incorrect number of version counters %d != 1", len(f.Version.Counters))
} }
prevLocalVer = f.LocalVersion prevSequence = f.Sequence
seen++ seen++
return seen < expected/2 return seen < expected/2
}) })

View File

@ -255,14 +255,14 @@ func (*Folder) ProtoMessage() {}
func (*Folder) Descriptor() ([]byte, []int) { return fileDescriptorBep, []int{3} } func (*Folder) Descriptor() ([]byte, []int) { return fileDescriptorBep, []int{3} }
type Device struct { type Device struct {
ID []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` ID []byte `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Addresses []string `protobuf:"bytes,3,rep,name=addresses" json:"addresses,omitempty"` Addresses []string `protobuf:"bytes,3,rep,name=addresses" json:"addresses,omitempty"`
Compression Compression `protobuf:"varint,4,opt,name=compression,proto3,enum=protocol.Compression" json:"compression,omitempty"` Compression Compression `protobuf:"varint,4,opt,name=compression,proto3,enum=protocol.Compression" json:"compression,omitempty"`
CertName string `protobuf:"bytes,5,opt,name=cert_name,json=certName,proto3" json:"cert_name,omitempty"` CertName string `protobuf:"bytes,5,opt,name=cert_name,json=certName,proto3" json:"cert_name,omitempty"`
MaxLocalVersion int64 `protobuf:"varint,6,opt,name=max_local_version,json=maxLocalVersion,proto3" json:"max_local_version,omitempty"` MaxSequence int64 `protobuf:"varint,6,opt,name=max_sequence,json=maxSequence,proto3" json:"max_sequence,omitempty"`
Introducer bool `protobuf:"varint,7,opt,name=introducer,proto3" json:"introducer,omitempty"` Introducer bool `protobuf:"varint,7,opt,name=introducer,proto3" json:"introducer,omitempty"`
IndexID IndexID `protobuf:"varint,8,opt,name=index_id,json=indexId,proto3,customtype=IndexID" json:"index_id"` IndexID IndexID `protobuf:"varint,8,opt,name=index_id,json=indexId,proto3,customtype=IndexID" json:"index_id"`
} }
func (m *Device) Reset() { *m = Device{} } func (m *Device) Reset() { *m = Device{} }
@ -300,7 +300,7 @@ type FileInfo struct {
Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"` Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"`
NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"` NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"`
Version Vector `protobuf:"bytes,9,opt,name=version" json:"version"` Version Vector `protobuf:"bytes,9,opt,name=version" json:"version"`
LocalVersion int64 `protobuf:"varint,10,opt,name=local_version,json=localVersion,proto3" json:"local_version,omitempty"` Sequence int64 `protobuf:"varint,10,opt,name=sequence,proto3" json:"sequence,omitempty"`
Blocks []BlockInfo `protobuf:"bytes,16,rep,name=Blocks,json=blocks" json:"Blocks"` Blocks []BlockInfo `protobuf:"bytes,16,rep,name=Blocks,json=blocks" json:"Blocks"`
} }
@ -658,10 +658,10 @@ func (m *Device) MarshalTo(data []byte) (int, error) {
i = encodeVarintBep(data, i, uint64(len(m.CertName))) i = encodeVarintBep(data, i, uint64(len(m.CertName)))
i += copy(data[i:], m.CertName) i += copy(data[i:], m.CertName)
} }
if m.MaxLocalVersion != 0 { if m.MaxSequence != 0 {
data[i] = 0x30 data[i] = 0x30
i++ i++
i = encodeVarintBep(data, i, uint64(m.MaxLocalVersion)) i = encodeVarintBep(data, i, uint64(m.MaxSequence))
} }
if m.Introducer { if m.Introducer {
data[i] = 0x38 data[i] = 0x38
@ -832,10 +832,10 @@ func (m *FileInfo) MarshalTo(data []byte) (int, error) {
return 0, err return 0, err
} }
i += n1 i += n1
if m.LocalVersion != 0 { if m.Sequence != 0 {
data[i] = 0x50 data[i] = 0x50
i++ i++
i = encodeVarintBep(data, i, uint64(m.LocalVersion)) i = encodeVarintBep(data, i, uint64(m.Sequence))
} }
if len(m.Blocks) > 0 { if len(m.Blocks) > 0 {
for _, msg := range m.Blocks { for _, msg := range m.Blocks {
@ -1288,8 +1288,8 @@ func (m *Device) ProtoSize() (n int) {
if l > 0 { if l > 0 {
n += 1 + l + sovBep(uint64(l)) n += 1 + l + sovBep(uint64(l))
} }
if m.MaxLocalVersion != 0 { if m.MaxSequence != 0 {
n += 1 + sovBep(uint64(m.MaxLocalVersion)) n += 1 + sovBep(uint64(m.MaxSequence))
} }
if m.Introducer { if m.Introducer {
n += 2 n += 2
@ -1362,8 +1362,8 @@ func (m *FileInfo) ProtoSize() (n int) {
} }
l = m.Version.ProtoSize() l = m.Version.ProtoSize()
n += 1 + l + sovBep(uint64(l)) n += 1 + l + sovBep(uint64(l))
if m.LocalVersion != 0 { if m.Sequence != 0 {
n += 1 + sovBep(uint64(m.LocalVersion)) n += 1 + sovBep(uint64(m.Sequence))
} }
if len(m.Blocks) > 0 { if len(m.Blocks) > 0 {
for _, e := range m.Blocks { for _, e := range m.Blocks {
@ -2218,9 +2218,9 @@ func (m *Device) Unmarshal(data []byte) error {
iNdEx = postIndex iNdEx = postIndex
case 6: case 6:
if wireType != 0 { if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field MaxLocalVersion", wireType) return fmt.Errorf("proto: wrong wireType = %d for field MaxSequence", wireType)
} }
m.MaxLocalVersion = 0 m.MaxSequence = 0
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowBep return ErrIntOverflowBep
@ -2230,7 +2230,7 @@ func (m *Device) Unmarshal(data []byte) error {
} }
b := data[iNdEx] b := data[iNdEx]
iNdEx++ iNdEx++
m.MaxLocalVersion |= (int64(b) & 0x7F) << shift m.MaxSequence |= (int64(b) & 0x7F) << shift
if b < 0x80 { if b < 0x80 {
break break
} }
@ -2741,9 +2741,9 @@ func (m *FileInfo) Unmarshal(data []byte) error {
iNdEx = postIndex iNdEx = postIndex
case 10: case 10:
if wireType != 0 { if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field LocalVersion", wireType) return fmt.Errorf("proto: wrong wireType = %d for field Sequence", wireType)
} }
m.LocalVersion = 0 m.Sequence = 0
for shift := uint(0); ; shift += 7 { for shift := uint(0); ; shift += 7 {
if shift >= 64 { if shift >= 64 {
return ErrIntOverflowBep return ErrIntOverflowBep
@ -2753,7 +2753,7 @@ func (m *FileInfo) Unmarshal(data []byte) error {
} }
b := data[iNdEx] b := data[iNdEx]
iNdEx++ iNdEx++
m.LocalVersion |= (int64(b) & 0x7F) << shift m.Sequence |= (int64(b) & 0x7F) << shift
if b < 0x80 { if b < 0x80 {
break break
} }
@ -3927,103 +3927,103 @@ var (
var fileDescriptorBep = []byte{ var fileDescriptorBep = []byte{
// 1569 bytes of a gzipped FileDescriptorProto // 1569 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x6f, 0x1b, 0x45, 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xac, 0x56, 0x4f, 0x6f, 0xdb, 0x46,
0x14, 0x8f, 0xed, 0xf5, 0xbf, 0x89, 0x93, 0x3a, 0xd3, 0x34, 0x35, 0xdb, 0x90, 0x84, 0x6d, 0x2b, 0x16, 0xb7, 0x24, 0x8a, 0x92, 0x46, 0xb2, 0x23, 0x4f, 0x1c, 0x47, 0xcb, 0x78, 0x6d, 0x2f, 0x93,
0x82, 0x45, 0x53, 0x68, 0x81, 0x4a, 0x48, 0x20, 0x39, 0xf6, 0x26, 0xb5, 0xea, 0xac, 0xdd, 0xb5, 0x60, 0xbd, 0xc2, 0xc6, 0xd9, 0x4d, 0xda, 0x06, 0x28, 0xd0, 0x02, 0xb2, 0x44, 0x3b, 0x44, 0x64,
0x9d, 0x52, 0x0e, 0x58, 0x6b, 0xef, 0xd8, 0x59, 0x75, 0xbd, 0x63, 0x76, 0xd7, 0x6d, 0xc3, 0x17, 0x4a, 0xa1, 0x24, 0xa7, 0xe9, 0xa1, 0x02, 0x25, 0x8e, 0x64, 0x22, 0x14, 0x47, 0x25, 0xa9, 0x24,
0x40, 0x82, 0x2f, 0xc0, 0x05, 0xa9, 0x57, 0xc4, 0x95, 0x0f, 0xd1, 0x63, 0xd5, 0x23, 0x87, 0x0a, 0xee, 0x47, 0x68, 0xbf, 0x40, 0x2f, 0x05, 0x82, 0xde, 0x7a, 0xef, 0x87, 0xc8, 0x31, 0xc8, 0xb1,
0xc2, 0x85, 0x2f, 0xc0, 0x9d, 0x37, 0x33, 0xbb, 0xde, 0x75, 0xfe, 0xa0, 0x1e, 0x38, 0x58, 0x9e, 0x87, 0xa0, 0x75, 0x2f, 0xfd, 0x02, 0xbd, 0x16, 0x7d, 0x9c, 0x21, 0x45, 0xca, 0x7f, 0x8a, 0x1c,
0x79, 0xef, 0x37, 0x6f, 0x66, 0x7e, 0xef, 0xf7, 0xde, 0x2c, 0xca, 0xf7, 0xc9, 0x64, 0x67, 0xe2, 0x7a, 0x10, 0x34, 0xf3, 0xde, 0x6f, 0xde, 0xcc, 0xfc, 0xde, 0xef, 0xbd, 0x21, 0x2a, 0x0c, 0xc8,
0x52, 0x9f, 0xe2, 0x1c, 0xff, 0x1b, 0x50, 0x5b, 0xbe, 0x35, 0xb2, 0xfc, 0xa3, 0x69, 0x7f, 0x67, 0x74, 0x77, 0xea, 0x52, 0x9f, 0xe2, 0x3c, 0xfb, 0x1b, 0x52, 0x5b, 0xba, 0x33, 0xb6, 0xfc, 0xe3,
0x40, 0xc7, 0xb7, 0x47, 0x74, 0x44, 0x6f, 0x73, 0x4f, 0x7f, 0x3a, 0xe4, 0x33, 0x3e, 0xe1, 0x23, 0xd9, 0x60, 0x77, 0x48, 0x27, 0x77, 0xc7, 0x74, 0x4c, 0xef, 0x32, 0xcf, 0x60, 0x36, 0x62, 0x33,
0xb1, 0x50, 0x99, 0xa0, 0xf4, 0x7d, 0x62, 0xdb, 0x14, 0x6f, 0xa2, 0x45, 0x93, 0x3c, 0xb5, 0x06, 0x36, 0x61, 0x23, 0xbe, 0x50, 0x9e, 0xa2, 0xec, 0x43, 0x62, 0xdb, 0x14, 0x6f, 0xa1, 0xa2, 0x49,
0xa4, 0xe7, 0x18, 0x63, 0x52, 0x4a, 0x6c, 0x25, 0xb6, 0xf3, 0x3a, 0x12, 0x26, 0x0d, 0x2c, 0x0c, 0x9e, 0x5b, 0x43, 0xd2, 0x77, 0x8c, 0x09, 0xa9, 0xa4, 0xb6, 0x53, 0x3b, 0x05, 0x1d, 0x71, 0x93,
0x30, 0xb0, 0x2d, 0xe2, 0xf8, 0x02, 0x90, 0x14, 0x00, 0x61, 0xe2, 0x80, 0x9b, 0x68, 0x39, 0x00, 0x06, 0x96, 0x00, 0x30, 0xb4, 0x2d, 0xe2, 0xf8, 0x1c, 0x90, 0xe6, 0x00, 0x6e, 0x62, 0x80, 0xdb,
0x3c, 0x25, 0xae, 0x67, 0x51, 0xa7, 0x94, 0xe2, 0x98, 0x25, 0x61, 0x3d, 0x14, 0x46, 0xc5, 0x43, 0x68, 0x25, 0x04, 0x3c, 0x27, 0xae, 0x67, 0x51, 0xa7, 0x92, 0x61, 0x98, 0x65, 0x6e, 0x3d, 0xe2,
0x99, 0xfb, 0xc4, 0x30, 0x89, 0x8b, 0x3f, 0x40, 0x92, 0x7f, 0x3c, 0x11, 0x7b, 0x2d, 0xdf, 0xb9, 0x46, 0xd9, 0x43, 0xe2, 0x43, 0x62, 0x98, 0xc4, 0xc5, 0xff, 0x41, 0x82, 0x7f, 0x32, 0xe5, 0x7b,
0xb2, 0x13, 0xde, 0x61, 0xe7, 0x80, 0x78, 0x9e, 0x31, 0x22, 0x1d, 0x70, 0xea, 0x1c, 0x82, 0xbf, 0xad, 0xdc, 0xbb, 0xb6, 0x1b, 0xdd, 0x61, 0xf7, 0x90, 0x78, 0x9e, 0x31, 0x26, 0x5d, 0x70, 0xea,
0x84, 0xcd, 0xe9, 0x78, 0xe2, 0x82, 0x83, 0x05, 0x4e, 0xf2, 0x15, 0xeb, 0x67, 0x56, 0x54, 0x23, 0x0c, 0x82, 0x3f, 0x85, 0xcd, 0xe9, 0x64, 0xea, 0x82, 0x23, 0x08, 0x9c, 0x66, 0x2b, 0x36, 0xce,
0x8c, 0x1e, 0x5f, 0xa0, 0x54, 0xd0, 0x52, 0xd5, 0x9e, 0x7a, 0x3e, 0x71, 0xab, 0xd4, 0x19, 0x5a, 0xad, 0xa8, 0xc7, 0x18, 0x3d, 0xb9, 0x40, 0xae, 0xa1, 0xe5, 0xba, 0x3d, 0xf3, 0x7c, 0xe2, 0xd6,
0x23, 0xfc, 0x11, 0xca, 0x0e, 0xa9, 0x0d, 0xa7, 0xf0, 0x60, 0xfb, 0xd4, 0xf6, 0xe2, 0x9d, 0x62, 0xa9, 0x33, 0xb2, 0xc6, 0xf8, 0x7f, 0x28, 0x37, 0xa2, 0x36, 0x9c, 0xc2, 0x83, 0xed, 0x33, 0x3b,
0x14, 0x6c, 0x8f, 0x3b, 0x76, 0xa5, 0x97, 0x6f, 0x36, 0x17, 0xf4, 0x10, 0xa6, 0xfc, 0x98, 0x44, 0xc5, 0x7b, 0xe5, 0x38, 0xd8, 0x3e, 0x73, 0xec, 0x09, 0xaf, 0xdf, 0x6d, 0x2d, 0xe9, 0x11, 0x4c,
0x19, 0xe1, 0xc1, 0x6b, 0x28, 0x69, 0x99, 0x82, 0xa2, 0xdd, 0xcc, 0xc9, 0x9b, 0xcd, 0x64, 0xbd, 0xfe, 0x26, 0x8d, 0x44, 0xee, 0xc1, 0xeb, 0x28, 0x6d, 0x99, 0x9c, 0xa2, 0x3d, 0xf1, 0xf4, 0xdd,
0xa6, 0x83, 0x05, 0xaf, 0xa2, 0xb4, 0x6d, 0xf4, 0x89, 0x1d, 0x90, 0x23, 0x26, 0xf8, 0x1a, 0xca, 0x56, 0x5a, 0x6d, 0xe8, 0x60, 0xc1, 0x6b, 0x28, 0x6b, 0x1b, 0x03, 0x62, 0x87, 0xe4, 0xf0, 0x09,
0xbb, 0x70, 0xe1, 0x1e, 0x75, 0xec, 0x63, 0x4e, 0x49, 0x4e, 0xcf, 0x31, 0x43, 0x13, 0xe6, 0xf8, 0xbe, 0x81, 0x0a, 0x2e, 0x5c, 0xb8, 0x4f, 0x1d, 0xfb, 0x84, 0x51, 0x92, 0xd7, 0xf3, 0x81, 0xa1,
0x16, 0xc2, 0xd6, 0xc8, 0xa1, 0x2e, 0xe9, 0x4d, 0x88, 0x3b, 0xb6, 0xf8, 0x69, 0xbd, 0x92, 0xc4, 0x05, 0x73, 0x7c, 0x07, 0x61, 0x6b, 0xec, 0x50, 0x97, 0xf4, 0xa7, 0xc4, 0x9d, 0x58, 0xec, 0xb4,
0x51, 0x2b, 0xc2, 0xd3, 0x8a, 0x1c, 0xf8, 0x3a, 0x5a, 0x0a, 0xe0, 0x26, 0xb1, 0x89, 0x4f, 0x4a, 0x5e, 0x45, 0x60, 0xa8, 0x55, 0xee, 0x69, 0xc7, 0x0e, 0x7c, 0x13, 0x2d, 0x87, 0x70, 0x93, 0xd8,
0x69, 0x8e, 0x2c, 0x08, 0x63, 0x8d, 0xdb, 0xe0, 0x6e, 0xab, 0xa6, 0xe5, 0x19, 0x7d, 0x9b, 0xf4, 0xc4, 0x27, 0x95, 0x2c, 0x43, 0x96, 0xb8, 0xb1, 0xc1, 0x6c, 0x70, 0xb7, 0x35, 0xd3, 0xf2, 0x8c,
0x7c, 0x32, 0x9e, 0xf4, 0x2c, 0xc7, 0x24, 0xcf, 0x89, 0x57, 0xca, 0x70, 0x2c, 0x0e, 0x7c, 0x1d, 0x81, 0x4d, 0xfa, 0x3e, 0x99, 0x4c, 0xfb, 0x96, 0x63, 0x92, 0x97, 0xc4, 0xab, 0x88, 0x0c, 0x8b,
0x70, 0xd5, 0x85, 0x87, 0xb1, 0x21, 0x32, 0xed, 0x95, 0x8a, 0xa7, 0xd9, 0xa8, 0x71, 0x47, 0xc8, 0x43, 0x5f, 0x17, 0x5c, 0x2a, 0xf7, 0x04, 0x6c, 0xf0, 0x4c, 0x7b, 0x95, 0xf2, 0x59, 0x36, 0x1a,
0x46, 0x00, 0x53, 0x7e, 0x05, 0x36, 0x84, 0x27, 0xc6, 0x46, 0x61, 0x8e, 0x0d, 0x8c, 0xa4, 0x98, 0xcc, 0x11, 0xb1, 0x11, 0xc2, 0xe4, 0xef, 0x81, 0x0d, 0xee, 0x49, 0xb0, 0x51, 0x5a, 0x60, 0x03,
0x52, 0xf8, 0x18, 0xaf, 0xa3, 0xbc, 0x61, 0x9a, 0x2c, 0x2b, 0xb0, 0x55, 0x0a, 0xb6, 0xca, 0xeb, 0x23, 0x21, 0xa1, 0x14, 0x36, 0xc6, 0x1b, 0xa8, 0x60, 0x98, 0x66, 0x90, 0x15, 0xd8, 0x2a, 0x03,
0x91, 0x01, 0xdf, 0x9b, 0xcf, 0xb2, 0x74, 0x5a, 0x17, 0x17, 0xa5, 0x97, 0x51, 0x3c, 0x20, 0x6e, 0x5b, 0x15, 0xf4, 0xd8, 0x80, 0x1f, 0x2c, 0x66, 0x59, 0x38, 0xab, 0x8b, 0xcb, 0xd2, 0x1b, 0x50,
0xa0, 0xcc, 0x34, 0xdf, 0x2f, 0xc7, 0x0c, 0x5c, 0x97, 0x65, 0xb4, 0x32, 0x36, 0x9e, 0xf7, 0x6c, 0x3c, 0x24, 0x6e, 0xa8, 0xcc, 0x2c, 0xdb, 0x2f, 0x1f, 0x18, 0x98, 0x2e, 0xff, 0x85, 0x4a, 0x13,
0x3a, 0x30, 0xec, 0x99, 0x34, 0x19, 0x17, 0x29, 0xfd, 0x12, 0x38, 0x1a, 0xcc, 0x1e, 0x88, 0x13, 0xe3, 0x65, 0xdf, 0x23, 0x5f, 0xce, 0x88, 0x33, 0x24, 0x8c, 0x86, 0x8c, 0x5e, 0x04, 0x5b, 0x27,
0x6f, 0x20, 0x64, 0x39, 0xbe, 0x4b, 0xcd, 0x29, 0x2c, 0x2f, 0x65, 0x39, 0x61, 0x31, 0x0b, 0xfe, 0x34, 0xe1, 0x4d, 0x84, 0x2c, 0xc7, 0x77, 0xa9, 0x39, 0x83, 0x55, 0x95, 0x1c, 0xe3, 0x29, 0x61,
0x14, 0xe5, 0x38, 0x9b, 0x3d, 0xb8, 0x71, 0x0e, 0xbc, 0xd2, 0xae, 0xcc, 0x78, 0xf9, 0xfd, 0xcd, 0xc1, 0x1f, 0xa2, 0x3c, 0x23, 0xb1, 0x0f, 0x17, 0xcd, 0x83, 0x57, 0xd8, 0x93, 0x02, 0x3a, 0x7e,
0x66, 0x96, 0x73, 0x59, 0xaf, 0x9d, 0x44, 0x43, 0x3d, 0xcb, 0xb1, 0x75, 0x53, 0x69, 0xa2, 0x34, 0x7a, 0xb7, 0x95, 0x63, 0x14, 0xaa, 0x8d, 0xd3, 0x78, 0xa8, 0xe7, 0x18, 0x56, 0x35, 0xe5, 0x16,
0xb7, 0x01, 0x57, 0x19, 0xa1, 0xa7, 0xa0, 0xc0, 0x82, 0x19, 0xde, 0x41, 0xe9, 0xa1, 0x65, 0x03, 0xca, 0x32, 0x1b, 0x50, 0x24, 0x72, 0x19, 0x85, 0x75, 0x15, 0xce, 0xf0, 0x2e, 0xca, 0x8e, 0x2c,
0x27, 0x49, 0x4e, 0x3f, 0x8e, 0x89, 0x11, 0xcc, 0x75, 0x67, 0x48, 0x83, 0x04, 0x08, 0x98, 0xd2, 0x1b, 0xa8, 0x48, 0x33, 0xd6, 0x71, 0x42, 0x83, 0x60, 0x56, 0x9d, 0x11, 0x0d, 0x79, 0xe7, 0x30,
0x45, 0x8b, 0x3c, 0x60, 0x77, 0x62, 0x1a, 0x3e, 0xf9, 0xdf, 0xc2, 0x7e, 0x9f, 0x42, 0xb9, 0xd0, 0xb9, 0x87, 0x8a, 0x2c, 0x60, 0x6f, 0x6a, 0x1a, 0x3e, 0xf9, 0xdb, 0xc2, 0xfe, 0x91, 0x46, 0xf9,
0x33, 0xcb, 0x5f, 0x22, 0x96, 0xbf, 0x72, 0x50, 0xb2, 0xa2, 0x00, 0xd7, 0xce, 0xc6, 0x8b, 0xd5, 0xc8, 0x33, 0x4f, 0x5b, 0x2a, 0x91, 0xb6, 0x6a, 0x58, 0xa9, 0xbc, 0xee, 0xd6, 0xcf, 0xc7, 0x4b,
0x2c, 0xac, 0xf7, 0xac, 0xef, 0x08, 0x97, 0x7c, 0x4a, 0xe7, 0x63, 0xbc, 0x85, 0x16, 0x4f, 0xeb, 0x94, 0x2a, 0xac, 0xf7, 0xac, 0xaf, 0x08, 0x53, 0x7a, 0x46, 0x67, 0x63, 0xbc, 0x8d, 0x8a, 0x67,
0x7c, 0x49, 0x8f, 0x9b, 0xb0, 0x8c, 0x72, 0x63, 0x6a, 0x5a, 0x43, 0x8b, 0x98, 0x3c, 0x93, 0x29, 0xe5, 0xbd, 0xac, 0x27, 0x4d, 0x58, 0x42, 0xf9, 0x09, 0x35, 0xad, 0x91, 0x45, 0x4c, 0x96, 0xc0,
0x7d, 0x36, 0xc7, 0x25, 0x26, 0x53, 0x26, 0x71, 0x33, 0xd0, 0x72, 0x38, 0x65, 0x1e, 0xcb, 0x79, 0x8c, 0x3e, 0x9f, 0xe3, 0x4a, 0xa0, 0xce, 0x40, 0xd9, 0x66, 0x28, 0xe1, 0x68, 0x1a, 0x78, 0x2c,
0x6a, 0xd8, 0x90, 0x16, 0x91, 0xb4, 0x70, 0xca, 0xba, 0x92, 0x43, 0xe7, 0x8a, 0x2b, 0xc7, 0x01, 0xe7, 0xb9, 0x61, 0x43, 0x5a, 0x78, 0xd2, 0xa2, 0x69, 0xd0, 0x8c, 0x1c, 0xba, 0x50, 0x53, 0x79,
0x4b, 0x0e, 0x8d, 0x17, 0x16, 0x54, 0x40, 0x28, 0x8d, 0x3c, 0xf8, 0xe7, 0x2a, 0xe0, 0x90, 0x0c, 0x06, 0x58, 0x76, 0x68, 0xb2, 0x9e, 0x40, 0xf8, 0x51, 0xb3, 0x2a, 0x80, 0x7f, 0x41, 0xf8, 0x47,
0x7c, 0x3a, 0xeb, 0x07, 0x01, 0x8c, 0x95, 0xe2, 0xbc, 0xa4, 0x10, 0x3f, 0x6d, 0xc1, 0x8e, 0xeb, 0x64, 0xe8, 0xd3, 0x79, 0x1b, 0x08, 0x61, 0xc1, 0x41, 0xe7, 0x4a, 0x42, 0xfc, 0xa0, 0xd1, 0x1c,
0xe9, 0x63, 0x94, 0xd9, 0x05, 0xc3, 0x93, 0xb0, 0xae, 0x2e, 0x47, 0x51, 0xb9, 0x3d, 0x96, 0x82, 0xff, 0x1f, 0x89, 0x7b, 0x36, 0x1d, 0x3e, 0x8b, 0xaa, 0xe8, 0x6a, 0x1c, 0x8c, 0xd9, 0x13, 0xcc,
0x4c, 0x9f, 0x03, 0x3f, 0x97, 0x7e, 0x7a, 0xb1, 0xb9, 0xa0, 0x3c, 0x44, 0xf9, 0x19, 0x80, 0xa5, 0x8b, 0x03, 0x06, 0xfc, 0x58, 0xf8, 0xf6, 0xd5, 0xd6, 0x92, 0xfc, 0x18, 0x15, 0xe6, 0x80, 0x20,
0x97, 0x0e, 0x87, 0x1e, 0xf1, 0x79, 0x2e, 0x52, 0x7a, 0x30, 0x9b, 0x31, 0xcc, 0xb2, 0x91, 0x0e, 0xab, 0x74, 0x34, 0xf2, 0x88, 0xcf, 0x52, 0x90, 0xd1, 0xc3, 0xd9, 0x9c, 0xd8, 0x20, 0x09, 0xd9,
0x18, 0x06, 0xdb, 0x91, 0xe1, 0x1d, 0x71, 0xd6, 0x0b, 0x3a, 0x1f, 0x07, 0x21, 0xbf, 0x40, 0x19, 0x90, 0x58, 0xb0, 0x1d, 0x1b, 0xde, 0x31, 0x23, 0xbb, 0xa4, 0xb3, 0x71, 0x18, 0xf2, 0x13, 0x24,
0x71, 0x13, 0x7c, 0x17, 0xe5, 0x06, 0x74, 0xea, 0xf8, 0x51, 0xf7, 0x5b, 0x89, 0x17, 0x19, 0xf7, 0xf2, 0x0b, 0xe0, 0xfb, 0x28, 0x3f, 0xa4, 0x33, 0xc7, 0x8f, 0x7b, 0xdd, 0x6a, 0xb2, 0xa4, 0x98,
0x04, 0xa7, 0x9a, 0x01, 0x95, 0x3d, 0x94, 0x0d, 0x5c, 0xc0, 0x69, 0x58, 0xf1, 0xd2, 0xee, 0x95, 0x27, 0x3c, 0xd5, 0x1c, 0x28, 0xef, 0xa3, 0x5c, 0xe8, 0x02, 0x2a, 0xa3, 0xfa, 0x16, 0xf6, 0xae,
0x50, 0xff, 0xed, 0x23, 0xea, 0xfa, 0x5c, 0xff, 0xb1, 0x76, 0x08, 0x39, 0x98, 0x8a, 0xf3, 0x49, 0x45, 0xb2, 0xef, 0x1c, 0x53, 0xd7, 0x67, 0xb2, 0x4f, 0x34, 0x3f, 0xa0, 0x7e, 0xc6, 0xcf, 0x27,
0xba, 0x98, 0x28, 0xbf, 0x25, 0x50, 0x56, 0x27, 0xdf, 0x4e, 0x89, 0xe7, 0xc7, 0x5a, 0x47, 0x7a, 0xe8, 0x7c, 0x22, 0xff, 0x98, 0x42, 0x39, 0x3d, 0xe0, 0xc7, 0xf3, 0x13, 0x8d, 0x22, 0xbb, 0xd0,
0xae, 0x75, 0x44, 0x7a, 0x4e, 0xce, 0xe9, 0x39, 0x94, 0x64, 0x2a, 0x26, 0xc9, 0x88, 0x1c, 0xe9, 0x28, 0x62, 0x19, 0xa7, 0x17, 0x64, 0x1c, 0x29, 0x31, 0x93, 0x50, 0x62, 0x4c, 0x8e, 0x70, 0x21,
0x5c, 0x72, 0xd2, 0xe7, 0x90, 0x93, 0x89, 0xc8, 0x61, 0x02, 0x19, 0xba, 0x74, 0xcc, 0x5b, 0x25, 0x39, 0xd9, 0x0b, 0xc8, 0x11, 0x63, 0x72, 0x02, 0x5d, 0x8c, 0x5c, 0x3a, 0x61, 0x8d, 0x91, 0xba,
0x75, 0x0d, 0xf7, 0x38, 0x50, 0xd0, 0x12, 0xb3, 0x76, 0x42, 0xa3, 0xd2, 0x43, 0x39, 0x9d, 0x78, 0x86, 0x7b, 0x12, 0x0a, 0x67, 0x39, 0xb0, 0x76, 0x23, 0xa3, 0xdc, 0x47, 0x79, 0x9d, 0x78, 0x53,
0x13, 0xd0, 0x0a, 0xb9, 0xf0, 0xd8, 0x10, 0x1e, 0xca, 0xd1, 0xe0, 0x87, 0x86, 0xf0, 0x6c, 0x8c, 0x90, 0x08, 0xb9, 0xf4, 0xd8, 0x10, 0x1e, 0xaa, 0xd0, 0x60, 0x87, 0x86, 0xf0, 0xc1, 0x18, 0xff,
0xdf, 0x47, 0xd2, 0x80, 0x9a, 0xe2, 0xc8, 0xcb, 0xf1, 0xfc, 0xab, 0xae, 0x4b, 0xe1, 0x35, 0x32, 0x1b, 0x09, 0x43, 0x6a, 0xf2, 0x23, 0xaf, 0x24, 0xf3, 0xaf, 0xb8, 0x2e, 0x85, 0xb7, 0xc7, 0x84,
0xa1, 0x5c, 0x18, 0x00, 0x5e, 0xe2, 0x62, 0x8d, 0x3e, 0x73, 0x6c, 0x6a, 0x98, 0x2d, 0x97, 0x8e, 0x2a, 0x09, 0x00, 0xf0, 0xee, 0x96, 0x1b, 0xf4, 0x85, 0x63, 0x53, 0xc3, 0x6c, 0xbb, 0x74, 0x1c,
0x58, 0x6b, 0xbb, 0xb0, 0xae, 0x6b, 0x28, 0x3b, 0xe5, 0x95, 0x1f, 0x56, 0xf6, 0x8d, 0xf9, 0x4a, 0x34, 0xb2, 0x4b, 0xcb, 0xb9, 0x81, 0x72, 0x33, 0x56, 0xf0, 0x51, 0x41, 0xdf, 0x5a, 0x2c, 0xc0,
0x3c, 0x1d, 0x48, 0xb4, 0x89, 0x50, 0xc1, 0xc1, 0x52, 0xe5, 0x75, 0x02, 0xc9, 0x17, 0xa3, 0x71, 0xb3, 0x81, 0x78, 0x77, 0x88, 0x84, 0x1b, 0x2e, 0x95, 0xdf, 0xa6, 0x90, 0x74, 0x39, 0x1a, 0xab,
0x1d, 0x2d, 0x0a, 0x64, 0x2f, 0xf6, 0x4a, 0x6f, 0xbf, 0xcd, 0x46, 0xbc, 0x09, 0xa0, 0xe9, 0x6c, 0xa8, 0xc8, 0x91, 0xfd, 0xc4, 0x9b, 0xbc, 0xf3, 0x3e, 0x1b, 0xb1, 0xda, 0x47, 0xb3, 0xf9, 0xf8,
0x7c, 0xee, 0x53, 0x10, 0xab, 0xb8, 0xd4, 0x5b, 0x57, 0x1c, 0xaf, 0x91, 0xd9, 0x83, 0x26, 0xc1, 0xc2, 0xc6, 0x9f, 0x28, 0xb4, 0xcc, 0xfb, 0x15, 0x1a, 0x3c, 0x75, 0xac, 0x46, 0xe6, 0xcf, 0x97,
0xdd, 0xd3, 0x7a, 0xa1, 0x2f, 0x0a, 0x85, 0xdb, 0x94, 0x0c, 0x92, 0x5a, 0x96, 0x33, 0x52, 0x36, 0x00, 0x77, 0xcf, 0xea, 0xa5, 0x01, 0x2f, 0x14, 0x66, 0x93, 0x45, 0x24, 0xb4, 0x2d, 0x67, 0x2c,
0x51, 0xba, 0x6a, 0x53, 0x9e, 0xac, 0x0c, 0xbc, 0xb6, 0x1e, 0x6c, 0x13, 0x70, 0x28, 0x66, 0xe5, 0x6f, 0xa1, 0x6c, 0xdd, 0xa6, 0x2c, 0x59, 0x22, 0xbc, 0xad, 0x1e, 0x6c, 0x13, 0x72, 0xc8, 0x67,
0xd7, 0x49, 0xb4, 0x18, 0xfb, 0xd0, 0x80, 0xf3, 0x2c, 0x57, 0x1b, 0xdd, 0x76, 0x47, 0xd5, 0x7b, 0xd5, 0xb7, 0x69, 0x54, 0x4c, 0x7c, 0x56, 0xc0, 0x79, 0x56, 0xea, 0xcd, 0x5e, 0xa7, 0xab, 0xe8,
0xd5, 0xa6, 0xb6, 0x57, 0xdf, 0x2f, 0x2e, 0xc8, 0xeb, 0x3f, 0xfc, 0xbc, 0x55, 0x1a, 0x47, 0xa0, 0xfd, 0x7a, 0x4b, 0xdb, 0x57, 0x0f, 0xca, 0x4b, 0xd2, 0xc6, 0xd7, 0xdf, 0x6d, 0x57, 0x26, 0x31,
0xf9, 0x6f, 0x08, 0xd8, 0xa2, 0xae, 0xd5, 0xd4, 0xaf, 0x8a, 0x09, 0x79, 0x15, 0x80, 0xc5, 0x18, 0x68, 0xf1, 0x8b, 0x01, 0xb6, 0x50, 0xb5, 0x86, 0xf2, 0x59, 0x39, 0x25, 0xad, 0x01, 0xb0, 0x9c,
0x50, 0x74, 0xfb, 0x0f, 0x51, 0x81, 0x03, 0x7a, 0xdd, 0x56, 0xad, 0xd2, 0x51, 0x8b, 0x49, 0x59, 0x00, 0xf2, 0x26, 0xff, 0x5f, 0x54, 0x62, 0x80, 0x7e, 0xaf, 0xdd, 0xa8, 0x75, 0x95, 0x72, 0x5a,
0x06, 0xdc, 0xda, 0x69, 0x5c, 0xc0, 0xf7, 0x75, 0xa8, 0x0b, 0xf5, 0x61, 0x57, 0x6d, 0x77, 0x8a, 0x92, 0x00, 0xb7, 0x7e, 0x16, 0x17, 0xf2, 0x7d, 0x13, 0xea, 0x42, 0x79, 0xdc, 0x53, 0x3a, 0xdd,
0x29, 0x79, 0x0d, 0x80, 0x38, 0x06, 0x0c, 0x2b, 0xe6, 0x26, 0xc8, 0x50, 0x6d, 0xb7, 0x9a, 0x5a, 0x72, 0x46, 0x5a, 0x07, 0x20, 0x4e, 0x00, 0xa3, 0x8a, 0xb9, 0x0d, 0x32, 0x54, 0x3a, 0xed, 0x96,
0x5b, 0x2d, 0x4a, 0xf2, 0x55, 0x40, 0x5d, 0x9e, 0x43, 0x05, 0x0a, 0xfd, 0x0c, 0xad, 0xd4, 0x9a, 0xd6, 0x51, 0xca, 0x82, 0x74, 0x1d, 0x50, 0x57, 0x17, 0x50, 0xa1, 0x42, 0x3f, 0x42, 0xab, 0x8d,
0x8f, 0xb4, 0x46, 0xb3, 0x52, 0xeb, 0xb5, 0xf4, 0xe6, 0x3e, 0xac, 0x69, 0x17, 0xd3, 0xf2, 0x26, 0xd6, 0x13, 0xad, 0xd9, 0xaa, 0x35, 0xfa, 0x6d, 0xbd, 0x75, 0x00, 0x6b, 0x3a, 0xe5, 0xac, 0xb4,
0xe0, 0xaf, 0xc5, 0xf0, 0x67, 0x04, 0xf7, 0x2e, 0xb0, 0x57, 0xd7, 0xf6, 0x8b, 0x19, 0xf9, 0x32, 0x05, 0xf8, 0x1b, 0x09, 0xfc, 0x39, 0xc1, 0xfd, 0x13, 0xd8, 0x53, 0xb5, 0x83, 0xb2, 0x28, 0x5d,
0x40, 0x2f, 0xc5, 0xa0, 0x8c, 0x54, 0x76, 0xe3, 0x6a, 0xa3, 0x09, 0x5b, 0x67, 0xcf, 0xdc, 0x98, 0x05, 0xe8, 0x95, 0x04, 0x34, 0x20, 0x35, 0xb8, 0x71, 0xbd, 0xd9, 0x82, 0xad, 0x73, 0xe7, 0x6e,
0x93, 0x5d, 0xfe, 0x06, 0xe1, 0xb3, 0x9f, 0x62, 0xf8, 0x06, 0x92, 0xb4, 0xa6, 0xa6, 0x02, 0xa1, 0xcc, 0xc8, 0xae, 0x7e, 0x81, 0xf0, 0xf9, 0x0f, 0x2f, 0x7c, 0x0b, 0x09, 0x5a, 0x4b, 0x53, 0x80,
0xfc, 0xfe, 0x67, 0x11, 0x1a, 0x75, 0x08, 0x56, 0x50, 0xaa, 0xf1, 0xf5, 0x27, 0x40, 0xe6, 0x3b, 0x50, 0x76, 0xff, 0xf3, 0x08, 0x8d, 0x3a, 0x04, 0xcb, 0x28, 0xd3, 0xfc, 0xfc, 0x03, 0x20, 0xf3,
0x00, 0xba, 0x72, 0x16, 0x04, 0xce, 0x32, 0x45, 0x8b, 0xf1, 0xc0, 0x0a, 0xca, 0x1d, 0xa8, 0x9d, 0x1f, 0x00, 0xba, 0x76, 0x1e, 0x04, 0xce, 0x2a, 0x45, 0xc5, 0x64, 0x60, 0x19, 0xe5, 0x0f, 0x95,
0x0a, 0x90, 0x5b, 0x81, 0xe0, 0xfc, 0x48, 0xa1, 0xfb, 0x80, 0xf8, 0x06, 0x2f, 0xc0, 0x75, 0x94, 0x6e, 0x0d, 0xc8, 0xad, 0x41, 0x70, 0x76, 0xa4, 0xc8, 0x7d, 0x48, 0x7c, 0x83, 0x15, 0xe0, 0x06,
0xd6, 0xd4, 0x43, 0x55, 0x87, 0xc0, 0x2b, 0x00, 0x58, 0x0a, 0x01, 0x1a, 0x01, 0x5d, 0xc1, 0x83, 0xca, 0x6a, 0xca, 0x91, 0xa2, 0x43, 0xe0, 0x55, 0x00, 0x2c, 0x47, 0x00, 0x8d, 0x80, 0xae, 0xe0,
0x9f, 0xa9, 0x34, 0x1e, 0x55, 0x1e, 0xb7, 0x21, 0x39, 0x18, 0xdc, 0xcb, 0xa1, 0xbb, 0x62, 0x3f, 0x9d, 0x17, 0x6b, 0xcd, 0x27, 0xb5, 0xa7, 0x1d, 0x48, 0x0e, 0x06, 0xf7, 0x4a, 0xe4, 0xae, 0xd9,
0x33, 0x8e, 0xbd, 0xf2, 0x3f, 0x09, 0x54, 0x88, 0xbf, 0x6d, 0xb0, 0x40, 0xda, 0xab, 0x37, 0xd4, 0x2f, 0x8c, 0x13, 0xaf, 0xfa, 0x7b, 0x0a, 0x95, 0x92, 0x4f, 0x1a, 0x2c, 0x10, 0xf6, 0xd5, 0xa6,
0x70, 0xbb, 0xb8, 0x8f, 0x8d, 0xf1, 0x36, 0xca, 0xd7, 0xea, 0xba, 0x5a, 0xed, 0x34, 0xf5, 0xc7, 0x12, 0x6d, 0x97, 0xf4, 0x05, 0x63, 0xbc, 0x83, 0x0a, 0x0d, 0x55, 0x57, 0xea, 0xdd, 0x96, 0xfe,
0xe1, 0x5d, 0xe2, 0xa0, 0x9a, 0xe5, 0x72, 0x71, 0xb3, 0x4f, 0xbf, 0x42, 0xfb, 0xf1, 0x41, 0xa3, 0x34, 0xba, 0x4b, 0x12, 0xd4, 0xb0, 0x5c, 0x26, 0xee, 0xe0, 0x43, 0xaf, 0xd4, 0x79, 0x7a, 0xd8,
0xae, 0x3d, 0xe8, 0xf1, 0x88, 0x49, 0xf9, 0x1a, 0x80, 0xaf, 0xc6, 0xc1, 0xed, 0xe3, 0xb1, 0x6d, 0x54, 0xb5, 0x47, 0x7d, 0x16, 0x31, 0x2d, 0xdd, 0x00, 0xf0, 0xf5, 0x24, 0xb8, 0x73, 0x32, 0xb1,
0x39, 0x4f, 0x78, 0xe0, 0x7b, 0x68, 0x25, 0x84, 0x47, 0x1b, 0xa4, 0xe4, 0x2d, 0x58, 0xb3, 0x7e, 0x2d, 0xe7, 0x19, 0x0b, 0xfc, 0x00, 0xad, 0x46, 0xf0, 0x78, 0x83, 0x8c, 0xb4, 0x0d, 0x6b, 0x36,
0xce, 0x9a, 0x68, 0x9f, 0xbb, 0xe8, 0x52, 0xb8, 0xb0, 0xab, 0x3d, 0xd0, 0x40, 0x16, 0xa0, 0x9c, 0x2e, 0x58, 0x13, 0xef, 0x73, 0x1f, 0x5d, 0x89, 0x16, 0xf6, 0xb4, 0x47, 0x1a, 0xc8, 0x02, 0x94,
0x0d, 0x58, 0x26, 0x9f, 0xb3, 0xac, 0xeb, 0x3c, 0x71, 0x40, 0x14, 0xe5, 0x5f, 0x12, 0x28, 0x3f, 0xb3, 0x09, 0xcb, 0xa4, 0x0b, 0x96, 0xf5, 0x9c, 0x67, 0x0e, 0x88, 0xa2, 0xfa, 0x43, 0x0a, 0x15,
0xeb, 0x50, 0x8c, 0x67, 0xad, 0xd9, 0x53, 0x75, 0xbd, 0xa9, 0x87, 0x17, 0x9f, 0x39, 0x35, 0xca, 0xe6, 0x1d, 0x2a, 0xe0, 0x59, 0x6b, 0xf5, 0x15, 0x5d, 0x6f, 0xe9, 0xd1, 0xc5, 0xe7, 0x4e, 0x8d,
0x87, 0xf8, 0x3d, 0x94, 0xdd, 0x57, 0x35, 0x55, 0xaf, 0x57, 0xc3, 0x7a, 0x98, 0x41, 0xf6, 0x89, 0xb2, 0x21, 0x7c, 0x54, 0xe5, 0x0e, 0x14, 0x4d, 0xd1, 0xd5, 0x7a, 0x54, 0x0f, 0x73, 0xc8, 0x01,
0x43, 0x5c, 0x6b, 0x00, 0x1f, 0xfc, 0x05, 0x08, 0xd3, 0xee, 0x56, 0xef, 0x87, 0x37, 0xe6, 0x02, 0x71, 0x88, 0x6b, 0x0d, 0xe1, 0xf3, 0xbe, 0x04, 0x61, 0x3a, 0xbd, 0xfa, 0xc3, 0xe8, 0xc6, 0x4c,
0x8e, 0x85, 0x6a, 0x4f, 0x07, 0x47, 0xfc, 0xb6, 0x65, 0x56, 0x3a, 0x87, 0x95, 0x46, 0xbd, 0x26, 0xc0, 0x89, 0x50, 0x9d, 0xd9, 0xf0, 0x98, 0xdd, 0xb6, 0x1a, 0x94, 0xce, 0x51, 0xad, 0xa9, 0x36,
0xa0, 0x29, 0xb9, 0x04, 0xd0, 0xd5, 0x19, 0xb4, 0x2e, 0x9e, 0x77, 0x86, 0x2d, 0x9b, 0x68, 0xe3, 0x38, 0x34, 0x23, 0x55, 0x00, 0xba, 0x36, 0x87, 0xaa, 0xfc, 0x55, 0x0f, 0xb0, 0x55, 0x13, 0x6d,
0xbf, 0x7b, 0x11, 0x7c, 0x76, 0x64, 0x2a, 0xad, 0x96, 0xaa, 0xd5, 0xc2, 0xd3, 0x47, 0xbe, 0xca, 0xfe, 0x75, 0x2f, 0x82, 0xaf, 0x0d, 0xb1, 0xd6, 0x6e, 0x2b, 0x5a, 0x23, 0x3a, 0x7d, 0xec, 0xab,
0x64, 0x42, 0x1c, 0x93, 0x21, 0xf6, 0x9a, 0xfa, 0xbe, 0xda, 0x09, 0x0f, 0x1f, 0x21, 0xf6, 0xa8, 0x4d, 0xa7, 0xc4, 0x31, 0x03, 0xc4, 0x7e, 0x4b, 0x3f, 0x50, 0xba, 0xd1, 0xe1, 0x63, 0xc4, 0x3e,
0x3b, 0x22, 0xfe, 0xee, 0xfa, 0xcb, 0x3f, 0x37, 0x16, 0x5e, 0xc1, 0xef, 0xe5, 0xc9, 0x46, 0xe2, 0x75, 0xc7, 0xc4, 0xdf, 0xdb, 0x78, 0xfd, 0xcb, 0xe6, 0xd2, 0x1b, 0xf8, 0xbd, 0x3e, 0xdd, 0x4c,
0x15, 0xfc, 0xfe, 0x38, 0xd9, 0x58, 0xf8, 0x1b, 0xfe, 0x5f, 0xfc, 0xb5, 0x91, 0xe8, 0x67, 0x78, 0xbd, 0x81, 0xdf, 0xcf, 0xa7, 0x9b, 0x4b, 0xbf, 0xc1, 0xff, 0xab, 0x5f, 0x37, 0x53, 0x03, 0x91,
0xef, 0xba, 0xfb, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x5f, 0x7a, 0x46, 0xf6, 0x94, 0x0d, 0x00, 0xf5, 0xae, 0xfb, 0x7f, 0x06, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x49, 0x51, 0xc5, 0x82, 0x0d, 0x00,
0x00, 0x00,
} }

View File

@ -63,14 +63,14 @@ message Folder {
} }
message Device { message Device {
bytes id = 1 [(gogoproto.customname) = "ID"]; bytes id = 1 [(gogoproto.customname) = "ID"];
string name = 2; string name = 2;
repeated string addresses = 3; repeated string addresses = 3;
Compression compression = 4; Compression compression = 4;
string cert_name = 5; string cert_name = 5;
int64 max_local_version = 6; int64 max_sequence = 6;
bool introducer = 7; bool introducer = 7;
uint64 index_id = 8 [(gogoproto.customname) = "IndexID", (gogoproto.customtype) = "IndexID", (gogoproto.nullable) = false]; uint64 index_id = 8 [(gogoproto.customname) = "IndexID", (gogoproto.customtype) = "IndexID", (gogoproto.nullable) = false];
} }
enum Compression { enum Compression {
@ -102,7 +102,7 @@ message FileInfo {
bool invalid = 7; bool invalid = 7;
bool no_permissions = 8; bool no_permissions = 8;
Vector version = 9 [(gogoproto.nullable) = false]; Vector version = 9 [(gogoproto.nullable) = false];
int64 local_version = 10; int64 sequence = 10;
repeated BlockInfo Blocks = 16 [(gogoproto.nullable) = false]; repeated BlockInfo Blocks = 16 [(gogoproto.nullable) = false];
} }

View File

@ -25,8 +25,8 @@ func (m Hello) Magic() uint32 {
} }
func (f FileInfo) String() string { func (f FileInfo) String() string {
return fmt.Sprintf("File{Name:%q, Type:%v, LocalVersion:%d, Permissions:0%o, Modified:%d, Version:%v, Length:%d, Deleted:%v, Invalid:%v, NoPermissions:%v, Blocks:%v}", return fmt.Sprintf("File{Name:%q, Type:%v, Sequence:%d, Permissions:0%o, Modified:%d, Version:%v, Length:%d, Deleted:%v, Invalid:%v, NoPermissions:%v, Blocks:%v}",
f.Name, f.Type, f.LocalVersion, f.Permissions, f.Modified, f.Version, f.Size, f.Deleted, f.Invalid, f.NoPermissions, f.Blocks) f.Name, f.Type, f.Sequence, f.Permissions, f.Modified, f.Version, f.Size, f.Deleted, f.Invalid, f.NoPermissions, f.Blocks)
} }
func (f FileInfo) IsDeleted() bool { func (f FileInfo) IsDeleted() bool {

View File

@ -46,7 +46,7 @@ type Process struct {
startComplete bool startComplete bool
startCompleteCond *stdsync.Cond startCompleteCond *stdsync.Cond
stop bool stop bool
localVersion map[string]map[string]int64 // Folder ID => Device ID => LocalVersion sequence map[string]map[string]int64 // Folder ID => Device ID => Sequence
done map[string]bool // Folder ID => 100% done map[string]bool // Folder ID => 100%
cmd *exec.Cmd cmd *exec.Cmd
@ -57,10 +57,10 @@ type Process struct {
// Example: NewProcess("127.0.0.1:8082") // Example: NewProcess("127.0.0.1:8082")
func NewProcess(addr string) *Process { func NewProcess(addr string) *Process {
p := &Process{ p := &Process{
addr: addr, addr: addr,
localVersion: make(map[string]map[string]int64), sequence: make(map[string]map[string]int64),
done: make(map[string]bool), done: make(map[string]bool),
eventMut: sync.NewMutex(), eventMut: sync.NewMutex(),
} }
p.startCompleteCond = stdsync.NewCond(p.eventMut) p.startCompleteCond = stdsync.NewCond(p.eventMut)
return p return p
@ -308,16 +308,16 @@ func InSync(folder string, ps ...*Process) bool {
return false return false
} }
// Check LocalVersion for each device. The local version seen by remote // Check Sequence for each device. The local version seen by remote
// devices should be the same as what it has locally, or the index // devices should be the same as what it has locally, or the index
// hasn't been sent yet. // hasn't been sent yet.
sourceID := ps[i].id.String() sourceID := ps[i].id.String()
sourceVersion := ps[i].localVersion[folder][sourceID] sourceSeq := ps[i].sequence[folder][sourceID]
for j := range ps { for j := range ps {
if i != j { if i != j {
remoteVersion := ps[j].localVersion[folder][sourceID] remoteSeq := ps[j].sequence[folder][sourceID]
if remoteVersion != sourceVersion { if remoteSeq != sourceSeq {
return false return false
} }
} }
@ -510,12 +510,12 @@ func (p *Process) eventLoop() {
folder := data["folder"].(string) folder := data["folder"].(string)
version, _ := data["version"].(json.Number).Int64() version, _ := data["version"].(json.Number).Int64()
p.eventMut.Lock() p.eventMut.Lock()
m := p.localVersion[folder] m := p.sequence[folder]
if m == nil { if m == nil {
m = make(map[string]int64) m = make(map[string]int64)
} }
m[p.id.String()] = version m[p.id.String()] = version
p.localVersion[folder] = m p.sequence[folder] = m
p.done[folder] = false p.done[folder] = false
l.Debugf("LocalIndexUpdated %v %v done=false\n\t%+v", p.id, folder, m) l.Debugf("LocalIndexUpdated %v %v done=false\n\t%+v", p.id, folder, m)
p.eventMut.Unlock() p.eventMut.Unlock()
@ -526,12 +526,12 @@ func (p *Process) eventLoop() {
folder := data["folder"].(string) folder := data["folder"].(string)
version, _ := data["version"].(json.Number).Int64() version, _ := data["version"].(json.Number).Int64()
p.eventMut.Lock() p.eventMut.Lock()
m := p.localVersion[folder] m := p.sequence[folder]
if m == nil { if m == nil {
m = make(map[string]int64) m = make(map[string]int64)
} }
m[device] = version m[device] = version
p.localVersion[folder] = m p.sequence[folder] = m
p.done[folder] = false p.done[folder] = false
l.Debugf("RemoteIndexUpdated %v %v done=false\n\t%+v", p.id, folder, m) l.Debugf("RemoteIndexUpdated %v %v done=false\n\t%+v", p.id, folder, m)
p.eventMut.Unlock() p.eventMut.Unlock()