mirror of
https://github.com/octoleo/syncthing.git
synced 2024-12-23 03:18:59 +00:00
This makes sure addresses are sorted when coming in from the API. The database merge operation still checks for correct ordering (which is quick) and sorts if it isn't correct (legacy database record or replication peer), but then does a copy first. Tested with -race in production...
This commit is contained in:
parent
c4f161d8c5
commit
9084510e1b
@ -18,6 +18,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
@ -279,6 +280,10 @@ func (s *apiSrv) handleAnnounce(remote net.IP, deviceID protocol.DeviceID, addre
|
|||||||
dbAddrs[i].Expires = expire
|
dbAddrs[i].Expires = expire
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The address slice must always be sorted for database merges to work
|
||||||
|
// properly.
|
||||||
|
sort.Sort(databaseAddressOrder(dbAddrs))
|
||||||
|
|
||||||
seen := now.UnixNano()
|
seen := now.UnixNano()
|
||||||
if s.repl != nil {
|
if s.repl != nil {
|
||||||
s.repl.send(key, dbAddrs, seen)
|
s.repl.send(key, dbAddrs, seen)
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"log"
|
||||||
"sort"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@ -263,12 +264,15 @@ func (s *levelDBStore) Stop() {
|
|||||||
// chosen for any duplicates.
|
// chosen for any duplicates.
|
||||||
func merge(a, b DatabaseRecord) DatabaseRecord {
|
func merge(a, b DatabaseRecord) DatabaseRecord {
|
||||||
// Both lists must be sorted for this to work.
|
// Both lists must be sorted for this to work.
|
||||||
sort.Slice(a.Addresses, func(i, j int) bool {
|
if !sort.IsSorted(databaseAddressOrder(a.Addresses)) {
|
||||||
return a.Addresses[i].Address < a.Addresses[j].Address
|
log.Println("Warning: bug: addresses not correctly sorted in merge")
|
||||||
})
|
a.Addresses = sortedAddressCopy(a.Addresses)
|
||||||
sort.Slice(b.Addresses, func(i, j int) bool {
|
}
|
||||||
return b.Addresses[i].Address < b.Addresses[j].Address
|
if !sort.IsSorted(databaseAddressOrder(b.Addresses)) {
|
||||||
})
|
// no warning because this is the side we read from disk and it may
|
||||||
|
// legitimately predate correct sorting.
|
||||||
|
b.Addresses = sortedAddressCopy(b.Addresses)
|
||||||
|
}
|
||||||
|
|
||||||
res := DatabaseRecord{
|
res := DatabaseRecord{
|
||||||
Addresses: make([]DatabaseAddress, 0, len(a.Addresses)+len(b.Addresses)),
|
Addresses: make([]DatabaseAddress, 0, len(a.Addresses)+len(b.Addresses)),
|
||||||
@ -352,3 +356,24 @@ func expire(addrs []DatabaseAddress, now int64) []DatabaseAddress {
|
|||||||
}
|
}
|
||||||
return addrs
|
return addrs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func sortedAddressCopy(addrs []DatabaseAddress) []DatabaseAddress {
|
||||||
|
sorted := make([]DatabaseAddress, len(addrs))
|
||||||
|
copy(sorted, addrs)
|
||||||
|
sort.Sort(databaseAddressOrder(sorted))
|
||||||
|
return sorted
|
||||||
|
}
|
||||||
|
|
||||||
|
type databaseAddressOrder []DatabaseAddress
|
||||||
|
|
||||||
|
func (s databaseAddressOrder) Less(a, b int) bool {
|
||||||
|
return s[a].Address < s[b].Address
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s databaseAddressOrder) Swap(a, b int) {
|
||||||
|
s[a], s[b] = s[b], s[a]
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s databaseAddressOrder) Len() int {
|
||||||
|
return len(s)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user