Skip to content

Commit 9c4c09f

Browse files
committed
added a simple, as of now uncomplete, binary
routing table
1 parent 4c1940d commit 9c4c09f

File tree

4 files changed

+244
-2
lines changed

4 files changed

+244
-2
lines changed

lib/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,6 @@ GOFILES=callmanager.go\
66
utility.go\
77
webinterface.go\
88
sleepqueue.go
9+
routing.go
910

1011
include $(GOROOT)/src/Make.pkg

lib/callmanager.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -135,10 +135,11 @@ type CallManager struct {
135135
regchan chan *RunningRPC
136136
inchan chan *RPC
137137
timeout int64
138+
rt RoutingTable
138139
}
139140

140141

141-
func NewCallManager(transceiver Transceiver) *CallManager {
142+
func NewCallManager(transceiver Transceiver, rt RoutingTable) *CallManager {
142143
cm := new(CallManager)
143144

144145
cm.rpcmap = make(map[string](*rpcentry), 8)
@@ -149,6 +150,7 @@ func NewCallManager(transceiver Transceiver) *CallManager {
149150
cm.regchan = make(chan *RunningRPC)
150151
cm.inchan = make(chan *RPC)
151152
cm.timeout = TIMEOUT
153+
cm.rt = rt
152154

153155
return cm
154156
}
@@ -206,6 +208,9 @@ func (cm *CallManager) constructAnswer(req *RPC, retcall uint8, retis []interfac
206208

207209
// TODO: errors...
208210
func (cm *CallManager) DispatchRPC(rpc *RPC) {
211+
if cm.rt != nil {
212+
cm.rt.SeeHost(rpc.From)
213+
}
209214
switch rpc.Header.Call {
210215
case 0x01:
211216
retcall, retis, err := cm.DispatchRequest(rpc)

lib/routing.go

Lines changed: 232 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,232 @@
1+
package malus
2+
3+
4+
import (
5+
"os"
6+
"log"
7+
"bytes"
8+
"fmt"
9+
)
10+
11+
type RoutingTable interface {
12+
SeeHost(h *Host)
13+
}
14+
15+
16+
type BRoutingTable struct {
17+
id string
18+
buckets [](*Bucket)
19+
maxbucket int
20+
21+
seehost chan *Host
22+
quitchan chan bool
23+
24+
Log bool
25+
logger *log.Logger
26+
}
27+
28+
29+
type RTHost struct {
30+
host *Host
31+
distance Distance
32+
}
33+
34+
type Bucket struct {
35+
hosts [](*RTHost)
36+
}
37+
38+
39+
func NewBRoutingTable(id string) (rt *BRoutingTable) {
40+
rt = new(BRoutingTable)
41+
42+
rt.id = id
43+
44+
rt.buckets = make([](*Bucket), HASHLEN * 8)
45+
firstbucket := new(Bucket)
46+
firstbucket.hosts = make([](*RTHost), K + 1)[0:0]
47+
48+
rt.buckets[0] = firstbucket
49+
rt.maxbucket = 0
50+
51+
rt.seehost = make(chan *Host)
52+
rt.quitchan = make(chan bool)
53+
54+
rt.Log = true
55+
rt.logger = log.New(os.Stdout, nil, "BRoutingTable: ", 0)
56+
57+
go rt.main()
58+
59+
return
60+
}
61+
62+
63+
func (rt *BRoutingTable) main() {
64+
for {
65+
select {
66+
case h := <- rt.seehost:
67+
rt.seeHost(h)
68+
case <- rt.quitchan:
69+
return
70+
}
71+
}
72+
}
73+
74+
75+
func (rt *BRoutingTable) SeeHost(h *Host) {
76+
rt.seehost <- h
77+
}
78+
79+
80+
func (rt *BRoutingTable) seeHost(h *Host) {
81+
if rt.Log {
82+
rt.logger.Logf("see host: %v dist %v\n", h, XOR(h.Id, rt.id)[0:5])
83+
}
84+
bucketno, pos, maxbucketno := rt.findHost(h)
85+
/*rt.logger.Logf("is in %d/%d maxbucketno %d\n", bucketno, pos, maxbucketno)
86+
rt.logger.Logf("dist %v to %v\n", XOR(h.Id, rt.id), h)
87+
rt.logger.Logf("own id is %x\n", rt.id)
88+
rt.logger.Logf("h.Id is %x", h.Id)*/
89+
90+
91+
bucket := rt.buckets[bucketno]
92+
93+
// we do not already have the entry
94+
if pos < 0 {
95+
if rt.Log {
96+
rt.logger.Logf("we don't have an entry yet\n")
97+
}
98+
rthost := &RTHost{h, XOR(h.Id, rt.id)}
99+
hl := len(bucket.hosts)
100+
if hl < K {
101+
if rt.Log {
102+
rt.logger.Logf("bucket %d not full yet -> inserting\n", bucketno)
103+
}
104+
bucket.hosts = bucket.hosts[0:hl+1]
105+
bucket.hosts[hl] = rthost
106+
} else {
107+
if maxbucketno == bucketno {
108+
if rt.Log {
109+
rt.logger.Logf("bucket %d full -> dropping\n", bucketno)
110+
}
111+
} else {
112+
rt.newBucket()
113+
bucket.hosts = bucket.hosts[0:hl+1]
114+
bucket.hosts[hl] = rthost
115+
rt.balanceleftright(uint(bucketno))
116+
}
117+
}
118+
} else {
119+
if rt.Log {
120+
rt.logger.Logf("we already have an entry\n")
121+
}
122+
host := bucket.hosts[pos]
123+
copy(bucket.hosts[pos:], bucket.hosts[pos+1:])
124+
bucket.hosts[len(bucket.hosts)-1] = host
125+
}
126+
}
127+
128+
129+
func (rt *BRoutingTable) newBucket() *Bucket {
130+
if rt.maxbucket == (HASHLEN * 8 - 1) {
131+
return nil
132+
}
133+
134+
b := new(Bucket)
135+
b.hosts = make([](*RTHost), K + 1)[0:0]
136+
137+
rt.maxbucket++
138+
rt.buckets[rt.maxbucket] = b
139+
140+
return b
141+
}
142+
143+
144+
func (rt *BRoutingTable) findHost(h *Host) (bucketno, pos, maxbucketno int) {
145+
bucketno = -1
146+
pos = -1
147+
148+
dist := XOR(h.Id, rt.id)
149+
maxbucketno = int(BucketNo(dist))
150+
151+
maxbucket := rt.maxbucket
152+
if maxbucket < 0 {
153+
return
154+
}
155+
156+
bucketno = maxbucketno
157+
158+
if bucketno > maxbucket {
159+
bucketno = maxbucket
160+
}
161+
162+
hosts := rt.buckets[bucketno].hosts
163+
for i, rh := range hosts {
164+
pos = i
165+
if rh.host.Id == h.Id {
166+
return
167+
}
168+
}
169+
170+
pos = -1
171+
return
172+
}
173+
174+
175+
func (rt *BRoutingTable) balanceleftright(lefti uint) {
176+
righti := lefti + 1
177+
178+
left := rt.buckets[lefti]
179+
right := rt.buckets[righti]
180+
181+
newleft := make([](*RTHost), K + 1)
182+
newright := make([](*RTHost), K + 1)
183+
184+
nleft := 0
185+
nright := 0
186+
187+
for _, rth := range left.hosts {
188+
if BucketNo(rth.distance) == lefti {
189+
newleft[nleft] = rth
190+
nleft++
191+
} else {
192+
newright[nright] = rth
193+
nright++
194+
}
195+
}
196+
197+
for _, rth := range right.hosts {
198+
if BucketNo(rth.distance) == lefti {
199+
newleft[nleft] = rth
200+
nleft++
201+
} else {
202+
newright[nright] = rth
203+
nright++
204+
}
205+
}
206+
207+
rt.logger.Logf("rebalanced to %d/%d\n", nleft, nright)
208+
209+
newleft = newleft[0:nleft]
210+
newright = newright[0:nright]
211+
212+
left.hosts = newleft
213+
right.hosts = newright
214+
215+
fmt.Printf("%v", rt)
216+
}
217+
218+
219+
func (rt *BRoutingTable) String() string {
220+
buf := bytes.NewBuffer(nil)
221+
222+
buf.WriteString("BRoutingTable ===>\n")
223+
for b := 0; b <= rt.maxbucket; b++ {
224+
buf.WriteString(fmt.Sprintf("bucket %d\n", b))
225+
for _, rth := range rt.buckets[b].hosts {
226+
buf.WriteString(fmt.Sprintf("\t%x | %v @ %v\n", rth.host.Id, XOR(rth.host.Id, rt.id)[0:5], rth.host.Addr))
227+
}
228+
}
229+
230+
buf.WriteString("<===\n")
231+
return buf.String()
232+
}

main/main.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,12 @@ func main() {
2424
panic("could not make transceiver")
2525
}
2626

27-
cm := malus.NewCallManager(tr)
2827
id := malus.SHA1String(strconv.Itoa(laddr.Port))
28+
29+
30+
rt := malus.NewBRoutingTable(id)
31+
32+
cm := malus.NewCallManager(tr, rt)
2933
cm.Id = id
3034
cm.AddRPC("ping", malus.Ping)
3135
cm.AddRPC("store", malus.Store)

0 commit comments

Comments
 (0)