forked from vanadium-archive/go.ref
/
serverlist.go
132 lines (115 loc) · 3.07 KB
/
serverlist.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// 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
}