blob: 88aefff82d4c26499e366f52b80938264b639042 [file] [log] [blame]
// Copyright 2015 The Vanadium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mounttablelib
import (
"container/list"
"sync"
"time"
"v.io/v23/naming"
vdltime "v.io/v23/vdlroot/time"
"v.io/x/ref/lib/timekeeper"
)
type serverListManager struct {
clock timekeeper.TimeKeeper
}
// server maintains the state of a single server. Unless expires is refreshed before the
// time is reached, the entry will be removed.
type server struct {
expires time.Time
oa string // object address of server
}
// serverList represents an ordered list of servers.
type serverList struct {
sync.Mutex
m *serverListManager
l *list.List // contains entries of type *server
}
// newServerListManager starts a serverlist manager with a particular clock.
func newServerListManager(clock timekeeper.TimeKeeper) *serverListManager {
return &serverListManager{clock: clock}
}
// SetServerListClock does what it says.
func (slm *serverListManager) setClock(clock timekeeper.TimeKeeper) {
slm.clock = clock
}
// newServerList creates a synchronized list of servers.
func (slm *serverListManager) newServerList() *serverList {
return &serverList{l: list.New(), m: slm}
}
func (sl *serverList) len() int {
sl.Lock()
defer sl.Unlock()
return sl.l.Len()
}
func (sl *serverList) Front() *server {
sl.Lock()
defer sl.Unlock()
return sl.l.Front().Value.(*server)
}
// add to the front of the list if not already in the list, otherwise,
// update the expiration time and move to the front of the list. That
// way the most recently refreshed is always first.
func (sl *serverList) add(oa string, ttl time.Duration) {
expires := sl.m.clock.Now().Add(ttl)
sl.Lock()
defer sl.Unlock()
for e := sl.l.Front(); e != nil; e = e.Next() {
s := e.Value.(*server)
if s.oa == oa {
s.expires = expires
sl.l.MoveToFront(e)
return
}
}
s := &server{
oa: oa,
expires: expires,
}
sl.l.PushFront(s) // innocent until proven guilty
}
// remove an element from the list. Return the number of elements remaining.
func (sl *serverList) remove(oa string) int {
sl.Lock()
defer sl.Unlock()
for e := sl.l.Front(); e != nil; e = e.Next() {
s := e.Value.(*server)
if s.oa == oa {
sl.l.Remove(e)
break
}
}
return sl.l.Len()
}
// removeExpired removes any expired servers.
func (sl *serverList) removeExpired() (int, int) {
sl.Lock()
defer sl.Unlock()
now := sl.m.clock.Now()
var next *list.Element
removed := 0
for e := sl.l.Front(); e != nil; e = next {
s := e.Value.(*server)
next = e.Next()
if now.After(s.expires) {
sl.l.Remove(e)
removed++
}
}
return sl.l.Len(), removed
}
// copyToSlice returns the contents of the list as a slice of MountedServer.
func (sl *serverList) copyToSlice() []naming.MountedServer {
sl.Lock()
defer sl.Unlock()
var slice []naming.MountedServer
for e := sl.l.Front(); e != nil; e = e.Next() {
s := e.Value.(*server)
ms := naming.MountedServer{
Server: s.oa,
Deadline: vdltime.Deadline{Time: s.expires},
}
slice = append(slice, ms)
}
return slice
}