fix: handle funky clocks when removing expired addresses

When setting the TTL to 0, we expect `UpdateAddrs` to atomically delete
the addresses. However, due to funky clock stuff, "now" isn't always
consistent and seems to make us think these addresses are _about_ to
expire.

Funky clock stuff -> `time.Now().Add(0).Unix() > time.Now().Unix()` in
some cases...
This commit is contained in:
Steven Allen 2021-07-16 20:31:43 -07:00
parent 1907cca69f
commit 810b492220

View File

@ -99,14 +99,16 @@ func (r *addrsRecord) clean() (chgd bool) {
return true
}
if r.dirty && addrsLen > 1 {
// First remove expired.
r.Addrs = removeExpired(r.Addrs, now)
// Then sort if there's anything to do.
if r.dirty && len(r.Addrs) > 0 {
sort.Slice(r.Addrs, func(i, j int) bool {
return r.Addrs[i].Expiry < r.Addrs[j].Expiry
})
}
r.Addrs = removeExpired(r.Addrs, now)
return r.dirty || len(r.Addrs) != addrsLen
}
@ -118,17 +120,22 @@ func (r *addrsRecord) hasExpiredAddrs(now int64) bool {
}
func removeExpired(entries []*pb.AddrBookRecord_AddrEntry, now int64) []*pb.AddrBookRecord_AddrEntry {
// since addresses are sorted by expiration, we find the first
// survivor and split the slice on its index.
pivot := -1
for i, addr := range entries {
if addr.Expiry > now {
break
// Filter out expired addresses in-place.
newEntries := entries[:0]
for _, addr := range entries {
// Sometimes clocks do funy things so we check the TTL as well.
if addr.Ttl == 0 || addr.Expiry <= now {
continue
}
pivot = i
newEntries = append(newEntries, addr)
}
return entries[pivot+1:]
// Let Go's GC free the remaining addresses.
for i := len(newEntries); i < len(entries); i++ {
entries[i] = nil
}
return newEntries
}
// dsAddrBook is an address book backed by a Datastore with a GC procedure to purge expired entries. It uses an