diff --git a/lib/routing.go b/lib/routing.go
index b82d2e1..995e235 100644
--- a/lib/routing.go
+++ b/lib/routing.go
@@ -6,7 +6,10 @@ import (
"log"
"bytes"
"fmt"
- )
+ "container/vector"
+ "sort"
+ "time"
+)
type RoutingTable interface {
SeeHost(h *Host)
@@ -14,28 +17,39 @@ type RoutingTable interface {
GetString() string
// may return "", subject to change
GetHTML() string
+ GetClosest(t string, n uint) *RTHostList
}
type BRoutingTable struct {
- id string
- buckets [](*Bucket)
+ id string
+ buckets [](*Bucket)
maxbucket int
- seehost chan *Host
- quitchan chan bool
- stringchan chan chan string
- htmlchan chan chan string
+ seehost chan *Host
+ quitchan chan bool
+ stringchan chan chan string
+ htmlchan chan chan string
+ closestchan chan *closestReq
- Log bool
+ Log bool
logger *log.Logger
}
+type closestReq struct {
+ target string
+ n uint
+ retchan chan *RTHostList
+}
+
type RTHost struct {
Host *Host
Distance Distance
}
+
+type RTHostList struct {
+ v *vector.Vector
}
type Bucket struct {
@@ -43,20 +57,63 @@ type Bucket struct {
}
+func NewRTHostList() *RTHostList {
+ r := new(RTHostList)
+ r.v = new(vector.Vector)
+ return r
+}
+
+func (l *RTHostList) Push(h *RTHost) { l.v.Push(h) }
+
+func (l *RTHostList) Len() int {
+ el := l.v.Len()
+ //fmt.Printf("len called: %d\n", el)
+ return el
+}
+
+func (l *RTHostList) Less(i, j int) bool {
+ //fmt.Printf("less called %d < %d\n", i, j)
+ return l.v.At(i).(*RTHost).Distance.Less(l.v.At(j).(*RTHost).Distance)
+}
+
+func (l *RTHostList) Swap(i, j int) {
+ //fmt.Printf("swap called %d < %d\n", i, j)
+ l.v.Swap(i, j)
+}
+
+func (l *RTHostList) Slice(i, j int) *RTHostList {
+ r := new(RTHostList)
+ r.v = l.v.Slice(i, j)
+ return r
+}
+
+func (l *RTHostList) Data() []*RTHost {
+ v := l.v
+ vl := v.Len()
+ rs := make([]*RTHost, vl)
+ for i := 0; i < vl; i++ {
+ rs[i] = v.At(i).(*RTHost)
+ }
+ return rs
+}
+
func NewBRoutingTable(id string) (rt *BRoutingTable) {
rt = new(BRoutingTable)
rt.id = id
- rt.buckets = make([](*Bucket), HASHLEN * 8)
+ rt.buckets = make([](*Bucket), HASHLEN*8)
firstbucket := new(Bucket)
- firstbucket.hosts = make([](*RTHost), K + 1)[0:0]
+ firstbucket.hosts = make([](*RTHost), K+1)[0:0]
rt.buckets[0] = firstbucket
rt.maxbucket = 0
rt.seehost = make(chan *Host)
rt.quitchan = make(chan bool)
+ rt.stringchan = make(chan chan string)
+ rt.htmlchan = make(chan chan string)
+ rt.closestchan = make(chan *closestReq)
rt.Log = true
rt.logger = log.New(os.Stdout, nil, "BRoutingTable: ", 0)
@@ -70,22 +127,22 @@ func NewBRoutingTable(id string) (rt *BRoutingTable) {
func (rt *BRoutingTable) main() {
for {
select {
- case h := <- rt.seehost:
+ case h := <-rt.seehost:
rt.seeHost(h)
- case <- rt.quitchan:
+ case <-rt.quitchan:
return
- case r := <- rt.stringchan:
+ case r := <-rt.stringchan:
r <- rt.string()
- case r := <- rt.htmlchan:
+ case r := <-rt.htmlchan:
r <- rt.html()
+ case r := <-rt.closestchan:
+ r.retchan <- rt.getClosest(r.target, r.n)
}
}
}
-func (rt *BRoutingTable) SeeHost(h *Host) {
- rt.seehost <- h
-}
+func (rt *BRoutingTable) SeeHost(h *Host) { rt.seehost <- h }
func (rt *BRoutingTable) seeHost(h *Host) {
@@ -93,7 +150,7 @@ func (rt *BRoutingTable) seeHost(h *Host) {
rt.logger.Logf("see host: %v dist %v\n", h, XOR(h.Id, rt.id)[0:5])
}
bucketno, pos, maxbucketno := rt.findHost(h)
- /*rt.logger.Logf("is in %d/%d maxbucketno %d\n", bucketno, pos, maxbucketno)
+ /*rt.logger.Logf("is in %d/%d maxbucketno %d\n", bucketno, pos, maxbucketno)
rt.logger.Logf("dist %v to %v\n", XOR(h.Id, rt.id), h)
rt.logger.Logf("own id is %x\n", rt.id)
rt.logger.Logf("h.Id is %x", h.Id)*/
@@ -112,7 +169,7 @@ func (rt *BRoutingTable) seeHost(h *Host) {
if rt.Log {
rt.logger.Logf("bucket %d not full yet -> inserting\n", bucketno)
}
- bucket.hosts = bucket.hosts[0:hl+1]
+ bucket.hosts = bucket.hosts[0 : hl+1]
bucket.hosts[hl] = rthost
} else {
if maxbucketno == bucketno {
@@ -121,7 +178,7 @@ func (rt *BRoutingTable) seeHost(h *Host) {
}
} else {
rt.newBucket()
- bucket.hosts = bucket.hosts[0:hl+1]
+ bucket.hosts = bucket.hosts[0 : hl+1]
bucket.hosts[hl] = rthost
rt.balanceleftright(uint(bucketno))
}
@@ -138,16 +195,16 @@ func (rt *BRoutingTable) seeHost(h *Host) {
func (rt *BRoutingTable) newBucket() *Bucket {
- if rt.maxbucket == (HASHLEN * 8 - 1) {
+ if rt.maxbucket == (HASHLEN*8 - 1) {
return nil
}
b := new(Bucket)
- b.hosts = make([](*RTHost), K + 1)[0:0]
+ b.hosts = make([](*RTHost), K+1)[0:0]
rt.maxbucket++
rt.buckets[rt.maxbucket] = b
-
+
return b
}
@@ -173,7 +230,7 @@ func (rt *BRoutingTable) findHost(h *Host) (bucketno, pos, maxbucketno int) {
hosts := rt.buckets[bucketno].hosts
for i, rh := range hosts {
pos = i
- if rh.host.Id == h.Id {
+ if rh.Host.Id == h.Id {
return
}
}
@@ -189,14 +246,14 @@ func (rt *BRoutingTable) balanceleftright(lefti uint) {
left := rt.buckets[lefti]
right := rt.buckets[righti]
- newleft := make([](*RTHost), K + 1)
- newright := make([](*RTHost), K + 1)
+ newleft := make([](*RTHost), K+1)
+ newright := make([](*RTHost), K+1)
nleft := 0
nright := 0
for _, rth := range left.hosts {
- if BucketNo(rth.distance) == lefti {
+ if BucketNo(rth.Distance) == lefti {
newleft[nleft] = rth
nleft++
} else {
@@ -206,7 +263,7 @@ func (rt *BRoutingTable) balanceleftright(lefti uint) {
}
for _, rth := range right.hosts {
- if BucketNo(rth.distance) == lefti {
+ if BucketNo(rth.Distance) == lefti {
newleft[nleft] = rth
nleft++
} else {
@@ -216,13 +273,13 @@ func (rt *BRoutingTable) balanceleftright(lefti uint) {
}
rt.logger.Logf("rebalanced to %d/%d\n", nleft, nright)
-
+
newleft = newleft[0:nleft]
newright = newright[0:nright]
left.hosts = newleft
right.hosts = newright
-
+
fmt.Printf("%v", rt)
}
@@ -231,14 +288,14 @@ func (rt *BRoutingTable) balanceleftright(lefti uint) {
func (rt *BRoutingTable) string() string {
buf := bytes.NewBuffer(nil)
- buf.WriteString("BRoutingTable ===>\n")
+ buf.WriteString("BRoutingTable
\n")
for b := 0; b <= rt.maxbucket; b++ {
buf.WriteString(fmt.Sprintf("bucket %d\n", b))
for _, rth := range rt.buckets[b].hosts {
buf.WriteString(fmt.Sprintf("\t%x | %v @ %v\n", rth.Host.Id, XOR(rth.Host.Id, rt.id)[0:5], rth.Host.Addr))
}
}
-
+
buf.WriteString("<===\n")
return buf.String()
}
@@ -264,7 +321,7 @@ func (rt *BRoutingTable) html() string {
}
buf.WriteString("")
-
+
buf.WriteString("")
return buf.String()
}
@@ -274,12 +331,88 @@ func (rt *BRoutingTable) html() string {
func (rt *BRoutingTable) GetString() string {
r := make(chan string)
rt.stringchan <- r
- return <- r
+ return <-r
}
// goroutine safe. not for internal use!
func (rt *BRoutingTable) GetHTML() string {
r := make(chan string)
rt.htmlchan <- r
- return <- r
+ return <-r
+}
+
+// goroutine safe. not for internal use!
+func (rt *BRoutingTable) GetClosest(t string, n uint) *RTHostList {
+ r := make(chan *RTHostList)
+ rt.closestchan <- &closestReq{t, n, r}
+ return <-r
+}
+
+// TODO: wtf behaviour? gets the closests n nodes to us close to t????
+// not goroutine safe. for internal use!
+func (rt *BRoutingTable) getClosest(t string, n uint) *RTHostList {
+ //rt.logger.Logf("looking for %x dist %v
\n", t, XOR(rt.id, t))
+ //d := XOR(t, rt.id)
+ t1 := time.Nanoseconds()
+ h := new(Host)
+ h.Id = t
+
+ bucketno, _, _ := rt.findHost(h)
+
+ if bucketno < 0 {
+ return nil
+ }
+
+ buckets := rt.buckets
+ hl := NewRTHostList()
+
+ var rn uint = 0
+
+ for _, el := range buckets[bucketno].hosts {
+ hl.Push(el)
+ rn++
+ }
+
+ rt.logger.Logf("match bucket: rn %d\n", rn)
+
+ // init for for loop
+ cangoup := bucketno < rt.maxbucket
+ cangodown := bucketno > 0
+ delta := 1
+
+ for (rn < n) && (cangoup || cangodown) {
+ cangoup = (bucketno + delta) < rt.maxbucket
+ cangodown = (bucketno - delta) > 0
+ //rt.logger.Logf("bucketno %d rt.maxbucket %d\n", bucketno, rt.maxbucket)
+ //rt.logger.Logf("bucketno - delta: %d. > 0: %v", bucketno-delta, (bucketno-delta) > 0)
+ //rt.logger.Logf("round delta %d cangoup %v cangodown %v\n", delta, cangoup, cangodown)
+
+ if cangoup {
+ for _, el := range buckets[bucketno+delta].hosts {
+ hl.Push(el)
+ rn++
+ }
+ }
+
+ if cangodown {
+ for _, el := range buckets[bucketno-delta].hosts {
+ hl.Push(el)
+ rn++
+ }
+ }
+
+ delta++
+ }
+
+ //rt.logger.Logf("sorting %v...\n", hl)
+ sort.Sort(hl)
+ //rt.logger.Logf("done!\n")
+ if rn >= n {
+ hl = hl.Slice(0, int(n-1))
+ }
+
+ t2 := time.Nanoseconds()
+ rt.logger.Logf("finding closest took %d us\n", (t2-t1)/1000)
+
+ return hl
}