diff --git a/.gitignore b/.gitignore index a62452e..63bade4 100644 --- a/.gitignore +++ b/.gitignore @@ -34,5 +34,6 @@ radix/profile/profile god_cli/god_cli persistence/test* radix/benchmarklogs +127.0.0.1_* 127.0.0.1:* diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e0a87c0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +Copyright (c) 2013, Martin Bruse +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of anyone or anything. diff --git a/README.md b/README.md index 4b9b679..3d53f33 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,34 @@ god === -god is a scalable, performant, persistent in memory data structure server. It allows massively distributed applications to update and fetch common data in a structured and sorted format. +god is a scalable, performant, persistent, in-memory data structure system. It allows massively distributed applications to update and fetch common data in a structured and sorted format. -Its main inspirations are Redis and Chord/DHash. Like Redis it focuses on performance, ease of use and a small, simple yet powerful feature set, while from the Chord/DHash projects it inherits scalability, redundancy and transparent failover behaviour. +Its main inspirations are Redis and Chord/DHash. Like Redis it focuses on performance, ease of use, and a small, simple yet powerful feature set, while from the Chord/DHash projects it inherits scalability, redundancy, and transparent failover behaviour. # Try it out -go get github.com/zond/god/god_server, run god_server, browse to http://localhost:9192/. +Install Go, git, Mercurial and gcc, go get github.com/zond/god/god_server, run god_server, browse to http://localhost:9192/. + +# Embed it in your Go application + +``` +import "github.com/zond/god/dhash" +s := dhash.NewNodeDir(fmt.Sprintf("%v:%v", listenIp, listenPort), fmt.Sprintf("%v:%v", broadcastIp, broadcastPort), dataDir) +s.MustStart() +s.MustJoin(fmt.Sprintf("%v:%v", joinIp, joinPort)) +``` # Documents HTML documentation: http://zond.github.com/god/ -godoc documentation: http://go.pkgdoc.org/github.com/zond/god +godoc documentation: http://godoc.org/github.com/zond/god # TODO * Docs * Add illustrations to the usage manual * Benchmark - * Consecutively start 1-20 ec2 small instances and benchmark against each size + * Consecutively start 1-20 instances on equally powerful machines and benchmark against each size * Need 20 machines of equal and constant performance. Is anyone willing to lend me this for few days of benchmarking? * Add benchmark results to docs diff --git a/bench/master.go b/bench/master.go index 015966e..b91e1f7 100644 --- a/bench/master.go +++ b/bench/master.go @@ -1,93 +1,93 @@ package bench import ( - "flag" - "fmt" - "net/rpc" - "regexp" - "strconv" - "strings" + "flag" + "fmt" + "net/rpc" + "regexp" + "strconv" + "strings" ) func RunMaster() { - ip := flag.String("ip", "127.0.0.1", "IP address to find a node at") - slaves := flag.String("slaves", "", "Comma separated list of slave host:ip pairs") - port := flag.Int("port", 9191, "Port to find a node at") - maxKey := flag.Int64("maxKey", 10000, "Biggest key as int64 converted to []byte using common.EncodeInt64") - prepare := flag.String("prepare", "0-0", "The key range (as int64's) to make sure exists before starging") - keyRangePattern := regexp.MustCompile("^(\\d+)-(\\d+)$") - flag.Parse() - slavehosts := strings.Split(*slaves, ",") - clients := make([]*rpc.Client, len(slavehosts)) - rps := make([]int64, len(slavehosts)) - var err error - for index, addr := range slavehosts { - if clients[index], err = rpc.Dial("tcp", addr); err != nil { - panic(err) - } - } - command := SpinCommand{ - Addr: fmt.Sprintf("%v:%v", *ip, *port), - MaxKey: *maxKey, - } - if match := keyRangePattern.FindStringSubmatch(*prepare); match != nil && match[1] != match[2] { - from, err := strconv.ParseInt(match[1], 10, 64) - if err != nil { - panic(err) - } - to, err := strconv.ParseInt(match[2], 10, 64) - if err != nil { - panic(err) - } - calls := make([]*rpc.Call, len(clients)) - for index, client := range clients { - calls[index] = client.Go("Slave.Prepare", PrepareCommand{ - Addr: command.Addr, - Range: [2]int64{ - from + (int64(index) * ((to - from) / int64(len(clients)))), - from + ((int64(index) + 1) * ((to - from) / int64(len(clients)))), - }, - }, &Nothing{}, nil) - } - for _, call := range calls { - <-call.Done - if call.Error != nil { - panic(call.Error) - } - } - } - var oldSpinRes *SpinResult - var spinRes SpinResult - for _, client := range clients { - if err = client.Call("Slave.Spin", command, &spinRes); err != nil { - panic(err) - } - if oldSpinRes == nil { - oldSpinRes = &spinRes - } else { - if spinRes.Keys != oldSpinRes.Keys || spinRes.Nodes != oldSpinRes.Nodes { - panic(fmt.Errorf("Last slave had %v nodes and %v keys, now I get %v nodes and %v keys?", oldSpinRes.Nodes, oldSpinRes.Keys, spinRes.Nodes, spinRes.Keys)) - } - } - } - for _, client := range clients { - if err = client.Call("Slave.Wait", Nothing{}, &Nothing{}); err != nil { - panic(err) - } - } - for index, client := range clients { - if err = client.Call("Slave.Current", Nothing{}, &(rps[index])); err != nil { - panic(err) - } - } - for _, client := range clients { - if err = client.Call("Slave.Stop", Nothing{}, &Nothing{}); err != nil { - panic(err) - } - } - sum := int64(0) - for _, r := range rps { - sum += r - } - fmt.Printf("%v\t%v\t%v\n", spinRes.Nodes, spinRes.Keys, sum) + ip := flag.String("ip", "127.0.0.1", "IP address to find a node at") + slaves := flag.String("slaves", "", "Comma separated list of slave host:ip pairs") + port := flag.Int("port", 9191, "Port to find a node at") + maxKey := flag.Int64("maxKey", 10000, "Biggest key as int64 converted to []byte using setop.EncodeInt64") + prepare := flag.String("prepare", "0-0", "The key range (as int64's) to make sure exists before starging") + keyRangePattern := regexp.MustCompile("^(\\d+)-(\\d+)$") + flag.Parse() + slavehosts := strings.Split(*slaves, ",") + clients := make([]*rpc.Client, len(slavehosts)) + rps := make([]int64, len(slavehosts)) + var err error + for index, addr := range slavehosts { + if clients[index], err = rpc.Dial("tcp", addr); err != nil { + panic(err) + } + } + command := SpinCommand{ + Addr: fmt.Sprintf("%v:%v", *ip, *port), + MaxKey: *maxKey, + } + if match := keyRangePattern.FindStringSubmatch(*prepare); match != nil && match[1] != match[2] { + from, err := strconv.ParseInt(match[1], 10, 64) + if err != nil { + panic(err) + } + to, err := strconv.ParseInt(match[2], 10, 64) + if err != nil { + panic(err) + } + calls := make([]*rpc.Call, len(clients)) + for index, client := range clients { + calls[index] = client.Go("Slave.Prepare", PrepareCommand{ + Addr: command.Addr, + Range: [2]int64{ + from + (int64(index) * ((to - from) / int64(len(clients)))), + from + ((int64(index) + 1) * ((to - from) / int64(len(clients)))), + }, + }, &Nothing{}, nil) + } + for _, call := range calls { + <-call.Done + if call.Error != nil { + panic(call.Error) + } + } + } + var oldSpinRes *SpinResult + var spinRes SpinResult + for _, client := range clients { + if err = client.Call("Slave.Spin", command, &spinRes); err != nil { + panic(err) + } + if oldSpinRes == nil { + oldSpinRes = &spinRes + } else { + if spinRes.Keys != oldSpinRes.Keys || spinRes.Nodes != oldSpinRes.Nodes { + panic(fmt.Errorf("Last slave had %v nodes and %v keys, now I get %v nodes and %v keys?", oldSpinRes.Nodes, oldSpinRes.Keys, spinRes.Nodes, spinRes.Keys)) + } + } + } + for _, client := range clients { + if err = client.Call("Slave.Wait", Nothing{}, &Nothing{}); err != nil { + panic(err) + } + } + for index, client := range clients { + if err = client.Call("Slave.Current", Nothing{}, &(rps[index])); err != nil { + panic(err) + } + } + for _, client := range clients { + if err = client.Call("Slave.Stop", Nothing{}, &Nothing{}); err != nil { + panic(err) + } + } + sum := int64(0) + for _, r := range rps { + sum += r + } + fmt.Printf("%v\t%v\t%v\n", spinRes.Nodes, spinRes.Keys, sum) } diff --git a/bench/slave.go b/bench/slave.go index c5e81ec..1376fc0 100644 --- a/bench/slave.go +++ b/bench/slave.go @@ -1,173 +1,173 @@ package bench import ( - "flag" - "fmt" - "github.com/zond/god/client" - "github.com/zond/god/murmur" - "math/rand" - "net" - "net/rpc" - "sync" - "sync/atomic" - "time" + "flag" + "fmt" + "github.com/zond/god/client" + "github.com/zond/god/murmur" + "math/rand" + "net" + "net/rpc" + "sync" + "sync/atomic" + "time" ) func init() { - rand.Seed(time.Now().UnixNano()) + rand.Seed(time.Now().UnixNano()) } const ( - stopped = iota - started + stopped = iota + started ) type SpinResult struct { - Nodes int - Keys int + Nodes int + Keys int } type PrepareCommand struct { - Addr string - Range [2]int64 + Addr string + Range [2]int64 } type SpinCommand struct { - Addr string - MaxKey int64 + Addr string + MaxKey int64 } type Nothing struct{} type Slave struct { - maxRps int64 - currRps int64 - maxKey int64 - req int64 - start time.Time - addr string - state int32 - client *client.Conn - wg *sync.WaitGroup + maxRps int64 + currRps int64 + maxKey int64 + req int64 + start time.Time + addr string + state int32 + client *client.Conn + wg *sync.WaitGroup } func (self *Slave) switchState(expected, wanted int32) bool { - return atomic.CompareAndSwapInt32(&self.state, expected, wanted) + return atomic.CompareAndSwapInt32(&self.state, expected, wanted) } func (self *Slave) hasState(s int32) bool { - return atomic.LoadInt32(&self.state) == s + return atomic.LoadInt32(&self.state) == s } func (self *Slave) spinner() { - var kv []byte - for self.hasState(started) { - kv = murmur.HashInt64(rand.Int63n(self.maxKey)) - self.client.Put(kv, kv) - atomic.AddInt64(&self.req, 1) - } + var kv []byte + for self.hasState(started) { + kv = murmur.HashInt64(rand.Int63n(self.maxKey)) + self.client.Put(kv, kv) + atomic.AddInt64(&self.req, 1) + } } func (self *Slave) run() { - freebies := 2 - peaked := false - var curr int64 - for self.hasState(started) { - curr = atomic.LoadInt64(&self.req) / ((time.Now().UnixNano() - self.start.UnixNano()) / int64(time.Second)) - atomic.StoreInt64(&self.currRps, curr) - if self.maxRps == 0 || freebies > 0 || curr > self.maxRps { - fmt.Println("Spinning up one more loader, curr:", curr, "max:", self.maxRps) - go self.spinner() - if curr < self.maxRps { - freebies-- - } - if self.maxRps == 0 || curr > self.maxRps { - self.maxRps = curr - } - } else if !peaked { - fmt.Println("Peaked at", self.maxRps) - self.wg.Done() - peaked = true - } - self.req = 0 - self.start = time.Now() - time.Sleep(time.Second) - } + freebies := 2 + peaked := false + var curr int64 + for self.hasState(started) { + curr = atomic.LoadInt64(&self.req) / ((time.Now().UnixNano() - self.start.UnixNano()) / int64(time.Second)) + atomic.StoreInt64(&self.currRps, curr) + if self.maxRps == 0 || freebies > 0 || curr > self.maxRps { + fmt.Println("Spinning up one more loader, curr:", curr, "max:", self.maxRps) + go self.spinner() + if curr < self.maxRps { + freebies-- + } + if self.maxRps == 0 || curr > self.maxRps { + self.maxRps = curr + } + } else if !peaked { + fmt.Println("Peaked at", self.maxRps) + self.wg.Done() + peaked = true + } + self.req = 0 + self.start = time.Now() + time.Sleep(time.Second) + } } func (self *Slave) Prepare(command PrepareCommand, x *Nothing) error { - if self.hasState(stopped) { - fmt.Printf("Preparing %+v\n", command) - self.client = client.MustConn(command.Addr) - var kv []byte - for i := command.Range[0]; i < command.Range[1]; i++ { - kv = murmur.HashInt64(i) - self.client.Put(kv, kv) - if i%1000 == 0 { - fmt.Print(".") - } - } - fmt.Println("done!") - } - return nil + if self.hasState(stopped) { + fmt.Printf("Preparing %+v\n", command) + self.client = client.MustConn(command.Addr) + var kv []byte + for i := command.Range[0]; i < command.Range[1]; i++ { + kv = murmur.HashInt64(i) + self.client.Put(kv, kv) + if i%1000 == 0 { + fmt.Print(".") + } + } + fmt.Println("done!") + } + return nil } func (self *Slave) Current(x Nothing, rps *int64) error { - if self.hasState(started) { - self.wg.Wait() - *rps = atomic.LoadInt64(&self.currRps) - return nil - } - return fmt.Errorf("%v is not started", self) + if self.hasState(started) { + self.wg.Wait() + *rps = atomic.LoadInt64(&self.currRps) + return nil + } + return fmt.Errorf("%v is not started", self) } func (self *Slave) Stop(x Nothing, y *Nothing) error { - if self.hasState(started) { - self.wg.Wait() - self.switchState(started, stopped) - } - return nil + if self.hasState(started) { + self.wg.Wait() + self.switchState(started, stopped) + } + return nil } func (self *Slave) Wait(x Nothing, y *Nothing) error { - if self.hasState(started) { - self.wg.Wait() - return nil - } - return fmt.Errorf("%v is not started", self) + if self.hasState(started) { + self.wg.Wait() + return nil + } + return fmt.Errorf("%v is not started", self) } func (self *Slave) Spin(command SpinCommand, result *SpinResult) error { - if self.switchState(stopped, started) { - fmt.Println("Spinning on ", command.Addr) - self.wg = new(sync.WaitGroup) - self.wg.Add(1) - self.maxRps = 0 - self.client = client.MustConn(command.Addr) - self.maxKey = command.MaxKey - go self.run() - } else { - fmt.Println("Already started on", self.addr) - } - *result = SpinResult{ - Nodes: len(self.client.Nodes()), - Keys: self.client.Size(), - } - return nil + if self.switchState(stopped, started) { + fmt.Println("Spinning on ", command.Addr) + self.wg = new(sync.WaitGroup) + self.wg.Add(1) + self.maxRps = 0 + self.client = client.MustConn(command.Addr) + self.maxKey = command.MaxKey + go self.run() + } else { + fmt.Println("Already started on", self.addr) + } + *result = SpinResult{ + Nodes: len(self.client.Nodes()), + Keys: self.client.Size(), + } + return nil } func RunSlave() { - var ip = flag.String("ip", "127.0.0.1", "IP address to listen to") - var port = flag.Int("port", 19191, "Port to connect to") - flag.Parse() - var err error - var addr *net.TCPAddr - if addr, err = net.ResolveTCPAddr("tcp", fmt.Sprintf("%v:%v", *ip, *port)); err != nil { - panic(err) - } - var listener *net.TCPListener - if listener, err = net.ListenTCP("tcp", addr); err != nil { - panic(err) - } - rpc.Register(&Slave{}) - rpc.Accept(listener) + var ip = flag.String("ip", "127.0.0.1", "IP address to listen to") + var port = flag.Int("port", 19191, "Port to connect to") + flag.Parse() + var err error + var addr *net.TCPAddr + if addr, err = net.ResolveTCPAddr("tcp", fmt.Sprintf("%v:%v", *ip, *port)); err != nil { + panic(err) + } + var listener *net.TCPListener + if listener, err = net.ListenTCP("tcp", addr); err != nil { + panic(err) + } + rpc.Register(&Slave{}) + rpc.Accept(listener) } diff --git a/client/client.go b/client/client.go index 75bdd7d..7eb6f78 100644 --- a/client/client.go +++ b/client/client.go @@ -1,34 +1,34 @@ package client import ( - "bytes" - "fmt" - "github.com/zond/god/common" - "github.com/zond/god/setop" - "net/rpc" - "sync" - "sync/atomic" - "time" + "bytes" + "fmt" + "github.com/zond/god/common" + "github.com/zond/setop" + "net/rpc" + "sync" + "sync/atomic" + "time" ) const ( - created = iota - started - stopped + created = iota + started + stopped ) func findKeys(op *setop.SetOp) (result map[string]bool) { - result = make(map[string]bool) - for _, source := range op.Sources { - if source.Key != nil { - result[string(source.Key)] = true - } else { - for key, _ := range findKeys(source.SetOp) { - result[key] = true - } - } - } - return + result = make(map[string]bool) + for _, source := range op.Sources { + if source.Key != nil { + result[string(source.Key)] = true + } else { + for key, _ := range findKeys(source.SetOp) { + result[key] = true + } + } + } + return } // Conn is the client connection. @@ -41,7 +41,7 @@ func findKeys(op *setop.SetOp) (result map[string]bool) { // // Sub trees can be 'mirrored', which means that they contain a tree mirroring its values as keys and its keys as values. // To mirror a sub tree, call SubAddConfiguration for the sub tree and set 'mirrored' to 'yes'. -// +// // Naming conventions: // // If there are two methods with similar names except that one has a capital S prefixed, that means that the method with the capital S will not return until all nodes responsible for the written data has received the data, while the one without the capital S will return as soon as the owner of the data has received it. @@ -58,914 +58,926 @@ func findKeys(op *setop.SetOp) (result map[string]bool) { // // Usage: https://github.com/zond/god/blob/master/client/client_test.go type Conn struct { - ring *common.Ring - state int32 + ring *common.Ring + state int32 } // NewConnRing creates a new Conn from a given set of known nodes. For internal usage. func NewConnRing(ring *common.Ring) *Conn { - return &Conn{ring: ring} + return &Conn{ring: ring} } // NewConn creates a new Conn to a cluster defined by the address of one of its members. func NewConn(addr string) (result *Conn, err error) { - result = &Conn{ring: common.NewRing()} - var newNodes common.Remotes - err = common.Switch.Call(addr, "Discord.Nodes", 0, &newNodes) - result.ring.SetNodes(newNodes) - return + result = &Conn{ring: common.NewRing()} + var newNodes common.Remotes + err = common.Switch.Call(addr, "Discord.Nodes", 0, &newNodes) + result.ring.SetNodes(newNodes) + return } // MustConn creates a working Conn or panics. func MustConn(addr string) (result *Conn) { - var err error - if result, err = NewConn(addr); err != nil { - panic(err) - } - return + var err error + if result, err = NewConn(addr); err != nil { + panic(err) + } + return } func (self *Conn) hasState(s int32) bool { - return atomic.LoadInt32(&self.state) == s + return atomic.LoadInt32(&self.state) == s } func (self *Conn) changeState(old, neu int32) bool { - return atomic.CompareAndSwapInt32(&self.state, old, neu) + return atomic.CompareAndSwapInt32(&self.state, old, neu) } func (self *Conn) removeNode(node common.Remote) { - self.ring.Remove(node) - self.Reconnect() + self.ring.Remove(node) + self.Reconnect() } // Nodes returns the set of known nodes for this Conn. func (self *Conn) Nodes() common.Remotes { - return self.ring.Nodes() + return self.ring.Nodes() } func (self *Conn) update() { - myRingHash := self.ring.Hash() - var otherRingHash []byte - node := self.ring.Random() - if err := node.Call("DHash.RingHash", 0, &otherRingHash); err != nil { - self.removeNode(node) - return - } - if bytes.Compare(myRingHash, otherRingHash) != 0 { - var newNodes common.Remotes - if err := node.Call("Discord.Nodes", 0, &newNodes); err != nil { - self.removeNode(node) - return - } - self.ring.SetNodes(newNodes) - } + myRingHash := self.ring.Hash() + var otherRingHash []byte + node := self.ring.Random() + if err := node.Call("DHash.RingHash", 0, &otherRingHash); err != nil { + self.removeNode(node) + return + } + if bytes.Compare(myRingHash, otherRingHash) != 0 { + var newNodes common.Remotes + if err := node.Call("Discord.Nodes", 0, &newNodes); err != nil { + self.removeNode(node) + return + } + self.ring.SetNodes(newNodes) + } } func (self *Conn) updateRegularly() { - for self.hasState(started) { - self.update() - time.Sleep(common.PingInterval) - } + for self.hasState(started) { + self.update() + time.Sleep(common.PingInterval) + } } // Start will begin to regularly update the set of known nodes for this Conn. func (self *Conn) Start() { - if self.changeState(created, started) { - go self.updateRegularly() - } + if self.changeState(created, started) { + go self.updateRegularly() + } } // Reconnect will try to refetch the set of known nodes from a randomly chosen currently known node. func (self *Conn) Reconnect() { - node := self.ring.Random() - var err error - for { - var newNodes common.Remotes - if err = node.Call("Discord.Nodes", 0, &newNodes); err == nil { - self.ring.SetNodes(newNodes) - return - } - self.ring.Remove(node) - if self.ring.Size() == 0 { - panic(fmt.Errorf("%v doesn't know of any live nodes!", self)) - } - node = self.ring.Random() - } + node := self.ring.Random() + var err error + for { + var newNodes common.Remotes + if err = node.Call("Discord.Nodes", 0, &newNodes); err == nil { + self.ring.SetNodes(newNodes) + return + } + self.ring.Remove(node) + if self.ring.Size() == 0 { + panic(fmt.Errorf("%v doesn't know of any live nodes!", self)) + } + node = self.ring.Random() + } } func (self *Conn) subClear(key []byte, sync bool) { - data := common.Item{ - Key: key, - Sync: sync, - } - _, _, successor := self.ring.Remotes(key) - var x int - if err := successor.Call("DHash.SubClear", data, &x); err != nil { - self.removeNode(*successor) - self.subClear(key, sync) - } + data := common.Item{ + Key: key, + Sync: sync, + } + _, _, successor := self.ring.Remotes(key) + var x int + if err := successor.Call("DHash.SubClear", data, &x); err != nil { + self.removeNode(*successor) + self.subClear(key, sync) + } } func (self *Conn) subDel(key, subKey []byte, sync bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - Sync: sync, - } - _, _, successor := self.ring.Remotes(key) - var x int - if err := successor.Call("DHash.SubDel", data, &x); err != nil { - self.removeNode(*successor) - self.subDel(key, subKey, sync) - } + data := common.Item{ + Key: key, + SubKey: subKey, + Sync: sync, + } + _, _, successor := self.ring.Remotes(key) + var x int + if err := successor.Call("DHash.SubDel", data, &x); err != nil { + self.removeNode(*successor) + self.subDel(key, subKey, sync) + } } func (self *Conn) subPutVia(succ *common.Remote, key, subKey, value []byte, sync bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - Value: value, - Sync: sync, - } - var x int - if err := succ.Call("DHash.SubPut", data, &x); err != nil { - self.removeNode(*succ) - _, _, newSuccessor := self.ring.Remotes(key) - *succ = *newSuccessor - self.subPutVia(succ, key, subKey, value, sync) - } + data := common.Item{ + Key: key, + SubKey: subKey, + Value: value, + Sync: sync, + } + var x int + if err := succ.Call("DHash.SubPut", data, &x); err != nil { + self.removeNode(*succ) + _, _, newSuccessor := self.ring.Remotes(key) + *succ = *newSuccessor + self.subPutVia(succ, key, subKey, value, sync) + } } func (self *Conn) subPut(key, subKey, value []byte, sync bool) { - _, _, successor := self.ring.Remotes(key) - self.subPutVia(successor, key, subKey, value, sync) + _, _, successor := self.ring.Remotes(key) + self.subPutVia(successor, key, subKey, value, sync) } func (self *Conn) del(key []byte, sync bool) { - data := common.Item{ - Key: key, - Sync: sync, - } - _, _, successor := self.ring.Remotes(key) - var x int - if err := successor.Call("DHash.Del", data, &x); err != nil { - self.removeNode(*successor) - self.del(key, sync) - } + data := common.Item{ + Key: key, + Sync: sync, + } + _, _, successor := self.ring.Remotes(key) + var x int + if err := successor.Call("DHash.Del", data, &x); err != nil { + self.removeNode(*successor) + self.del(key, sync) + } } func (self *Conn) putVia(succ *common.Remote, key, value []byte, sync bool) { - data := common.Item{ - Key: key, - Value: value, - Sync: sync, - } - var x int - if err := succ.Call("DHash.Put", data, &x); err != nil { - self.removeNode(*succ) - _, _, newSuccessor := self.ring.Remotes(key) - *succ = *newSuccessor - self.putVia(succ, key, value, sync) - } + data := common.Item{ + Key: key, + Value: value, + Sync: sync, + } + var x int + if err := succ.Call("DHash.Put", data, &x); err != nil { + self.removeNode(*succ) + _, _, newSuccessor := self.ring.Remotes(key) + *succ = *newSuccessor + self.putVia(succ, key, value, sync) + } } func (self *Conn) put(key, value []byte, sync bool) { - _, _, successor := self.ring.Remotes(key) - self.putVia(successor, key, value, sync) + _, _, successor := self.ring.Remotes(key) + self.putVia(successor, key, value, sync) } func (self *Conn) mergeRecent(operation string, r common.Range, up bool) (result []common.Item) { - currentRedundancy := self.ring.Redundancy() - futures := make([]*rpc.Call, currentRedundancy) - results := make([]*[]common.Item, currentRedundancy) - nodes := make(common.Remotes, currentRedundancy) - nextKey := r.Key - var nextSuccessor *common.Remote - for i := 0; i < currentRedundancy; i++ { - _, _, nextSuccessor = self.ring.Remotes(nextKey) - var thisResult []common.Item - nodes[i] = *nextSuccessor - results[i] = &thisResult - futures[i] = nextSuccessor.Go(operation, r, &thisResult) - nextKey = nextSuccessor.Pos - } - for index, future := range futures { - <-future.Done - if future.Error != nil { - self.removeNode(nodes[index]) - return self.mergeRecent(operation, r, up) - } - } - result = common.MergeItems(results, up) - return + currentRedundancy := self.ring.Redundancy() + futures := make([]*rpc.Call, currentRedundancy) + results := make([]*[]common.Item, currentRedundancy) + nodes := make(common.Remotes, currentRedundancy) + nextKey := r.Key + var nextSuccessor *common.Remote + for i := 0; i < currentRedundancy; i++ { + _, _, nextSuccessor = self.ring.Remotes(nextKey) + var thisResult []common.Item + nodes[i] = *nextSuccessor + results[i] = &thisResult + futures[i] = nextSuccessor.Go(operation, r, &thisResult) + nextKey = nextSuccessor.Pos + } + for index, future := range futures { + <-future.Done + if future.Error != nil { + self.removeNode(nodes[index]) + return self.mergeRecent(operation, r, up) + } + } + result = common.MergeItems(results, up) + return } func (self *Conn) findRecent(operation string, data common.Item) (result *common.Item) { - currentRedundancy := self.ring.Redundancy() - futures := make([]*rpc.Call, currentRedundancy) - results := make([]*common.Item, currentRedundancy) - nodes := make(common.Remotes, currentRedundancy) - nextKey := data.Key - var nextSuccessor *common.Remote - for i := 0; i < currentRedundancy; i++ { - _, _, nextSuccessor = self.ring.Remotes(nextKey) - thisResult := &common.Item{} - nodes[i] = *nextSuccessor - results[i] = thisResult - futures[i] = nextSuccessor.Go(operation, data, thisResult) - nextKey = nextSuccessor.Pos - } - for index, future := range futures { - <-future.Done - if future.Error != nil { - self.removeNode(nodes[index]) - return self.findRecent(operation, data) - } - if result == nil || result.Timestamp < results[index].Timestamp { - result = results[index] - } - } - return + currentRedundancy := self.ring.Redundancy() + futures := make([]*rpc.Call, currentRedundancy) + results := make([]*common.Item, currentRedundancy) + nodes := make(common.Remotes, currentRedundancy) + nextKey := data.Key + var nextSuccessor *common.Remote + for i := 0; i < currentRedundancy; i++ { + _, _, nextSuccessor = self.ring.Remotes(nextKey) + thisResult := &common.Item{} + nodes[i] = *nextSuccessor + results[i] = thisResult + futures[i] = nextSuccessor.Go(operation, data, thisResult) + nextKey = nextSuccessor.Pos + } + for index, future := range futures { + <-future.Done + if future.Error != nil { + self.removeNode(nodes[index]) + return self.findRecent(operation, data) + } + if result == nil || result.Timestamp < results[index].Timestamp { + result = results[index] + } + } + return } func (self *Conn) consume(c chan [2][]byte, wait *sync.WaitGroup, successor *common.Remote) { - for pair := range c { - self.putVia(successor, pair[0], pair[1], false) - } - wait.Done() + for pair := range c { + self.putVia(successor, pair[0], pair[1], false) + } + wait.Done() } func (self *Conn) dump(c chan [2][]byte, wait *sync.WaitGroup) { - var succ *common.Remote - dumps := make(map[string]chan [2][]byte) - for pair := range c { - _, _, succ = self.ring.Remotes(pair[0]) - if dump, ok := dumps[succ.Addr]; ok { - dump <- pair - } else { - newDump := make(chan [2][]byte, 16) - wait.Add(1) - go self.consume(newDump, wait, succ) - newDump <- pair - dumps[succ.Addr] = newDump - } - } - for _, dump := range dumps { - close(dump) - } - wait.Done() + var succ *common.Remote + dumps := make(map[string]chan [2][]byte) + for pair := range c { + _, _, succ = self.ring.Remotes(pair[0]) + if dump, ok := dumps[succ.Addr]; ok { + dump <- pair + } else { + newDump := make(chan [2][]byte, 16) + wait.Add(1) + go self.consume(newDump, wait, succ) + newDump <- pair + dumps[succ.Addr] = newDump + } + } + for _, dump := range dumps { + close(dump) + } + wait.Done() } func (self *Conn) subDump(key []byte, c chan [2][]byte, wait *sync.WaitGroup) { - _, _, succ := self.ring.Remotes(key) - for pair := range c { - self.subPutVia(succ, key, pair[0], pair[1], false) - } - wait.Done() + _, _, succ := self.ring.Remotes(key) + for pair := range c { + self.subPutVia(succ, key, pair[0], pair[1], false) + } + wait.Done() } // Clear will remove all data from all currently known database nodes. func (self *Conn) Clear() { - var x int - for _, node := range self.ring.Nodes() { - if err := node.Call("DHash.Clear", 0, &x); err != nil { - self.removeNode(node) - } - } + var x int + for _, node := range self.ring.Nodes() { + if err := node.Call("DHash.Clear", 0, &x); err != nil { + self.removeNode(node) + } + } } // SSubPut will put value under subKey in the sub tree defined by key. func (self *Conn) SSubPut(key, subKey, value []byte) { - self.subPut(key, subKey, value, true) + self.subPut(key, subKey, value, true) } // SubPut will put value under subKey in the sub tree defined by key. func (self *Conn) SubPut(key, subKey, value []byte) { - self.subPut(key, subKey, value, false) + self.subPut(key, subKey, value, false) } // SPut will put value under key. func (self *Conn) SPut(key, value []byte) { - self.put(key, value, true) + self.put(key, value, true) } // Put will put value under key. func (self *Conn) Put(key, value []byte) { - self.put(key, value, false) + self.put(key, value, false) } // Dump will return a channel to send multiple key/value pairs through. When finished, close the channel and #Wait for the *sync.WaitGroup. func (self *Conn) Dump() (c chan [2][]byte, wait *sync.WaitGroup) { - wait = new(sync.WaitGroup) - c = make(chan [2][]byte, 16) - wait.Add(1) - go self.dump(c, wait) - return + wait = new(sync.WaitGroup) + c = make(chan [2][]byte, 16) + wait.Add(1) + go self.dump(c, wait) + return } // SubDump will return a channel to send multiple key/value pairs to a given sub tree through. When finished, close the channel and #Wait for the *sync.WaitGroup. func (self *Conn) SubDump(key []byte) (c chan [2][]byte, wait *sync.WaitGroup) { - wait = new(sync.WaitGroup) - c = make(chan [2][]byte) - wait.Add(1) - go self.subDump(key, c, wait) - return + wait = new(sync.WaitGroup) + c = make(chan [2][]byte) + wait.Add(1) + go self.subDump(key, c, wait) + return } // SubClear will remove all byte values from the sub tree defined by key. It will retain delete markers for all deleted values. func (self *Conn) SubClear(key []byte) { - self.subClear(key, false) + self.subClear(key, false) } -// SubClear will remove all byte values from the sub tree defined by key. It will retain delete markers for all deleted values. +// SSubClear will remove all byte values from the sub tree defined by key. It will retain delete markers for all deleted values. func (self *Conn) SSubClear(key []byte) { - self.subClear(key, true) + self.subClear(key, true) } // SubDel will remove the value under subKey from the sub tree defined by key. func (self *Conn) SubDel(key, subKey []byte) { - self.subDel(key, subKey, false) + self.subDel(key, subKey, false) } // SSubDel will remove the value under subKey from the sub tree defined by key. func (self *Conn) SSubDel(key, subKey []byte) { - self.subDel(key, subKey, true) + self.subDel(key, subKey, true) } // SDel will remove the byte value under key. func (self *Conn) SDel(key []byte) { - self.del(key, true) + self.del(key, true) } // Del will remove the byte value under key. func (self *Conn) Del(key []byte) { - self.del(key, false) + self.del(key, false) } // MirrorReverseIndexOf will return the the distance from the end for subKey, looking at the mirror tree of the sub tree defined by key. func (self *Conn) MirrorReverseIndexOf(key, subKey []byte) (index int, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - _, _, successor := self.ring.Remotes(key) - var result common.Index - if err := successor.Call("DHash.MirrorReverseIndexOf", data, &result); err != nil { - self.removeNode(*successor) - return self.MirrorReverseIndexOf(key, subKey) - } - index, existed = result.N, result.Existed - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + _, _, successor := self.ring.Remotes(key) + var result common.Index + if err := successor.Call("DHash.MirrorReverseIndexOf", data, &result); err != nil { + self.removeNode(*successor) + return self.MirrorReverseIndexOf(key, subKey) + } + index, existed = result.N, result.Existed + return } // MirrorIndexOf will return the the distance from the start for subKey, looking at the mirror tree of the sub tree defined by key. func (self *Conn) MirrorIndexOf(key, subKey []byte) (index int, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - _, _, successor := self.ring.Remotes(key) - var result common.Index - if err := successor.Call("DHash.MirrorIndexOf", data, &result); err != nil { - self.removeNode(*successor) - return self.MirrorIndexOf(key, subKey) - } - index, existed = result.N, result.Existed - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + _, _, successor := self.ring.Remotes(key) + var result common.Index + if err := successor.Call("DHash.MirrorIndexOf", data, &result); err != nil { + self.removeNode(*successor) + return self.MirrorIndexOf(key, subKey) + } + index, existed = result.N, result.Existed + return } // ReverseIndexOf will return the the distance from the end for subKey, looking at the sub tree defined by key. func (self *Conn) ReverseIndexOf(key, subKey []byte) (index int, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - _, _, successor := self.ring.Remotes(key) - var result common.Index - if err := successor.Call("DHash.ReverseIndexOf", data, &result); err != nil { - self.removeNode(*successor) - return self.ReverseIndexOf(key, subKey) - } - index, existed = result.N, result.Existed - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + _, _, successor := self.ring.Remotes(key) + var result common.Index + if err := successor.Call("DHash.ReverseIndexOf", data, &result); err != nil { + self.removeNode(*successor) + return self.ReverseIndexOf(key, subKey) + } + index, existed = result.N, result.Existed + return } // IndexOf will return the the distance from the start for subKey, looking at the sub tree defined by key. func (self *Conn) IndexOf(key, subKey []byte) (index int, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - _, _, successor := self.ring.Remotes(key) - var result common.Index - if err := successor.Call("DHash.IndexOf", data, &result); err != nil { - self.removeNode(*successor) - return self.IndexOf(key, subKey) - } - index, existed = result.N, result.Existed - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + _, _, successor := self.ring.Remotes(key) + var result common.Index + if err := successor.Call("DHash.IndexOf", data, &result); err != nil { + self.removeNode(*successor) + return self.IndexOf(key, subKey) + } + index, existed = result.N, result.Existed + return } // Next will return the next key and value after key. func (self *Conn) Next(key []byte) (nextKey, nextValue []byte, existed bool) { - data := common.Item{ - Key: key, - } - result := &common.Item{} - _, _, successor := self.ring.Remotes(key) - firstAddr := successor.Addr - for { - if err := successor.Call("DHash.Next", data, result); err != nil { - self.removeNode(*successor) - return self.Next(key) - } - if result.Exists { - break - } - _, _, successor = self.ring.Remotes(successor.Pos) - if successor.Addr == firstAddr { - break - } - } - nextKey, nextValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + } + result := &common.Item{} + _, _, successor := self.ring.Remotes(key) + firstAddr := successor.Addr + for { + if err := successor.Call("DHash.Next", data, result); err != nil { + self.removeNode(*successor) + return self.Next(key) + } + if result.Exists { + break + } + _, _, successor = self.ring.Remotes(successor.Pos) + if successor.Addr == firstAddr { + break + } + } + nextKey, nextValue, existed = result.Key, result.Value, result.Exists + return } // Prev will return the previous key and value before key. func (self *Conn) Prev(key []byte) (prevKey, prevValue []byte, existed bool) { - data := common.Item{ - Key: key, - } - result := &common.Item{} - _, _, successor := self.ring.Remotes(key) - firstAddr := successor.Addr - for { - if err := successor.Call("DHash.Prev", data, result); err != nil { - self.removeNode(*successor) - return self.Prev(key) - } - if result.Exists { - break - } - successor, _, _ = self.ring.Remotes(successor.Pos) - if successor.Addr == firstAddr { - break - } - } - prevKey, prevValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + } + result := &common.Item{} + _, _, successor := self.ring.Remotes(key) + firstAddr := successor.Addr + for { + if err := successor.Call("DHash.Prev", data, result); err != nil { + self.removeNode(*successor) + return self.Prev(key) + } + if result.Exists { + break + } + successor, _, _ = self.ring.Remotes(successor.Pos) + if successor.Addr == firstAddr { + break + } + } + prevKey, prevValue, existed = result.Key, result.Value, result.Exists + return } // MirrorCount will count the number of keys between min and max in the mirror tree of the sub tree defined by key. func (self *Conn) MirrorCount(key, min, max []byte, mininc, maxinc bool) (result int) { - r := common.Range{ - Key: key, - Min: min, - Max: max, - MinInc: mininc, - MaxInc: maxinc, - } - _, _, successor := self.ring.Remotes(key) - if err := successor.Call("DHash.MirrorCount", r, &result); err != nil { - self.removeNode(*successor) - return self.MirrorCount(key, min, max, mininc, maxinc) - } - return + r := common.Range{ + Key: key, + Min: min, + Max: max, + MinInc: mininc, + MaxInc: maxinc, + } + _, _, successor := self.ring.Remotes(key) + if err := successor.Call("DHash.MirrorCount", r, &result); err != nil { + self.removeNode(*successor) + return self.MirrorCount(key, min, max, mininc, maxinc) + } + return } // Count will count the number of keys between min and max in the sub tree defined by key. func (self *Conn) Count(key, min, max []byte, mininc, maxinc bool) (result int) { - r := common.Range{ - Key: key, - Min: min, - Max: max, - MinInc: mininc, - MaxInc: maxinc, - } - _, _, successor := self.ring.Remotes(key) - if err := successor.Call("DHash.Count", r, &result); err != nil { - self.removeNode(*successor) - return self.Count(key, min, max, mininc, maxinc) - } - return + r := common.Range{ + Key: key, + Min: min, + Max: max, + MinInc: mininc, + MaxInc: maxinc, + } + _, _, successor := self.ring.Remotes(key) + if err := successor.Call("DHash.Count", r, &result); err != nil { + self.removeNode(*successor) + return self.Count(key, min, max, mininc, maxinc) + } + return } // MirrorNextIndex will return the key, value and index of the first key after index in the mirror tree of the sub tree defined by key. func (self *Conn) MirrorNextIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) { - data := common.Item{ - Key: key, - Index: index, - } - result := &common.Item{} - _, _, successor := self.ring.Remotes(key) - if err := successor.Call("DHash.MirrorNextIndex", data, result); err != nil { - self.removeNode(*successor) - return self.MirrorNextIndex(key, index) - } - foundKey, foundValue, foundIndex, existed = result.Key, result.Value, result.Index, result.Exists - return + data := common.Item{ + Key: key, + Index: index, + } + result := &common.Item{} + _, _, successor := self.ring.Remotes(key) + if err := successor.Call("DHash.MirrorNextIndex", data, result); err != nil { + self.removeNode(*successor) + return self.MirrorNextIndex(key, index) + } + foundKey, foundValue, foundIndex, existed = result.Key, result.Value, result.Index, result.Exists + return } // MirrorPrevIndex will return the key, value and index of the first key before index in the mirror tree of the sub tree defined by key. func (self *Conn) MirrorPrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) { - data := common.Item{ - Key: key, - Index: index, - } - result := &common.Item{} - _, _, successor := self.ring.Remotes(key) - if err := successor.Call("DHash.MirrorPrevIndex", data, result); err != nil { - self.removeNode(*successor) - return self.MirrorNextIndex(key, index) - } - foundKey, foundValue, foundIndex, existed = result.Key, result.Value, result.Index, result.Exists - return + data := common.Item{ + Key: key, + Index: index, + } + result := &common.Item{} + _, _, successor := self.ring.Remotes(key) + if err := successor.Call("DHash.MirrorPrevIndex", data, result); err != nil { + self.removeNode(*successor) + return self.MirrorNextIndex(key, index) + } + foundKey, foundValue, foundIndex, existed = result.Key, result.Value, result.Index, result.Exists + return } // NextIndex will return the key, value and index of the first key after index in the sub tree defined by key. func (self *Conn) NextIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) { - data := common.Item{ - Key: key, - Index: index, - } - result := &common.Item{} - _, _, successor := self.ring.Remotes(key) - if err := successor.Call("DHash.NextIndex", data, result); err != nil { - self.removeNode(*successor) - return self.NextIndex(key, index) - } - foundKey, foundValue, foundIndex, existed = result.Key, result.Value, result.Index, result.Exists - return + data := common.Item{ + Key: key, + Index: index, + } + result := &common.Item{} + _, _, successor := self.ring.Remotes(key) + if err := successor.Call("DHash.NextIndex", data, result); err != nil { + self.removeNode(*successor) + return self.NextIndex(key, index) + } + foundKey, foundValue, foundIndex, existed = result.Key, result.Value, result.Index, result.Exists + return } // PrevIndex will return the key, value and index of the first key before index in the sub tree defined by key. func (self *Conn) PrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) { - data := common.Item{ - Key: key, - Index: index, - } - result := &common.Item{} - _, _, successor := self.ring.Remotes(key) - if err := successor.Call("DHash.PrevIndex", data, result); err != nil { - self.removeNode(*successor) - return self.NextIndex(key, index) - } - foundKey, foundValue, foundIndex, existed = result.Key, result.Value, result.Index, result.Exists - return + data := common.Item{ + Key: key, + Index: index, + } + result := &common.Item{} + _, _, successor := self.ring.Remotes(key) + if err := successor.Call("DHash.PrevIndex", data, result); err != nil { + self.removeNode(*successor) + return self.NextIndex(key, index) + } + foundKey, foundValue, foundIndex, existed = result.Key, result.Value, result.Index, result.Exists + return } // MirrorReverseSliceIndex will return the reverse slice between index min and max in the mirror tree of the sub tree defined by key. +// A min of nil will return from the end. A max of nil will return to the start. func (self *Conn) MirrorReverseSliceIndex(key []byte, min, max *int) (result []common.Item) { - var mi int - var ma int - if min != nil { - mi = *min - } - if max != nil { - ma = *max - } - r := common.Range{ - Key: key, - MinIndex: mi, - MaxIndex: ma, - MinInc: min != nil, - MaxInc: max != nil, - } - result = self.mergeRecent("DHash.MirrorReverseSliceIndex", r, false) - return + var mi int + var ma int + if min != nil { + mi = *min + } + if max != nil { + ma = *max + } + r := common.Range{ + Key: key, + MinIndex: mi, + MaxIndex: ma, + MinInc: min != nil, + MaxInc: max != nil, + } + result = self.mergeRecent("DHash.MirrorReverseSliceIndex", r, false) + return } // MirrorSliceIndex will return the slice between index min and max in the mirror tree of the sub tree defined by key. +// A min of nil will return from the start. A max of nil will return to the end. func (self *Conn) MirrorSliceIndex(key []byte, min, max *int) (result []common.Item) { - var mi int - var ma int - if min != nil { - mi = *min - } - if max != nil { - ma = *max - } - r := common.Range{ - Key: key, - MinIndex: mi, - MaxIndex: ma, - MinInc: min != nil, - MaxInc: max != nil, - } - result = self.mergeRecent("DHash.MirrorSliceIndex", r, true) - return + var mi int + var ma int + if min != nil { + mi = *min + } + if max != nil { + ma = *max + } + r := common.Range{ + Key: key, + MinIndex: mi, + MaxIndex: ma, + MinInc: min != nil, + MaxInc: max != nil, + } + result = self.mergeRecent("DHash.MirrorSliceIndex", r, true) + return } // MirrorReverseSlice will return the reverse slice between min and max in the mirror tree of the sub tree defined by key. +// A min of nil will return from the end. A max of nil will return to the start. func (self *Conn) MirrorReverseSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) { - r := common.Range{ - Key: key, - Min: min, - Max: max, - MinInc: mininc, - MaxInc: maxinc, - } - result = self.mergeRecent("DHash.MirrorReverseSlice", r, false) - return + r := common.Range{ + Key: key, + Min: min, + Max: max, + MinInc: mininc, + MaxInc: maxinc, + } + result = self.mergeRecent("DHash.MirrorReverseSlice", r, false) + return } // MirrorSlice will return the slice between min and max in the mirror tree of the sub tree defined by key. +// A min of nil will return from the start. A max of nil will return to the end. func (self *Conn) MirrorSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) { - r := common.Range{ - Key: key, - Min: min, - Max: max, - MinInc: mininc, - MaxInc: maxinc, - } - result = self.mergeRecent("DHash.MirrorSlice", r, true) - return + r := common.Range{ + Key: key, + Min: min, + Max: max, + MinInc: mininc, + MaxInc: maxinc, + } + result = self.mergeRecent("DHash.MirrorSlice", r, true) + return } // MirrorSliceLen will return at most maxRes elements after min in the mirror tree of the sub tree defined by key. +// A min of nil will return from the start. func (self *Conn) MirrorSliceLen(key, min []byte, mininc bool, maxRes int) (result []common.Item) { - r := common.Range{ - Key: key, - Min: min, - MinInc: mininc, - Len: maxRes, - } - result = self.mergeRecent("DHash.MirrorSliceLen", r, true) - return + r := common.Range{ + Key: key, + Min: min, + MinInc: mininc, + Len: maxRes, + } + result = self.mergeRecent("DHash.MirrorSliceLen", r, true) + return } // MirrorReverseSliceLen will return at most maxRes elements before max in the mirror tree of the sub tree defined by key. +// A min of nil will return from the end. func (self *Conn) MirrorReverseSliceLen(key, max []byte, maxinc bool, maxRes int) (result []common.Item) { - r := common.Range{ - Key: key, - Max: max, - MaxInc: maxinc, - Len: maxRes, - } - result = self.mergeRecent("DHash.MirrorReverseSliceLen", r, false) - return + r := common.Range{ + Key: key, + Max: max, + MaxInc: maxinc, + Len: maxRes, + } + result = self.mergeRecent("DHash.MirrorReverseSliceLen", r, false) + return } // ReverseSliceIndex will the reverse slice between index min and max in the sub tree defined by key. +// A min of nil will return from the end. A max of nil will return to the start. func (self *Conn) ReverseSliceIndex(key []byte, min, max *int) (result []common.Item) { - var mi int - var ma int - if min != nil { - mi = *min - } - if max != nil { - ma = *max - } - r := common.Range{ - Key: key, - MinIndex: mi, - MaxIndex: ma, - MinInc: min != nil, - MaxInc: max != nil, - } - result = self.mergeRecent("DHash.ReverseSliceIndex", r, false) - return + var mi int + var ma int + if min != nil { + mi = *min + } + if max != nil { + ma = *max + } + r := common.Range{ + Key: key, + MinIndex: mi, + MaxIndex: ma, + MinInc: min != nil, + MaxInc: max != nil, + } + result = self.mergeRecent("DHash.ReverseSliceIndex", r, false) + return } // SliceIndex will return the slice between index min and max in the sub tree defined by key. +// A min of nil will return from the start. A max of nil will return to the end. func (self *Conn) SliceIndex(key []byte, min, max *int) (result []common.Item) { - var mi int - var ma int - if min != nil { - mi = *min - } - if max != nil { - ma = *max - } - r := common.Range{ - Key: key, - MinIndex: mi, - MaxIndex: ma, - MinInc: min != nil, - MaxInc: max != nil, - } - result = self.mergeRecent("DHash.SliceIndex", r, true) - return + var mi int + var ma int + if min != nil { + mi = *min + } + if max != nil { + ma = *max + } + r := common.Range{ + Key: key, + MinIndex: mi, + MaxIndex: ma, + MinInc: min != nil, + MaxInc: max != nil, + } + result = self.mergeRecent("DHash.SliceIndex", r, true) + return } // ReverseSlice will return the reverse slice between min and max in the sub tree defined by key. +// A min of nil will return from the end. A max of nil will return to the start. func (self *Conn) ReverseSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) { - r := common.Range{ - Key: key, - Min: min, - Max: max, - MinInc: mininc, - MaxInc: maxinc, - } - result = self.mergeRecent("DHash.ReverseSlice", r, false) - return -} - -// ReverseSlice will return the slice between min and max in the sub tree defined by key. + r := common.Range{ + Key: key, + Min: min, + Max: max, + MinInc: mininc, + MaxInc: maxinc, + } + result = self.mergeRecent("DHash.ReverseSlice", r, false) + return +} + +// Slice will return the slice between min and max in the sub tree defined by key. +// A min of nil will return from the start. A max of nil will return to the end. func (self *Conn) Slice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) { - r := common.Range{ - Key: key, - Min: min, - Max: max, - MinInc: mininc, - MaxInc: maxinc, - } - result = self.mergeRecent("DHash.Slice", r, true) - return + r := common.Range{ + Key: key, + Min: min, + Max: max, + MinInc: mininc, + MaxInc: maxinc, + } + result = self.mergeRecent("DHash.Slice", r, true) + return } // SliceLen will return at most maxRes elements after min in the sub tree defined by key. +// A min of nil will return from the start. func (self *Conn) SliceLen(key, min []byte, mininc bool, maxRes int) (result []common.Item) { - r := common.Range{ - Key: key, - Min: min, - MinInc: mininc, - Len: maxRes, - } - result = self.mergeRecent("DHash.SliceLen", r, true) - return + r := common.Range{ + Key: key, + Min: min, + MinInc: mininc, + Len: maxRes, + } + result = self.mergeRecent("DHash.SliceLen", r, true) + return } // ReverseSliceLen will return at most maxRes elements before max in the sub tree defined by key. +// A min of nil will return from the end. A max of nil will return to the start. func (self *Conn) ReverseSliceLen(key, max []byte, maxinc bool, maxRes int) (result []common.Item) { - r := common.Range{ - Key: key, - Max: max, - MaxInc: maxinc, - Len: maxRes, - } - result = self.mergeRecent("DHash.ReverseSliceLen", r, false) - return + r := common.Range{ + Key: key, + Max: max, + MaxInc: maxinc, + Len: maxRes, + } + result = self.mergeRecent("DHash.ReverseSliceLen", r, false) + return } // SubMirrorPrev will return the previous key and value before subKey in the sub tree defined by key. func (self *Conn) SubMirrorPrev(key, subKey []byte) (prevKey, prevValue []byte, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - result := self.findRecent("DHash.SubMirrorPrev", data) - prevKey, prevValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + result := self.findRecent("DHash.SubMirrorPrev", data) + prevKey, prevValue, existed = result.Key, result.Value, result.Exists + return } -// SubMirrorPrev will return the next key and value after subKey in the sub tree defined by key. +// SubMirrorNext will return the next key and value after subKey in the sub tree defined by key. func (self *Conn) SubMirrorNext(key, subKey []byte) (nextKey, nextValue []byte, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - result := self.findRecent("DHash.SubMirrorNext", data) - nextKey, nextValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + result := self.findRecent("DHash.SubMirrorNext", data) + nextKey, nextValue, existed = result.Key, result.Value, result.Exists + return } // SubPrev will return the previous key and value before subKey in the sub tree defined by key. func (self *Conn) SubPrev(key, subKey []byte) (prevKey, prevValue []byte, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - result := self.findRecent("DHash.SubPrev", data) - prevKey, prevValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + result := self.findRecent("DHash.SubPrev", data) + prevKey, prevValue, existed = result.Key, result.Value, result.Exists + return } // SubNext will return the next key and value after subKey in the sub tree defined by key. func (self *Conn) SubNext(key, subKey []byte) (nextKey, nextValue []byte, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - result := self.findRecent("DHash.SubNext", data) - nextKey, nextValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + result := self.findRecent("DHash.SubNext", data) + nextKey, nextValue, existed = result.Key, result.Value, result.Exists + return } // MirrorLast will return the last key and valuei in the mirror tree of the sub tree defined by key. func (self *Conn) MirrorLast(key []byte) (lastKey, lastValue []byte, existed bool) { - data := common.Item{ - Key: key, - } - result := self.findRecent("DHash.MirrorLast", data) - lastKey, lastValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + } + result := self.findRecent("DHash.MirrorLast", data) + lastKey, lastValue, existed = result.Key, result.Value, result.Exists + return } // MirrorFirst will return the first key and value in the mirror tree of the sub tree defined by key. func (self *Conn) MirrorFirst(key []byte) (firstKey, firstValue []byte, existed bool) { - data := common.Item{ - Key: key, - } - result := self.findRecent("DHash.MirrorFirst", data) - firstKey, firstValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + } + result := self.findRecent("DHash.MirrorFirst", data) + firstKey, firstValue, existed = result.Key, result.Value, result.Exists + return } // Last will return the last key and value in the sub tree defined by key. func (self *Conn) Last(key []byte) (lastKey, lastValue []byte, existed bool) { - data := common.Item{ - Key: key, - } - result := self.findRecent("DHash.Last", data) - lastKey, lastValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + } + result := self.findRecent("DHash.Last", data) + lastKey, lastValue, existed = result.Key, result.Value, result.Exists + return } // First will return the first key and value in the sub tree defined by key. func (self *Conn) First(key []byte) (firstKey, firstValue []byte, existed bool) { - data := common.Item{ - Key: key, - } - result := self.findRecent("DHash.First", data) - firstKey, firstValue, existed = result.Key, result.Value, result.Exists - return + data := common.Item{ + Key: key, + } + result := self.findRecent("DHash.First", data) + firstKey, firstValue, existed = result.Key, result.Value, result.Exists + return } // SubGet will return the value under subKey in the sub tree defined by key. func (self *Conn) SubGet(key, subKey []byte) (value []byte, existed bool) { - data := common.Item{ - Key: key, - SubKey: subKey, - } - result := self.findRecent("DHash.SubGet", data) - if result.Value != nil { - value, existed = result.Value, result.Exists - } else { - value, existed = nil, false - } - return + data := common.Item{ + Key: key, + SubKey: subKey, + } + result := self.findRecent("DHash.SubGet", data) + if result.Value != nil { + value, existed = result.Value, result.Exists + } else { + value, existed = nil, false + } + return } // Get will return the value under key. func (self *Conn) Get(key []byte) (value []byte, existed bool) { - data := common.Item{ - Key: key, - } - result := self.findRecent("DHash.Get", data) - if result.Value != nil { - value, existed = result.Value, result.Exists - } else { - value, existed = nil, false - } - return + data := common.Item{ + Key: key, + } + result := self.findRecent("DHash.Get", data) + if result.Value != nil { + value, existed = result.Value, result.Exists + } else { + value, existed = nil, false + } + return } // DescribeTree will return a string representation of the complete tree in the node at pos. // Used for debug purposes, don't do it on big databases! func (self *Conn) DescribeTree(pos []byte) (result string, err error) { - _, match, _ := self.ring.Remotes(pos) - if match == nil { - err = fmt.Errorf("No node with position %v found", common.HexEncode(pos)) - return - } - err = match.Call("DHash.DescribeTree", 0, &result) - return + _, match, _ := self.ring.Remotes(pos) + if match == nil { + err = fmt.Errorf("No node with position %v found", common.HexEncode(pos)) + return + } + err = match.Call("DHash.DescribeTree", 0, &result) + return } -// DescribeTree will return a string representation of the complete trees of all known nodes. +// DescribeAllTrees will return a string representation of the complete trees of all known nodes. // Used for debug purposes, don't do it on big databases! func (self *Conn) DescribeAllTrees() string { - buf := new(bytes.Buffer) - for _, rem := range self.ring.Nodes() { - if res, err := self.DescribeTree(rem.Pos); err == nil { - fmt.Fprintln(buf, res) - } - } - return string(buf.Bytes()) + buf := new(bytes.Buffer) + for _, rem := range self.ring.Nodes() { + if res, err := self.DescribeTree(rem.Pos); err == nil { + fmt.Fprintln(buf, res) + } + } + return string(buf.Bytes()) } // DescribeAllNodes will return the description structures of all known nodes. func (self *Conn) DescribeAllNodes() (result []common.DHashDescription) { - for _, rem := range self.ring.Nodes() { - if res, err := self.DescribeNode(rem.Pos); err == nil { - result = append(result, res) - } - } - return + for _, rem := range self.ring.Nodes() { + if res, err := self.DescribeNode(rem.Pos); err == nil { + result = append(result, res) + } + } + return } // DescribeNode will return the description structure of the node at pos. func (self *Conn) DescribeNode(pos []byte) (result common.DHashDescription, err error) { - _, match, _ := self.ring.Remotes(pos) - if match == nil { - err = fmt.Errorf("No node with position %v found", common.HexEncode(pos)) - return - } - err = match.Call("DHash.Describe", 0, &result) - return + _, match, _ := self.ring.Remotes(pos) + if match == nil { + err = fmt.Errorf("No node with position %v found", common.HexEncode(pos)) + return + } + err = match.Call("DHash.Describe", 0, &result) + return } // SubSize will return the size of the sub tree defined by key. func (self *Conn) SubSize(key []byte) (result int) { - _, _, successor := self.ring.Remotes(key) - if err := successor.Call("DHash.SubSize", key, &result); err != nil { - self.removeNode(*successor) - return self.SubSize(key) - } - return + _, _, successor := self.ring.Remotes(key) + if err := successor.Call("DHash.SubSize", key, &result); err != nil { + self.removeNode(*successor) + return self.SubSize(key) + } + return } // Size will return the total size of all known nodes. func (self *Conn) Size() (result int) { - var tmp int - for _, node := range self.ring.Nodes() { - if err := node.Call("DHash.Size", 0, &tmp); err != nil { - self.removeNode(node) - return self.Size() - } - result += tmp - } - return + var tmp int + for _, node := range self.ring.Nodes() { + if err := node.Call("DHash.Size", 0, &tmp); err != nil { + self.removeNode(node) + return self.Size() + } + result += tmp + } + return } // Describe will return a string representation of the known cluster of nodes. func (self *Conn) Describe() string { - return self.ring.Describe() + return self.ring.Describe() } // SetExpression will execute the given expr. @@ -974,91 +986,91 @@ func (self *Conn) Describe() string { // // If expr.Dest is nil it will return the result. // -// Either expr.Op or expr.Code has to be set. +// Either expr.Op or expr.Code has to be set. // // If expr.Op is nil expr.Code will be parsed using SetOpParser to provide expr.Op. func (self *Conn) SetExpression(expr setop.SetExpression) (result []setop.SetOpResult) { - if expr.Op == nil { - expr.Op = setop.MustParse(expr.Code) - } - var biggestKey []byte - biggestSize := 0 - var thisSize int - - for key, _ := range findKeys(expr.Op) { - thisSize = self.SubSize([]byte(key)) - if biggestKey == nil { - biggestKey = []byte(key) - biggestSize = thisSize - } else if thisSize > biggestSize { - biggestKey = []byte(key) - biggestSize = thisSize - } - } - _, _, successor := self.ring.Remotes(biggestKey) - var results []setop.SetOpResult - err := successor.Call("DHash.SetExpression", expr, &results) - for err != nil { - self.removeNode(*successor) - _, _, successor = self.ring.Remotes(biggestKey) - err = successor.Call("DHash.SetExpression", expr, &results) - } - return results + if expr.Op == nil { + expr.Op = setop.MustParse(expr.Code) + } + var biggestKey []byte + biggestSize := 0 + var thisSize int + + for key, _ := range findKeys(expr.Op) { + thisSize = self.SubSize([]byte(key)) + if biggestKey == nil { + biggestKey = []byte(key) + biggestSize = thisSize + } else if thisSize > biggestSize { + biggestKey = []byte(key) + biggestSize = thisSize + } + } + _, _, successor := self.ring.Remotes(biggestKey) + var results []setop.SetOpResult + err := successor.Call("DHash.SetExpression", expr, &results) + for err != nil { + self.removeNode(*successor) + _, _, successor = self.ring.Remotes(biggestKey) + err = successor.Call("DHash.SetExpression", expr, &results) + } + return results } // Configuration will return the configuration for the entire cluster. // Not internally used for anything right now. func (self *Conn) Configuration() (conf map[string]string) { - var result common.Conf - _, _, successor := self.ring.Remotes(nil) - if err := successor.Call("DHash.Configuration", 0, &result); err != nil { - self.removeNode(*successor) - return self.Configuration() - } - return result.Data + var result common.Conf + _, _, successor := self.ring.Remotes(nil) + if err := successor.Call("DHash.Configuration", 0, &result); err != nil { + self.removeNode(*successor) + return self.Configuration() + } + return result.Data } -// SubConfiguratino will return the configuration for the sub tree defined by key. +// SubConfiguration will return the configuration for the sub tree defined by key. // // mirrored=yes means that the sub tree is currently mirrored. func (self *Conn) SubConfiguration(key []byte) (conf map[string]string) { - var result common.Conf - _, _, successor := self.ring.Remotes(nil) - if err := successor.Call("DHash.SubConfiguration", key, &result); err != nil { - self.removeNode(*successor) - return self.Configuration() - } - return result.Data + var result common.Conf + _, _, successor := self.ring.Remotes(nil) + if err := successor.Call("DHash.SubConfiguration", key, &result); err != nil { + self.removeNode(*successor) + return self.Configuration() + } + return result.Data } // AddConfiguration will set a key and value to the cluster configuration. // Not internally used for anything right now. func (self *Conn) AddConfiguration(key, value string) { - conf := common.ConfItem{ - Key: key, - Value: value, - } - _, _, successor := self.ring.Remotes(nil) - var x int - if err := successor.Call("DHash.AddConfiguration", conf, &x); err != nil { - self.removeNode(*successor) - self.AddConfiguration(key, value) - } -} - -// SubAddConfiguration will set a key and value to the configuratino of the sub tree defined by key. + conf := common.ConfItem{ + Key: key, + Value: value, + } + _, _, successor := self.ring.Remotes(nil) + var x int + if err := successor.Call("DHash.AddConfiguration", conf, &x); err != nil { + self.removeNode(*successor) + self.AddConfiguration(key, value) + } +} + +// SubAddConfiguration will set a key and value to the configuration of the sub tree defined by key. // // To mirror a sub tree, set mirrored=yes. To turn off mirroring of a sub tree, set mirrored!=yes. func (self *Conn) SubAddConfiguration(treeKey []byte, key, value string) { - conf := common.ConfItem{ - TreeKey: treeKey, - Key: key, - Value: value, - } - _, _, successor := self.ring.Remotes(nil) - var x int - if err := successor.Call("DHash.SubAddConfiguration", conf, &x); err != nil { - self.removeNode(*successor) - self.AddConfiguration(key, value) - } + conf := common.ConfItem{ + TreeKey: treeKey, + Key: key, + Value: value, + } + _, _, successor := self.ring.Remotes(nil) + var x int + if err := successor.Call("DHash.SubAddConfiguration", conf, &x); err != nil { + self.removeNode(*successor) + self.AddConfiguration(key, value) + } } diff --git a/client/client_test.go b/client/client_test.go deleted file mode 100644 index c8c1c20..0000000 --- a/client/client_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package client - -import ( - "fmt" - "github.com/zond/god/common" - "github.com/zond/god/setop" -) - -func ExampleSetExpression() { - conn := MustConn("127.0.0.1:9191") - conn.Kill() - conn.SubPut([]byte("myfriends"), []byte("alice"), common.EncodeFloat64(10)) - conn.SubPut([]byte("myfriends"), []byte("bob"), common.EncodeFloat64(5)) - conn.SubPut([]byte("yourfriends"), []byte("bob"), common.EncodeFloat64(6)) - conn.SubPut([]byte("yourfriends"), []byte("charlie"), common.EncodeFloat64(4)) - fmt.Printf("name score\n") - for _, friend := range conn.SetExpression(setop.SetExpression{ - Code: "(U:FloatSum myfriends yourfriends)", - }) { - fmt.Printf("%v %v\n", string(friend.Key), common.MustDecodeFloat64(friend.Values[0])) - } - // Output: - // name score - // alice 10 - // bob 11 - // charlie 4 -} - -func ExampleTreeMirror() { - conn := MustConn("127.0.0.1:9191") - conn.Kill() - conn.SubAddConfiguration([]byte("myfriends"), "mirrored", "yes") - conn.SubPut([]byte("myfriends"), []byte("alice"), common.EncodeFloat64(10)) - conn.SubPut([]byte("myfriends"), []byte("bob"), common.EncodeFloat64(5)) - conn.SubPut([]byte("myfriends"), []byte("charlie"), common.EncodeFloat64(6)) - conn.SubPut([]byte("myfriends"), []byte("denise"), common.EncodeFloat64(4)) - fmt.Printf("name score\n") - for _, friend := range conn.MirrorReverseSlice([]byte("myfriends"), nil, nil, true, true) { - fmt.Printf("%v %v\n", common.MustDecodeFloat64(friend.Key), string(friend.Value)) - } - // Output: - // name score - // 10 alice - // 6 charlie - // 5 bob - // 4 denise -} diff --git a/client/examples/example_test.go b/client/examples/example_test.go new file mode 100644 index 0000000..0931d39 --- /dev/null +++ b/client/examples/example_test.go @@ -0,0 +1,53 @@ +package client + +import ( + "fmt" + + "github.com/zond/god/client" + "github.com/zond/god/dhash" + "github.com/zond/setop" +) + +var ran = false + +func ExampleSetExpression() { + server := dhash.NewNodeDir("127.0.0.1:2020", "127.0.0.1:2020", "").MustStart() + defer server.Stop() + conn := client.MustConn("127.0.0.1:2020") + conn.SubPut([]byte("myfriends"), []byte("alice"), setop.EncodeFloat64(10)) + conn.SubPut([]byte("myfriends"), []byte("bob"), setop.EncodeFloat64(5)) + conn.SubPut([]byte("yourfriends"), []byte("bob"), setop.EncodeFloat64(6)) + conn.SubPut([]byte("yourfriends"), []byte("charlie"), setop.EncodeFloat64(4)) + fmt.Printf("name score\n") + for _, friend := range conn.SetExpression(setop.SetExpression{ + Code: "(U:FloatSum myfriends yourfriends)", + }) { + fmt.Printf("%v %v\n", string(friend.Key), fmt.Sprint(setop.DecodeFloat64(friend.Values[0]))) + } + // Output: + // name score + // alice 10 + // bob 11 + // charlie 4 +} + +func ExampleTreeMirror() { + server := dhash.NewNodeDir("127.0.0.1:3030", "127.0.0.1:3030", "").MustStart() + defer server.Stop() + conn := client.MustConn("127.0.0.1:3030") + conn.SubAddConfiguration([]byte("myfriends"), "mirrored", "yes") + conn.SubPut([]byte("myfriends"), []byte("alice"), setop.EncodeFloat64(10)) + conn.SubPut([]byte("myfriends"), []byte("bob"), setop.EncodeFloat64(5)) + conn.SubPut([]byte("myfriends"), []byte("charlie"), setop.EncodeFloat64(6)) + conn.SubPut([]byte("myfriends"), []byte("denise"), setop.EncodeFloat64(4)) + fmt.Printf("name score\n") + for _, friend := range conn.MirrorReverseSlice([]byte("myfriends"), nil, nil, true, true) { + fmt.Printf("%v %v\n", fmt.Sprint(setop.DecodeFloat64(friend.Key)), string(friend.Value)) + } + // Output: + // name score + // 10 alice + // 6 charlie + // 5 bob + // 4 denise +} diff --git a/common/common.go b/common/common.go index ed30ddb..a42be84 100644 --- a/common/common.go +++ b/common/common.go @@ -2,10 +2,9 @@ package common import ( "bytes" - "encoding/binary" "encoding/hex" + "encoding/json" "fmt" - "math/big" "runtime" "sort" "strconv" @@ -14,10 +13,17 @@ import ( ) const ( - Redundancy = 3 PingInterval = time.Second ) +var ( + Redundancy int = 3 +) + +func SetRedundancy(r int) { + Redundancy = r +} + func MustParseFloat64(s string) (result float64) { var err error if result, err = strconv.ParseFloat(s, 64); err != nil { @@ -26,48 +32,18 @@ func MustParseFloat64(s string) (result float64) { return } -func EncodeBigInt(i *big.Int) []byte { - return i.Bytes() -} -func DecodeBigInt(b []byte) (result *big.Int) { - result = new(big.Int).SetBytes(b) - return -} -func EncodeInt64(i int64) []byte { - result := new(bytes.Buffer) - if err := binary.Write(result, binary.BigEndian, i); err != nil { - panic(err) - } - return result.Bytes() -} -func MustDecodeInt64(b []byte) (result int64) { - result, err := DecodeInt64(b) +func MustJSONEncode(i interface{}) []byte { + result, err := json.Marshal(i) if err != nil { panic(err) } - return -} -func DecodeInt64(b []byte) (result int64, err error) { - err = binary.Read(bytes.NewBuffer(b), binary.BigEndian, &result) - return + return result } -func EncodeFloat64(f float64) []byte { - result := new(bytes.Buffer) - if err := binary.Write(result, binary.BigEndian, f); err != nil { - panic(err) - } - return result.Bytes() -} -func MustDecodeFloat64(b []byte) (result float64) { - result, err := DecodeFloat64(b) +func MustJSONDecode(b []byte, i interface{}) { + err := json.Unmarshal(b, i) if err != nil { panic(err) } - return -} -func DecodeFloat64(b []byte) (result float64, err error) { - err = binary.Read(bytes.NewBuffer(b), binary.BigEndian, &result) - return } func Max64(i ...int64) (result int64) { diff --git a/common/remote.go b/common/remote.go index 83ec540..09adef0 100644 --- a/common/remote.go +++ b/common/remote.go @@ -1,66 +1,70 @@ package common import ( - "bytes" - "fmt" - "net/rpc" + "bytes" + "fmt" + "net/rpc" ) type Remotes []Remote func (self Remotes) Equal(other []Remote) bool { - if len(self) != len(other) { - return false - } - for i, r := range self { - if !r.Equal(other[i]) { - return false - } - } - return true + if len(self) != len(other) { + return false + } + for i, r := range self { + if !r.Equal(other[i]) { + return false + } + } + return true } func (self Remotes) Describe() string { - buffer := new(bytes.Buffer) - for index, node := range self { - fmt.Fprintf(buffer, "%v: %v\n", index, node) - } - return string(buffer.Bytes()) + buffer := new(bytes.Buffer) + for index, node := range self { + fmt.Fprintf(buffer, "%v: %v\n", index, node) + } + return string(buffer.Bytes()) } func (self Remotes) Clone() (result Remotes) { - result = make(Remotes, len(self)) - for i, n := range self { - result[i] = n.Clone() - } - return + result = make(Remotes, len(self)) + for i, n := range self { + result[i] = n.Clone() + } + return } type Remote struct { - Pos []byte - Addr string + Pos []byte + Addr string } func (self Remote) Clone() (result Remote) { - result.Pos = make([]byte, len(self.Pos)) - copy(result.Pos, self.Pos) - result.Addr = self.Addr - return + result.Pos = make([]byte, len(self.Pos)) + copy(result.Pos, self.Pos) + result.Addr = self.Addr + return } func (self Remote) Equal(other Remote) bool { - return self.Addr == other.Addr && bytes.Compare(self.Pos, other.Pos) == 0 + return self.Addr == other.Addr && bytes.Compare(self.Pos, other.Pos) == 0 } func (self Remote) Less(other Remote) bool { - val := bytes.Compare(self.Pos, other.Pos) - if val == 0 { - val = bytes.Compare([]byte(self.Addr), []byte(other.Addr)) - } - return val < 0 + val := bytes.Compare(self.Pos, other.Pos) + if val == 0 { + val = bytes.Compare([]byte(self.Addr), []byte(other.Addr)) + } + return val < 0 } func (self Remote) String() string { - return fmt.Sprintf("[%v@%v]", HexEncode(self.Pos), self.Addr) + return fmt.Sprintf("[%v@%v]", HexEncode(self.Pos), self.Addr) } func (self Remote) Call(service string, args, reply interface{}) error { - return Switch.Call(self.Addr, service, args, reply) + return Switch.Call(self.Addr, service, args, reply) } func (self Remote) Go(service string, args, reply interface{}) *rpc.Call { - return Switch.Go(self.Addr, service, args, reply) + return Switch.Go(self.Addr, service, args, reply) +} + +func (self Remote) Close() error { + return Switch.Close(self.Addr) } diff --git a/common/ring.go b/common/ring.go index 9f697eb..e6ddfd9 100644 --- a/common/ring.go +++ b/common/ring.go @@ -1,215 +1,221 @@ package common import ( - "bytes" - "fmt" - "github.com/zond/god/murmur" - "math/big" - "math/rand" - "sort" - "sync" + "bytes" + "fmt" + "github.com/zond/god/murmur" + "math/big" + "math/rand" + "sort" + "sync" ) // RingChangeListener is a function listening to changes in a Ring (ie changes in Node composition or position). type RingChangeListener func(ring *Ring) (keep bool) -// Ring contains an ordered set of routes to discord.Nodes. +// Ring contains an ordered set of routes to discord.Nodes. // It can fetch predecessor, match and successor for any key or remote (remotes are ordeded first on position, then on address, so that we have // a defined orded even between nodes with the same position). type Ring struct { - nodes Remotes - lock *sync.RWMutex - changeListeners []RingChangeListener + nodes Remotes + lock *sync.RWMutex + changeListeners []RingChangeListener } func NewRing() *Ring { - return &Ring{ - lock: new(sync.RWMutex), - } + return &Ring{ + lock: new(sync.RWMutex), + } } func NewRingNodes(nodes Remotes) *Ring { - return &Ring{ - lock: new(sync.RWMutex), - nodes: nodes, - } + return &Ring{ + lock: new(sync.RWMutex), + nodes: nodes, + } } func (self *Ring) AddChangeListener(f RingChangeListener) { - self.lock.Lock() - defer self.lock.Unlock() - self.changeListeners = append(self.changeListeners, f) + self.lock.Lock() + defer self.lock.Unlock() + self.changeListeners = append(self.changeListeners, f) } // Random returns a random Node in this Ring. func (self *Ring) Random() Remote { - self.lock.RLock() - defer self.lock.RUnlock() - return self.nodes[rand.Int()%len(self.nodes)].Clone() + self.lock.RLock() + defer self.lock.RUnlock() + return self.nodes[rand.Int()%len(self.nodes)].Clone() } func (self *Ring) hash() []byte { - hasher := murmur.New() - for _, node := range self.nodes { - hasher.MustWrite(node.Pos) - hasher.MustWrite([]byte(node.Addr)) - } - return hasher.Get() + hasher := murmur.New() + for _, node := range self.nodes { + hasher.MustWrite(node.Pos) + hasher.MustWrite([]byte(node.Addr)) + } + return hasher.Get() } // Hash returns a hash of the contents of this Ring. func (self *Ring) Hash() []byte { - self.lock.RLock() - defer self.lock.RUnlock() - return self.hash() + self.lock.RLock() + defer self.lock.RUnlock() + return self.hash() } // Validate, used for testing, validates the orded in this Ring. func (self *Ring) Validate() { - clone := self.Clone() - seen := make(map[string]bool) - var last *Remote - for _, node := range clone.nodes { - if _, ok := seen[node.Addr]; ok { - panic(fmt.Errorf("Duplicate node in Ring! %v", clone.Describe())) - } - if last != nil && node.Less(*last) { - panic(fmt.Errorf("Badly ordered Ring! %v", clone.Describe())) - } - last = &node - seen[node.Addr] = true - } + clone := self.Clone() + seen := make(map[string]bool) + var last *Remote + for _, node := range clone.nodes { + if _, ok := seen[node.Addr]; ok { + panic(fmt.Errorf("Duplicate node in Ring! %v", clone.Describe())) + } + if last != nil && node.Less(*last) { + panic(fmt.Errorf("Badly ordered Ring! %v", clone.Describe())) + } + last = &node + seen[node.Addr] = true + } } // Describe returns a humanly readable description of this Ring. func (self *Ring) Describe() string { - self.lock.RLock() - defer self.lock.RUnlock() - return self.nodes.Describe() + self.lock.RLock() + defer self.lock.RUnlock() + return self.nodes.Describe() } // SetNodes copies the nodes to replace the Nodes in this Ring. func (self *Ring) SetNodes(nodes Remotes) { - self.lock.Lock() - defer self.lock.Unlock() - h := self.hash() - self.nodes = nodes.Clone() - self.sendChanges(h) + self.lock.Lock() + defer self.lock.Unlock() + h := self.hash() + self.nodes = nodes.Clone() + self.sendChanges(h) } func (self *Ring) sendChanges(oldHash []byte) { - if bytes.Compare(oldHash, self.hash()) != 0 { - var newListeners []RingChangeListener - clone := NewRingNodes(self.nodes.Clone()) - for _, listener := range self.changeListeners { - self.lock.Unlock() - if listener(clone) { - newListeners = append(newListeners, listener) - } - self.lock.Lock() - } - self.changeListeners = newListeners - } + if bytes.Compare(oldHash, self.hash()) != 0 { + var newListeners []RingChangeListener + clone := NewRingNodes(self.nodes.Clone()) + for _, listener := range self.changeListeners { + self.lock.Unlock() + if listener(clone) { + newListeners = append(newListeners, listener) + } + self.lock.Lock() + } + self.changeListeners = newListeners + } } // Nodes returns a copy of the Nodes of this Ring. func (self *Ring) Nodes() Remotes { - self.lock.RLock() - defer self.lock.RUnlock() - return self.nodes.Clone() + self.lock.RLock() + defer self.lock.RUnlock() + return self.nodes.Clone() } // Clone returns a copy of this Ring and its contents. func (self *Ring) Clone() *Ring { - return NewRingNodes(self.Nodes()) + return NewRingNodes(self.Nodes()) } func (self *Ring) Size() int { - self.lock.RLock() - defer self.lock.RUnlock() - return len(self.nodes) + self.lock.RLock() + defer self.lock.RUnlock() + return len(self.nodes) } func (self *Ring) Equal(other *Ring) bool { - return self.Nodes().Equal(other.Nodes()) + return self.Nodes().Equal(other.Nodes()) } func (self *Ring) predecessorIndex(r Remote) int { - i := sort.Search(len(self.nodes), func(i int) bool { - return !self.nodes[i].Less(r) - }) - if i < len(self.nodes) && i > 0 { - return i - 1 - } - return len(self.nodes) - 1 + i := sort.Search(len(self.nodes), func(i int) bool { + return !self.nodes[i].Less(r) + }) + if i < len(self.nodes) && i > 0 { + return i - 1 + } + return len(self.nodes) - 1 } func (self *Ring) Predecessor(r Remote) Remote { - self.lock.RLock() - defer self.lock.RUnlock() - return self.nodes[self.predecessorIndex(r)] + self.lock.RLock() + defer self.lock.RUnlock() + if len(self.nodes) == 0 { + return r + } + if len(self.nodes) == 1 { + return self.nodes[0] + } + return self.nodes[self.predecessorIndex(r)] } func (self *Ring) successorIndex(r Remote) int { - i := sort.Search(len(self.nodes), func(i int) bool { - return r.Less(self.nodes[i]) - }) - if i < len(self.nodes) { - return i - } - return 0 + i := sort.Search(len(self.nodes), func(i int) bool { + return r.Less(self.nodes[i]) + }) + if i < len(self.nodes) { + return i + } + return 0 } func (self *Ring) Successor(r Remote) Remote { - self.lock.RLock() - defer self.lock.RUnlock() - return self.nodes[self.successorIndex(r)].Clone() + self.lock.RLock() + defer self.lock.RUnlock() + return self.nodes[self.successorIndex(r)].Clone() } // Add adds r to this Ring. If a Node with the same address is already present, it will be updated if needed. func (self *Ring) Add(r Remote) { - self.lock.Lock() - defer self.lock.Unlock() - oldHash := self.hash() - remote := r.Clone() - for index, current := range self.nodes { - if current.Addr == remote.Addr { - if bytes.Compare(current.Pos, remote.Pos) == 0 { - return - } - self.nodes = append(self.nodes[:index], self.nodes[index+1:]...) - } - } - i := sort.Search(len(self.nodes), func(i int) bool { - return remote.Less(self.nodes[i]) - }) - if i < len(self.nodes) { - self.nodes = append(self.nodes[:i], append(Remotes{remote}, self.nodes[i:]...)...) - } else { - self.nodes = append(self.nodes, remote) - } - self.sendChanges(oldHash) + self.lock.Lock() + defer self.lock.Unlock() + oldHash := self.hash() + remote := r.Clone() + for index, current := range self.nodes { + if current.Addr == remote.Addr { + if bytes.Compare(current.Pos, remote.Pos) == 0 { + return + } + self.nodes = append(self.nodes[:index], self.nodes[index+1:]...) + } + } + i := sort.Search(len(self.nodes), func(i int) bool { + return remote.Less(self.nodes[i]) + }) + if i < len(self.nodes) { + self.nodes = append(self.nodes[:i], append(Remotes{remote}, self.nodes[i:]...)...) + } else { + self.nodes = append(self.nodes, remote) + } + self.sendChanges(oldHash) } // Redundancy returns the minimum of the number of nodes present and the Redundancy const. func (self *Ring) Redundancy() int { - self.lock.RLock() - defer self.lock.RUnlock() - if len(self.nodes) < Redundancy { - return len(self.nodes) - } - return Redundancy + self.lock.RLock() + defer self.lock.RUnlock() + if len(self.nodes) < Redundancy { + return len(self.nodes) + } + return Redundancy } // Remotes returns the predecessor of pos, any Remote at pos and the successor of pos. func (self *Ring) Remotes(pos []byte) (before, at, after *Remote) { - self.lock.RLock() - defer self.lock.RUnlock() - beforeIndex, atIndex, afterIndex := self.byteIndices(pos) - if beforeIndex != -1 { - tmp := self.nodes[beforeIndex].Clone() - before = &tmp - } - if atIndex != -1 { - tmp := self.nodes[atIndex].Clone() - at = &tmp - } - if afterIndex != -1 { - tmp := self.nodes[afterIndex].Clone() - after = &tmp - } - return + self.lock.RLock() + defer self.lock.RUnlock() + beforeIndex, atIndex, afterIndex := self.byteIndices(pos) + if beforeIndex != -1 { + tmp := self.nodes[beforeIndex].Clone() + before = &tmp + } + if atIndex != -1 { + tmp := self.nodes[atIndex].Clone() + at = &tmp + } + if afterIndex != -1 { + tmp := self.nodes[afterIndex].Clone() + after = &tmp + } + return } /* @@ -217,49 +223,49 @@ byteIndices searches the Ring for a position, and returns the last index before the index where the positon can be found (or -1) and the first index after the position. */ func (self *Ring) byteIndices(pos []byte) (before, at, after int) { - if len(self.nodes) == 0 { - return -1, -1, -1 - } - // Find the first position in self.nodes where the position - // is greather than or equal to the searched for position. - i := sort.Search(len(self.nodes), func(i int) bool { - return bytes.Compare(pos, self.nodes[i].Pos) < 1 - }) - // If we didn't find any position like that - if i == len(self.nodes) { - after = 0 - before = len(self.nodes) - 1 - at = -1 - return - } - // If we did, then we know that the position before (or the last position) - // is the one that is before the searched for position. - if i == 0 { - before = len(self.nodes) - 1 - } else { - before = i - 1 - } - // If we found a position that is equal to the searched for position - // just keep searching for a position that is guaranteed to be greater - // than the searched for position. - // If we did not find a position that is equal, then we know that the found - // position is greater than. - if bytes.Compare(pos, self.nodes[i].Pos) == 0 { - at = i - j := sort.Search(len(self.nodes)-i, func(k int) bool { - return bytes.Compare(pos, self.nodes[k+i].Pos) < 0 - }) - j += i - if j < len(self.nodes) { - after = j - } else { - after = 0 - } - } else { - at = -1 - after = i - } - return + if len(self.nodes) == 0 { + return -1, -1, -1 + } + // Find the first position in self.nodes where the position + // is greather than or equal to the searched for position. + i := sort.Search(len(self.nodes), func(i int) bool { + return bytes.Compare(pos, self.nodes[i].Pos) < 1 + }) + // If we didn't find any position like that + if i == len(self.nodes) { + after = 0 + before = len(self.nodes) - 1 + at = -1 + return + } + // If we did, then we know that the position before (or the last position) + // is the one that is before the searched for position. + if i == 0 { + before = len(self.nodes) - 1 + } else { + before = i - 1 + } + // If we found a position that is equal to the searched for position + // just keep searching for a position that is guaranteed to be greater + // than the searched for position. + // If we did not find a position that is equal, then we know that the found + // position is greater than. + if bytes.Compare(pos, self.nodes[i].Pos) == 0 { + at = i + j := sort.Search(len(self.nodes)-i, func(k int) bool { + return bytes.Compare(pos, self.nodes[k+i].Pos) < 0 + }) + j += i + if j < len(self.nodes) { + after = j + } else { + after = 0 + } + } else { + at = -1 + after = i + } + return } /* @@ -267,106 +273,106 @@ indices searches the Ring for a Remote, and returns the last index before the po the index where the positon can be found (or -1) and the first index after the position. */ func (self *Ring) indices(pos Remote) (before, at, after int) { - if len(self.nodes) == 0 { - return -1, -1, -1 - } - // Find the first position in self.nodes where the position - // is greather than or equal to the searched for position. - i := sort.Search(len(self.nodes), func(i int) bool { - return !self.nodes[i].Less(pos) - }) - // If we didn't find any position like that - if i == len(self.nodes) { - after = 0 - before = len(self.nodes) - 1 - at = -1 - return - } - // If we did, then we know that the position before (or the last position) - // is the one that is before the searched for position. - if i == 0 { - before = len(self.nodes) - 1 - } else { - before = i - 1 - } - // If we found a position that is equal to the searched for position - // just keep searching for a position that is guaranteed to be greater - // than the searched for position. - // If we did not find a position that is equal, then we know that the found - // position is greater than. - if pos.Equal(self.nodes[i]) { - at = i - j := sort.Search(len(self.nodes)-i, func(k int) bool { - return pos.Less(self.nodes[k+i]) - }) - j += i - if j < len(self.nodes) { - after = j - } else { - after = 0 - } - } else { - at = -1 - after = i - } - return + if len(self.nodes) == 0 { + return -1, -1, -1 + } + // Find the first position in self.nodes where the position + // is greather than or equal to the searched for position. + i := sort.Search(len(self.nodes), func(i int) bool { + return !self.nodes[i].Less(pos) + }) + // If we didn't find any position like that + if i == len(self.nodes) { + after = 0 + before = len(self.nodes) - 1 + at = -1 + return + } + // If we did, then we know that the position before (or the last position) + // is the one that is before the searched for position. + if i == 0 { + before = len(self.nodes) - 1 + } else { + before = i - 1 + } + // If we found a position that is equal to the searched for position + // just keep searching for a position that is guaranteed to be greater + // than the searched for position. + // If we did not find a position that is equal, then we know that the found + // position is greater than. + if pos.Equal(self.nodes[i]) { + at = i + j := sort.Search(len(self.nodes)-i, func(k int) bool { + return pos.Less(self.nodes[k+i]) + }) + j += i + if j < len(self.nodes) { + after = j + } else { + after = 0 + } + } else { + at = -1 + after = i + } + return } // GetSlot returns the biggest free spot in this Ring, assuming a maximum size 2 ^ (murmur.Size * 8). func (self *Ring) GetSlot() []byte { - self.lock.RLock() - defer self.lock.RUnlock() - biggestSpace := new(big.Int) - biggestSpaceIndex := 0 - for i := 0; i < len(self.nodes); i++ { - this := new(big.Int).SetBytes(self.nodes[i].Pos) - var next *big.Int - if i+1 < len(self.nodes) { - next = new(big.Int).SetBytes(self.nodes[i+1].Pos) - } else { - max := make([]byte, murmur.Size+1) - max[0] = 1 - next = new(big.Int).Add(new(big.Int).SetBytes(max), new(big.Int).SetBytes(self.nodes[0].Pos)) - } - thisSpace := new(big.Int).Sub(next, this) - if biggestSpace.Cmp(thisSpace) < 0 { - biggestSpace = thisSpace - biggestSpaceIndex = i - } - } - return new(big.Int).Add(new(big.Int).SetBytes(self.nodes[biggestSpaceIndex].Pos), new(big.Int).Div(biggestSpace, big.NewInt(2))).Bytes() + self.lock.RLock() + defer self.lock.RUnlock() + biggestSpace := new(big.Int) + biggestSpaceIndex := 0 + for i := 0; i < len(self.nodes); i++ { + this := new(big.Int).SetBytes(self.nodes[i].Pos) + var next *big.Int + if i+1 < len(self.nodes) { + next = new(big.Int).SetBytes(self.nodes[i+1].Pos) + } else { + max := make([]byte, murmur.Size+1) + max[0] = 1 + next = new(big.Int).Add(new(big.Int).SetBytes(max), new(big.Int).SetBytes(self.nodes[0].Pos)) + } + thisSpace := new(big.Int).Sub(next, this) + if biggestSpace.Cmp(thisSpace) < 0 { + biggestSpace = thisSpace + biggestSpaceIndex = i + } + } + return new(big.Int).Add(new(big.Int).SetBytes(self.nodes[biggestSpaceIndex].Pos), new(big.Int).Div(biggestSpace, big.NewInt(2))).Bytes() } // Remove deletes any Nodes in this Ring with the same address as remote. func (self *Ring) Remove(remote Remote) { - self.lock.Lock() - defer self.lock.Unlock() - oldHash := self.hash() - for index, current := range self.nodes { - if current.Addr == remote.Addr { - if len(self.nodes) == 1 { - panic("Why would you want to remove the last Node in the Ring? Inconceivable!") - } - self.nodes = append(self.nodes[:index], self.nodes[index+1:]...) - } - } - self.sendChanges(oldHash) + self.lock.Lock() + defer self.lock.Unlock() + oldHash := self.hash() + for index, current := range self.nodes { + if current.Addr == remote.Addr { + if len(self.nodes) == 1 { + panic("Why would you want to remove the last Node in the Ring? Inconceivable!") + } + self.nodes = append(self.nodes[:index], self.nodes[index+1:]...) + } + } + self.sendChanges(oldHash) } // Clean removes any Nodes in this Ring between predecessor and successor (exclusive). func (self *Ring) Clean(predecessor, successor Remote) { - self.lock.Lock() - defer self.lock.Unlock() - oldHash := self.hash() - _, _, from := self.indices(predecessor) - to, at, _ := self.indices(successor) - if at != -1 { - to = at - } - if from > to { - self.nodes = self.nodes[to:from] - } else { - self.nodes = append(self.nodes[:from], self.nodes[to:]...) - } - self.sendChanges(oldHash) + self.lock.Lock() + defer self.lock.Unlock() + oldHash := self.hash() + _, _, from := self.indices(predecessor) + to, at, _ := self.indices(successor) + if at != -1 { + to = at + } + if from > to { + self.nodes = self.nodes[to:from] + } else { + self.nodes = append(self.nodes[:from], self.nodes[to:]...) + } + self.sendChanges(oldHash) } diff --git a/common/switchboard.go b/common/switchboard.go index 4028b6e..f9e205a 100644 --- a/common/switchboard.go +++ b/common/switchboard.go @@ -61,3 +61,12 @@ func (self *Switchboard) Call(addr, service string, args, reply interface{}) (er } return } + +func (self *Switchboard) Close(addr string) error { + client, err := self.client(addr) + if err != nil { + return err + } + + return client.Close() +} \ No newline at end of file diff --git a/common/time_lock.go b/common/time_lock.go index d819a77..eb5469e 100644 --- a/common/time_lock.go +++ b/common/time_lock.go @@ -1,61 +1,61 @@ package common import ( - "sync" - "sync/atomic" - "time" + "sync" + "sync/atomic" + "time" ) const ( - logsize = 16 + logsize = 16 ) type TimeLock struct { - lock *sync.RWMutex - lockdurations [logsize]int64 - locktimes [logsize]int64 - index int + lockdurations [logsize]int64 + locktimes [logsize]int64 + lock *sync.RWMutex + index int } func NewTimeLock() *TimeLock { - return &TimeLock{ - lock: new(sync.RWMutex), - } + return &TimeLock{ + lock: new(sync.RWMutex), + } } func (self *TimeLock) Lock() { - self.lock.Lock() - atomic.StoreInt64(&self.locktimes[self.index], time.Now().UnixNano()) - atomic.StoreInt64(&self.lockdurations[self.index], -self.locktimes[self.index]) + self.lock.Lock() + atomic.StoreInt64(&self.locktimes[self.index], time.Now().UnixNano()) + atomic.StoreInt64(&self.lockdurations[self.index], -self.locktimes[self.index]) } func (self *TimeLock) Unlock() { - atomic.AddInt64(&self.lockdurations[self.index], time.Now().UnixNano()) - self.index = (self.index + 1) % logsize - self.lock.Unlock() + atomic.AddInt64(&self.lockdurations[self.index], time.Now().UnixNano()) + self.index = (self.index + 1) % logsize + self.lock.Unlock() } func (self *TimeLock) RLock() { - self.lock.RLock() + self.lock.RLock() } func (self *TimeLock) RUnlock() { - self.lock.RUnlock() + self.lock.RUnlock() } func (self *TimeLock) Load() float64 { - var sum int64 - var first int64 - var tmp int64 - for i := 0; i < logsize; i++ { - tmp = atomic.LoadInt64(&self.lockdurations[i]) - if tmp > 0 { - sum += tmp - } - tmp = atomic.LoadInt64(&self.locktimes[i]) - if first == 0 || tmp < first { - first = tmp - } - } - return float64(sum) / float64(time.Now().UnixNano()-first) + var sum int64 + var first int64 + var tmp int64 + for i := 0; i < logsize; i++ { + tmp = atomic.LoadInt64(&self.lockdurations[i]) + if tmp > 0 { + sum += tmp + } + tmp = atomic.LoadInt64(&self.locktimes[i]) + if first == 0 || tmp < first { + first = tmp + } + } + return float64(sum) / float64(time.Now().UnixNano()-first) } diff --git a/dhash/api_functions.go b/dhash/api_functions.go index 11f39d7..6d08365 100644 --- a/dhash/api_functions.go +++ b/dhash/api_functions.go @@ -1,492 +1,494 @@ package dhash import ( - "bytes" - "fmt" - "github.com/zond/god/client" - "github.com/zond/god/common" - "github.com/zond/god/setop" - "sync/atomic" - "time" + "bytes" + "fmt" + "sync/atomic" + "time" + + "github.com/zond/god/client" + "github.com/zond/god/common" + "github.com/zond/setop" ) // Description will return a current description of the node. func (self *Node) Description() common.DHashDescription { - return common.DHashDescription{ - Addr: self.GetAddr(), - Pos: self.node.GetPosition(), - LastReroute: time.Unix(0, atomic.LoadInt64(&self.lastReroute)), - LastSync: time.Unix(0, atomic.LoadInt64(&self.lastSync)), - LastMigrate: time.Unix(0, atomic.LoadInt64(&self.lastMigrate)), - Timer: self.timer.ActualTime(), - OwnedEntries: self.Owned(), - HeldEntries: self.tree.RealSize(), - Load: self.tree.Load(), - Nodes: self.node.GetNodes(), - } + return common.DHashDescription{ + Addr: self.GetBroadcastAddr(), + Pos: self.node.GetPosition(), + LastReroute: time.Unix(0, atomic.LoadInt64(&self.lastReroute)), + LastSync: time.Unix(0, atomic.LoadInt64(&self.lastSync)), + LastMigrate: time.Unix(0, atomic.LoadInt64(&self.lastMigrate)), + Timer: self.timer.ActualTime(), + OwnedEntries: self.Owned(), + HeldEntries: self.tree.RealSize(), + Load: self.tree.Load(), + Nodes: self.node.GetNodes(), + } } // Describe will return a humanly readable string describing the node. func (self *Node) Describe() string { - return self.Description().Describe() + return self.Description().Describe() } // DescribeTree will return a humanly readable string describing the node contents. func (self *Node) DescribeTree() string { - return self.tree.Describe() + return self.tree.Describe() } func (self *Node) client() *client.Conn { - return client.NewConnRing(common.NewRingNodes(self.node.Nodes())) + return client.NewConnRing(common.NewRingNodes(self.node.Nodes())) } func (self *Node) Get(data common.Item, result *common.Item) error { - *result = data - result.Value, result.Timestamp, result.Exists = self.tree.Get(data.Key) - return nil + *result = data + result.Value, result.Timestamp, result.Exists = self.tree.Get(data.Key) + return nil } func (self *Node) Prev(data common.Item, result *common.Item) error { - *result = data - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.Prev(data.Key) - return nil + *result = data + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.Prev(data.Key) + return nil } func (self *Node) Next(data common.Item, result *common.Item) error { - *result = data - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.Next(data.Key) - return nil + *result = data + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.Next(data.Key) + return nil } func (self *Node) RingHash(x int, ringHash *[]byte) error { - *ringHash = self.node.RingHash() - return nil + *ringHash = self.node.RingHash() + return nil } func (self *Node) MirrorCount(r common.Range, result *int) error { - *result = self.tree.SubMirrorSizeBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc) - return nil + *result = self.tree.SubMirrorSizeBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc) + return nil } func (self *Node) Count(r common.Range, result *int) error { - *result = self.tree.SubSizeBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc) - return nil + *result = self.tree.SubSizeBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc) + return nil } func (self *Node) MirrorLast(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubMirrorLast(data.Key) - return nil + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubMirrorLast(data.Key) + return nil } func (self *Node) MirrorFirst(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubMirrorFirst(data.Key) - return nil + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubMirrorFirst(data.Key) + return nil } func (self *Node) Last(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubLast(data.Key) - return nil + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubLast(data.Key) + return nil } func (self *Node) First(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubFirst(data.Key) - return nil + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubFirst(data.Key) + return nil } func (self *Node) MirrorPrevIndex(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Index, result.Exists = self.tree.SubMirrorPrevIndex(data.Key, data.Index) - return nil + result.Key, result.Value, result.Timestamp, result.Index, result.Exists = self.tree.SubMirrorPrevIndex(data.Key, data.Index) + return nil } func (self *Node) MirrorNextIndex(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Index, result.Exists = self.tree.SubMirrorNextIndex(data.Key, data.Index) - return nil + result.Key, result.Value, result.Timestamp, result.Index, result.Exists = self.tree.SubMirrorNextIndex(data.Key, data.Index) + return nil } func (self *Node) PrevIndex(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Index, result.Exists = self.tree.SubPrevIndex(data.Key, data.Index) - return nil + result.Key, result.Value, result.Timestamp, result.Index, result.Exists = self.tree.SubPrevIndex(data.Key, data.Index) + return nil } func (self *Node) NextIndex(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Index, result.Exists = self.tree.SubNextIndex(data.Key, data.Index) - return nil + result.Key, result.Value, result.Timestamp, result.Index, result.Exists = self.tree.SubNextIndex(data.Key, data.Index) + return nil } func (self *Node) SubMirrorPrev(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubMirrorPrev(data.Key, data.SubKey) - return nil + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubMirrorPrev(data.Key, data.SubKey) + return nil } func (self *Node) SubMirrorNext(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubMirrorNext(data.Key, data.SubKey) - return nil + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubMirrorNext(data.Key, data.SubKey) + return nil } func (self *Node) SubPrev(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubPrev(data.Key, data.SubKey) - return nil + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubPrev(data.Key, data.SubKey) + return nil } func (self *Node) SubNext(data common.Item, result *common.Item) error { - result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubNext(data.Key, data.SubKey) - return nil + result.Key, result.Value, result.Timestamp, result.Exists = self.tree.SubNext(data.Key, data.SubKey) + return nil } func (self *Node) SliceIndex(r common.Range, items *[]common.Item) error { - min := &r.MinIndex - max := &r.MaxIndex - if !r.MinInc { - min = nil - } - if !r.MaxInc { - max = nil - } - self.tree.SubEachBetweenIndex(r.Key, min, max, func(key []byte, value []byte, version int64, index int) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - Index: index, - }) - return true - }) - return nil + min := &r.MinIndex + max := &r.MaxIndex + if !r.MinInc { + min = nil + } + if !r.MaxInc { + max = nil + } + self.tree.SubEachBetweenIndex(r.Key, min, max, func(key []byte, value []byte, version int64, index int) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + Index: index, + }) + return true + }) + return nil } func (self *Node) ReverseSliceIndex(r common.Range, items *[]common.Item) error { - min := &r.MinIndex - max := &r.MaxIndex - if !r.MinInc { - min = nil - } - if !r.MaxInc { - max = nil - } - self.tree.SubReverseEachBetweenIndex(r.Key, min, max, func(key []byte, value []byte, version int64, index int) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - Index: index, - }) - return true - }) - return nil + min := &r.MinIndex + max := &r.MaxIndex + if !r.MinInc { + min = nil + } + if !r.MaxInc { + max = nil + } + self.tree.SubReverseEachBetweenIndex(r.Key, min, max, func(key []byte, value []byte, version int64, index int) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + Index: index, + }) + return true + }) + return nil } func (self *Node) ReverseSlice(r common.Range, items *[]common.Item) error { - self.tree.SubReverseEachBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc, func(key []byte, value []byte, version int64) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - }) - return true - }) - return nil + self.tree.SubReverseEachBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc, func(key []byte, value []byte, version int64) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + }) + return true + }) + return nil } func (self *Node) Slice(r common.Range, items *[]common.Item) error { - self.tree.SubEachBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc, func(key []byte, value []byte, version int64) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - }) - return true - }) - return nil + self.tree.SubEachBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc, func(key []byte, value []byte, version int64) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + }) + return true + }) + return nil } func (self *Node) SliceLen(r common.Range, items *[]common.Item) error { - self.tree.SubEachBetween(r.Key, r.Min, nil, r.MinInc, false, func(key []byte, value []byte, version int64) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - }) - return len(*items) < r.Len - }) - return nil + self.tree.SubEachBetween(r.Key, r.Min, nil, r.MinInc, false, func(key []byte, value []byte, version int64) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + }) + return len(*items) < r.Len + }) + return nil } func (self *Node) ReverseSliceLen(r common.Range, items *[]common.Item) error { - self.tree.SubReverseEachBetween(r.Key, nil, r.Max, false, r.MaxInc, func(key []byte, value []byte, version int64) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - }) - return len(*items) < r.Len - }) - return nil + self.tree.SubReverseEachBetween(r.Key, nil, r.Max, false, r.MaxInc, func(key []byte, value []byte, version int64) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + }) + return len(*items) < r.Len + }) + return nil } func (self *Node) MirrorSliceIndex(r common.Range, items *[]common.Item) error { - min := &r.MinIndex - max := &r.MaxIndex - if !r.MinInc { - min = nil - } - if !r.MaxInc { - max = nil - } - self.tree.SubMirrorEachBetweenIndex(r.Key, min, max, func(key []byte, value []byte, version int64, index int) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - Index: index, - }) - return true - }) - return nil + min := &r.MinIndex + max := &r.MaxIndex + if !r.MinInc { + min = nil + } + if !r.MaxInc { + max = nil + } + self.tree.SubMirrorEachBetweenIndex(r.Key, min, max, func(key []byte, value []byte, version int64, index int) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + Index: index, + }) + return true + }) + return nil } func (self *Node) MirrorReverseSliceIndex(r common.Range, items *[]common.Item) error { - min := &r.MinIndex - max := &r.MaxIndex - if !r.MinInc { - min = nil - } - if !r.MaxInc { - max = nil - } - self.tree.SubMirrorReverseEachBetweenIndex(r.Key, min, max, func(key []byte, value []byte, version int64, index int) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - Index: index, - }) - return true - }) - return nil + min := &r.MinIndex + max := &r.MaxIndex + if !r.MinInc { + min = nil + } + if !r.MaxInc { + max = nil + } + self.tree.SubMirrorReverseEachBetweenIndex(r.Key, min, max, func(key []byte, value []byte, version int64, index int) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + Index: index, + }) + return true + }) + return nil } func (self *Node) MirrorReverseSlice(r common.Range, items *[]common.Item) error { - self.tree.SubMirrorReverseEachBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc, func(key []byte, value []byte, version int64) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - }) - return true - }) - return nil + self.tree.SubMirrorReverseEachBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc, func(key []byte, value []byte, version int64) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + }) + return true + }) + return nil } func (self *Node) MirrorSlice(r common.Range, items *[]common.Item) error { - self.tree.SubMirrorEachBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc, func(key []byte, value []byte, version int64) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - }) - return true - }) - return nil + self.tree.SubMirrorEachBetween(r.Key, r.Min, r.Max, r.MinInc, r.MaxInc, func(key []byte, value []byte, version int64) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + }) + return true + }) + return nil } func (self *Node) MirrorSliceLen(r common.Range, items *[]common.Item) error { - self.tree.SubMirrorEachBetween(r.Key, r.Min, nil, r.MinInc, false, func(key []byte, value []byte, version int64) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - }) - return len(*items) < r.Len - }) - return nil + self.tree.SubMirrorEachBetween(r.Key, r.Min, nil, r.MinInc, false, func(key []byte, value []byte, version int64) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + }) + return len(*items) < r.Len + }) + return nil } func (self *Node) MirrorReverseSliceLen(r common.Range, items *[]common.Item) error { - self.tree.SubMirrorReverseEachBetween(r.Key, nil, r.Max, false, r.MaxInc, func(key []byte, value []byte, version int64) bool { - *items = append(*items, common.Item{ - Key: key, - Value: value, - Timestamp: version, - }) - return len(*items) < r.Len - }) - return nil + self.tree.SubMirrorReverseEachBetween(r.Key, nil, r.Max, false, r.MaxInc, func(key []byte, value []byte, version int64) bool { + *items = append(*items, common.Item{ + Key: key, + Value: value, + Timestamp: version, + }) + return len(*items) < r.Len + }) + return nil } func (self *Node) MirrorReverseIndexOf(data common.Item, result *common.Index) error { - result.N, result.Existed = self.tree.SubMirrorReverseIndexOf(data.Key, data.SubKey) - return nil + result.N, result.Existed = self.tree.SubMirrorReverseIndexOf(data.Key, data.SubKey) + return nil } func (self *Node) MirrorIndexOf(data common.Item, result *common.Index) error { - result.N, result.Existed = self.tree.SubMirrorIndexOf(data.Key, data.SubKey) - return nil + result.N, result.Existed = self.tree.SubMirrorIndexOf(data.Key, data.SubKey) + return nil } func (self *Node) ReverseIndexOf(data common.Item, result *common.Index) error { - result.N, result.Existed = self.tree.SubReverseIndexOf(data.Key, data.SubKey) - return nil + result.N, result.Existed = self.tree.SubReverseIndexOf(data.Key, data.SubKey) + return nil } func (self *Node) IndexOf(data common.Item, result *common.Index) error { - result.N, result.Existed = self.tree.SubIndexOf(data.Key, data.SubKey) - return nil + result.N, result.Existed = self.tree.SubIndexOf(data.Key, data.SubKey) + return nil } func (self *Node) SubGet(data common.Item, result *common.Item) error { - *result = data - result.Value, result.Timestamp, result.Exists = self.tree.SubGet(data.Key, data.SubKey) - return nil + *result = data + result.Value, result.Timestamp, result.Exists = self.tree.SubGet(data.Key, data.SubKey) + return nil } func (self *Node) SubClear(data common.Item) error { - data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() - return self.subClear(data) + data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() + return self.subClear(data) } func (self *Node) SubDel(data common.Item) error { - data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() - return self.subDel(data) + data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() + return self.subDel(data) } func (self *Node) SubPut(data common.Item) error { - data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() - return self.subPut(data) + data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() + return self.subPut(data) } func (self *Node) Del(data common.Item) error { - data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() - return self.del(data) + data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() + return self.del(data) } func (self *Node) Put(data common.Item) error { - data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() - return self.put(data) + data.TTL, data.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() + return self.put(data) } func (self *Node) forwardOperation(data common.Item, operation string) { - data.TTL-- - successor := self.node.GetSuccessor() - var x int - if self.hasCommListeners() { - self.triggerCommListeners(Comm{ - Key: data.Key, - SubKey: data.SubKey, - Source: self.node.Remote(), - Destination: successor, - Type: operation, - }) - } - err := successor.Call(operation, data, &x) - for err != nil { - self.node.RemoveNode(successor) - successor = self.node.GetSuccessor() - err = successor.Call(operation, data, &x) - } + data.TTL-- + successor := self.node.GetSuccessor() + var x int + if self.hasCommListeners() { + self.triggerCommListeners(Comm{ + Key: data.Key, + SubKey: data.SubKey, + Source: self.node.Remote(), + Destination: successor, + Type: operation, + }) + } + err := successor.Call(operation, data, &x) + for err != nil { + self.node.RemoveNode(successor) + successor = self.node.GetSuccessor() + err = successor.Call(operation, data, &x) + } } func (self *Node) Clear() { - self.tree.Clear(self.timer.ContinuousTime()) + self.tree.Clear(self.timer.ContinuousTime()) } func (self *Node) subClear(data common.Item) error { - if data.TTL > 1 { - if data.Sync { - self.forwardOperation(data, "DHash.SlaveSubClear") - } else { - go self.forwardOperation(data, "DHash.SlaveSubClear") - } - } - self.tree.SubClear(data.Key, data.Timestamp) - return nil + if data.TTL > 1 { + if data.Sync { + self.forwardOperation(data, "DHash.SlaveSubClear") + } else { + go self.forwardOperation(data, "DHash.SlaveSubClear") + } + } + self.tree.SubClear(data.Key, data.Timestamp) + return nil } func (self *Node) subDel(data common.Item) error { - if data.TTL > 1 { - if data.Sync { - self.forwardOperation(data, "DHash.SlaveSubDel") - } else { - go self.forwardOperation(data, "DHash.SlaveSubDel") - } - } - self.tree.SubFakeDel(data.Key, data.SubKey, data.Timestamp) - return nil + if data.TTL > 1 { + if data.Sync { + self.forwardOperation(data, "DHash.SlaveSubDel") + } else { + go self.forwardOperation(data, "DHash.SlaveSubDel") + } + } + self.tree.SubFakeDel(data.Key, data.SubKey, data.Timestamp) + return nil } func (self *Node) subPut(data common.Item) error { - if data.TTL > 1 { - if data.Sync { - self.forwardOperation(data, "DHash.SlaveSubPut") - } else { - go self.forwardOperation(data, "DHash.SlaveSubPut") - } - } - self.tree.SubPut(data.Key, data.SubKey, data.Value, data.Timestamp) - return nil + if data.TTL > 1 { + if data.Sync { + self.forwardOperation(data, "DHash.SlaveSubPut") + } else { + go self.forwardOperation(data, "DHash.SlaveSubPut") + } + } + self.tree.SubPut(data.Key, data.SubKey, data.Value, data.Timestamp) + return nil } func (self *Node) del(data common.Item) error { - if data.TTL > 1 { - if data.Sync { - self.forwardOperation(data, "DHash.SlaveDel") - } else { - go self.forwardOperation(data, "DHash.SlaveDel") - } - } - self.tree.FakeDel(data.Key, data.Timestamp) - return nil + if data.TTL > 1 { + if data.Sync { + self.forwardOperation(data, "DHash.SlaveDel") + } else { + go self.forwardOperation(data, "DHash.SlaveDel") + } + } + self.tree.FakeDel(data.Key, data.Timestamp) + return nil } func (self *Node) put(data common.Item) error { - if data.TTL > 1 { - if data.Sync { - self.forwardOperation(data, "DHash.SlavePut") - } else { - go self.forwardOperation(data, "DHash.SlavePut") - } - } - self.tree.Put(data.Key, data.Value, data.Timestamp) - return nil + if data.TTL > 1 { + if data.Sync { + self.forwardOperation(data, "DHash.SlavePut") + } else { + go self.forwardOperation(data, "DHash.SlavePut") + } + } + self.tree.Put(data.Key, data.Value, data.Timestamp) + return nil } func (self *Node) Size() int { - pred := self.node.GetPredecessor() - me := self.node.Remote() - cmp := bytes.Compare(pred.Pos, me.Pos) - if cmp < 0 { - return self.tree.SizeBetween(pred.Pos, me.Pos, true, false) - } else if cmp > 0 { - return self.tree.SizeBetween(pred.Pos, nil, true, false) + self.tree.SizeBetween(nil, me.Pos, true, false) - } - if pred.Less(me) { - return 0 - } - return self.tree.Size() + pred := self.node.GetPredecessor() + me := self.node.Remote() + cmp := bytes.Compare(pred.Pos, me.Pos) + if cmp < 0 { + return self.tree.SizeBetween(pred.Pos, me.Pos, true, false) + } else if cmp > 0 { + return self.tree.SizeBetween(pred.Pos, nil, true, false) + self.tree.SizeBetween(nil, me.Pos, true, false) + } + if pred.Less(me) { + return 0 + } + return self.tree.Size() } func (self *Node) SubSize(key []byte, result *int) error { - *result = self.tree.SubSize(key) - return nil + *result = self.tree.SubSize(key) + return nil } func (self *Node) SetExpression(expr setop.SetExpression, items *[]setop.SetOpResult) (err error) { - if expr.Dest != nil { - if expr.Op.Merge == setop.Append { - err = fmt.Errorf("When storing results of Set expressions the Append merge function is not allowed") - return - } - successor := self.node.GetSuccessorFor(expr.Dest) - if successor.Addr != self.node.GetAddr() { - return successor.Call("DHash.SetExpression", expr, items) - } - } - data := common.Item{ - Key: expr.Dest, - } - err = expr.Each(func(b []byte) setop.Skipper { - succ := self.node.GetSuccessorFor(b) - result := &treeSkipper{ - remote: succ, - key: b, - } - if succ.Addr == self.node.GetAddr() { - result.tree = self.tree - } - return result - }, func(res *setop.SetOpResult) { - if expr.Dest == nil { - *items = append(*items, *res) - } else { - data.SubKey = res.Key - data.Value = res.Values[0] - data.TTL = self.node.Redundancy() - data.Timestamp = self.timer.ContinuousTime() - self.subPut(data) - } - }) - return + if expr.Dest != nil { + if expr.Op.Merge == setop.Append { + err = fmt.Errorf("When storing results of Set expressions the Append merge function is not allowed") + return + } + successor := self.node.GetSuccessorFor(expr.Dest) + if successor.Addr != self.node.GetBroadcastAddr() { + return successor.Call("DHash.SetExpression", expr, items) + } + } + data := common.Item{ + Key: expr.Dest, + } + err = expr.Each(func(b []byte) (result setop.Skipper, err error) { + succ := self.node.GetSuccessorFor(b) + res := &treeSkipper{ + remote: succ, + key: b, + } + if succ.Addr == self.node.GetBroadcastAddr() { + res.tree = self.tree + } + result = res + return + }, func(res *setop.SetOpResult) { + if expr.Dest == nil { + *items = append(*items, *res) + } else { + data.SubKey = res.Key + data.Value = res.Values[0] + data.TTL = self.node.Redundancy() + data.Timestamp = self.timer.ContinuousTime() + self.subPut(data) + } + }) + return } func (self *Node) AddConfiguration(c common.ConfItem) { - self.tree.AddConfiguration(self.timer.ContinuousTime(), c.Key, c.Value) + self.tree.AddConfiguration(self.timer.ContinuousTime(), c.Key, c.Value) } func (self *Node) forwardConfiguration(c common.ConfItem, operation string) { - c.TTL-- - successor := self.node.GetSuccessor() - var x int - err := successor.Call(operation, c, &x) - for err != nil { - self.node.RemoveNode(successor) - successor = self.node.GetSuccessor() - err = successor.Call(operation, c, &x) - } + c.TTL-- + successor := self.node.GetSuccessor() + var x int + err := successor.Call(operation, c, &x) + for err != nil { + self.node.RemoveNode(successor) + successor = self.node.GetSuccessor() + err = successor.Call(operation, c, &x) + } } func (self *Node) subAddConfiguration(c common.ConfItem) { - if self.tree.SubAddConfiguration(c.TreeKey, c.Timestamp, c.Key, c.Value) { - if c.TTL > 1 { - self.forwardConfiguration(c, "DHash.SlaveSubAddConfiguration") - } - } + if self.tree.SubAddConfiguration(c.TreeKey, c.Timestamp, c.Key, c.Value) { + if c.TTL > 1 { + self.forwardConfiguration(c, "DHash.SlaveSubAddConfiguration") + } + } } func (self *Node) SubAddConfiguration(c common.ConfItem) { - c.TTL, c.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() - self.subAddConfiguration(c) + c.TTL, c.Timestamp = self.node.Redundancy(), self.timer.ContinuousTime() + self.subAddConfiguration(c) } func (self *Node) Configuration(x int, result *common.Conf) error { - *result = common.Conf{} - (*result).Data, (*result).Timestamp = self.tree.Configuration() - return nil + *result = common.Conf{} + (*result).Data, (*result).Timestamp = self.tree.Configuration() + return nil } func (self *Node) SubConfiguration(key []byte, result *common.Conf) error { - *result = common.Conf{TreeKey: key} - (*result).Data, (*result).Timestamp = self.tree.SubConfiguration(key) - return nil + *result = common.Conf{TreeKey: key} + (*result).Data, (*result).Timestamp = self.tree.SubConfiguration(key) + return nil } diff --git a/dhash/client_test.go b/dhash/client_test.go index 6878d74..001035c 100644 --- a/dhash/client_test.go +++ b/dhash/client_test.go @@ -1,662 +1,679 @@ package dhash import ( - "bytes" - "fmt" - "github.com/zond/god/client" - "github.com/zond/god/common" - "github.com/zond/god/murmur" - "github.com/zond/god/setop" - "math/big" - "net" - "runtime" - "testing" - "time" + "bytes" + "fmt" + "math/big" + "net" + "runtime" + "testing" + "time" + + "github.com/zond/god/client" + "github.com/zond/god/common" + "github.com/zond/god/murmur" + "github.com/zond/setop" ) type testClient interface { - SSubPut(key, subKey, value []byte) - SubPut(key, subKey, value []byte) - SPut(key, value []byte) - Put(key, value []byte) - SubClear(key []byte) - SSubClear(key []byte) - SubDel(key, subKey []byte) - SSubDel(key, subKey []byte) - SDel(key []byte) - Del(key []byte) - MirrorReverseIndexOf(key, subKey []byte) (index int, existed bool) - MirrorIndexOf(key, subKey []byte) (index int, existed bool) - ReverseIndexOf(key, subKey []byte) (index int, existed bool) - IndexOf(key, subKey []byte) (index int, existed bool) - Next(key []byte) (nextKey, nextValue []byte, existed bool) - Prev(key []byte) (prevKey, prevValue []byte, existed bool) - MirrorCount(key, min, max []byte, mininc, maxinc bool) (result int) - Count(key, min, max []byte, mininc, maxinc bool) (result int) - MirrorNextIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) - MirrorPrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) - NextIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) - PrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) - MirrorReverseSliceIndex(key []byte, min, max *int) (result []common.Item) - MirrorSliceIndex(key []byte, min, max *int) (result []common.Item) - MirrorReverseSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) - MirrorSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) - MirrorSliceLen(key, min []byte, mininc bool, maxRes int) (result []common.Item) - MirrorReverseSliceLen(key, max []byte, maxinc bool, maxRes int) (result []common.Item) - ReverseSliceIndex(key []byte, min, max *int) (result []common.Item) - SliceIndex(key []byte, min, max *int) (result []common.Item) - ReverseSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) - Slice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) - SliceLen(key, min []byte, mininc bool, maxRes int) (result []common.Item) - ReverseSliceLen(key, max []byte, maxinc bool, maxRes int) (result []common.Item) - SubMirrorPrev(key, subKey []byte) (prevKey, prevValue []byte, existed bool) - SubMirrorNext(key, subKey []byte) (nextKey, nextValue []byte, existed bool) - SubPrev(key, subKey []byte) (prevKey, prevValue []byte, existed bool) - SubNext(key, subKey []byte) (nextKey, nextValue []byte, existed bool) - MirrorLast(key []byte) (lastKey, lastValue []byte, existed bool) - MirrorFirst(key []byte) (firstKey, firstValue []byte, existed bool) - Last(key []byte) (lastKey, lastValue []byte, existed bool) - First(key []byte) (firstKey, firstValue []byte, existed bool) - SubGet(key, subKey []byte) (value []byte, existed bool) - Get(key []byte) (value []byte, existed bool) - SubSize(key []byte) (result int) - Size() (result int) - SetExpression(expr setop.SetExpression) (result []setop.SetOpResult) - SubAddConfiguration(treeKey []byte, key, value string) + SSubPut(key, subKey, value []byte) + SubPut(key, subKey, value []byte) + SPut(key, value []byte) + Put(key, value []byte) + SubClear(key []byte) + SSubClear(key []byte) + SubDel(key, subKey []byte) + SSubDel(key, subKey []byte) + SDel(key []byte) + Del(key []byte) + MirrorReverseIndexOf(key, subKey []byte) (index int, existed bool) + MirrorIndexOf(key, subKey []byte) (index int, existed bool) + ReverseIndexOf(key, subKey []byte) (index int, existed bool) + IndexOf(key, subKey []byte) (index int, existed bool) + Next(key []byte) (nextKey, nextValue []byte, existed bool) + Prev(key []byte) (prevKey, prevValue []byte, existed bool) + MirrorCount(key, min, max []byte, mininc, maxinc bool) (result int) + Count(key, min, max []byte, mininc, maxinc bool) (result int) + MirrorNextIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) + MirrorPrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) + NextIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) + PrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundIndex int, existed bool) + MirrorReverseSliceIndex(key []byte, min, max *int) (result []common.Item) + MirrorSliceIndex(key []byte, min, max *int) (result []common.Item) + MirrorReverseSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) + MirrorSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) + MirrorSliceLen(key, min []byte, mininc bool, maxRes int) (result []common.Item) + MirrorReverseSliceLen(key, max []byte, maxinc bool, maxRes int) (result []common.Item) + ReverseSliceIndex(key []byte, min, max *int) (result []common.Item) + SliceIndex(key []byte, min, max *int) (result []common.Item) + ReverseSlice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) + Slice(key, min, max []byte, mininc, maxinc bool) (result []common.Item) + SliceLen(key, min []byte, mininc bool, maxRes int) (result []common.Item) + ReverseSliceLen(key, max []byte, maxinc bool, maxRes int) (result []common.Item) + SubMirrorPrev(key, subKey []byte) (prevKey, prevValue []byte, existed bool) + SubMirrorNext(key, subKey []byte) (nextKey, nextValue []byte, existed bool) + SubPrev(key, subKey []byte) (prevKey, prevValue []byte, existed bool) + SubNext(key, subKey []byte) (nextKey, nextValue []byte, existed bool) + MirrorLast(key []byte) (lastKey, lastValue []byte, existed bool) + MirrorFirst(key []byte) (firstKey, firstValue []byte, existed bool) + Last(key []byte) (lastKey, lastValue []byte, existed bool) + First(key []byte) (firstKey, firstValue []byte, existed bool) + SubGet(key, subKey []byte) (value []byte, existed bool) + Get(key []byte) (value []byte, existed bool) + SubSize(key []byte) (result int) + Size() (result int) + SetExpression(expr setop.SetExpression) (result []setop.SetOpResult) + SubAddConfiguration(treeKey []byte, key, value string) } var benchNode *Node func BenchmarkServer(b *testing.B) { - oldprocs := runtime.GOMAXPROCS(runtime.NumCPU()) - defer runtime.GOMAXPROCS(oldprocs) - b.StopTimer() - if benchNode == nil { - benchNode = NewNode("127.0.0.1:1231") - benchNode.MustStart() - } - benchNode.Clear() - var bs [][]byte - for i := 0; i < b.N; i++ { - bs = append(bs, murmur.HashString(fmt.Sprint(i))) - } - b.StartTimer() - for i := 0; i < b.N; i++ { - benchNode.Put(common.Item{ - Key: bs[i], - Value: bs[i], - }) - } + oldprocs := runtime.GOMAXPROCS(runtime.NumCPU()) + defer runtime.GOMAXPROCS(oldprocs) + b.StopTimer() + if benchNode == nil { + benchNode = NewNode("127.0.0.1:1231", "127.0.0.1:1231") + benchNode.MustStart() + } + benchNode.Clear() + var bs [][]byte + for i := 0; i < b.N; i++ { + bs = append(bs, murmur.HashString(fmt.Sprint(i))) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + benchNode.Put(common.Item{ + Key: bs[i], + Value: bs[i], + }) + } } func BenchmarkClientAndServer(b *testing.B) { - oldprocs := runtime.GOMAXPROCS(runtime.NumCPU()) - defer runtime.GOMAXPROCS(oldprocs) - b.StopTimer() - if benchNode == nil { - benchNode = NewNode("127.0.0.1:1231") - benchNode.MustStart() - } - c := client.MustConn("127.0.0.1:1231") - c.Clear() - var bs [][]byte - for i := 0; i < b.N; i++ { - bs = append(bs, murmur.HashString(fmt.Sprint(i))) - } - b.StartTimer() - for i := 0; i < b.N; i++ { - c.Put(bs[i], bs[i]) - } + oldprocs := runtime.GOMAXPROCS(runtime.NumCPU()) + defer runtime.GOMAXPROCS(oldprocs) + b.StopTimer() + if benchNode == nil { + benchNode = NewNode("127.0.0.1:1231", "127.0.0.1:1231") + benchNode.MustStart() + } + c := client.MustConn("127.0.0.1:1231") + c.Clear() + var bs [][]byte + for i := 0; i < b.N; i++ { + bs = append(bs, murmur.HashString(fmt.Sprint(i))) + } + b.StartTimer() + for i := 0; i < b.N; i++ { + c.Put(bs[i], bs[i]) + } } func TestClient(t *testing.T) { - dhashes := testStartup(t, common.Redundancy*2, 11191) - testGOBClient(t, dhashes) - testJSONClient(t, dhashes) + dhashes := testStartup(t, common.Redundancy*2, 11191) + testGOBClient(t, dhashes) + testJSONClient(t, dhashes) + stopServers(dhashes) } func clearAll(dhashes []*Node) { - for _, node := range dhashes { - node.Clear() - } + for _, node := range dhashes { + node.Clear() + } } func testGOBClient(t *testing.T, dhashes []*Node) { - clearAll(dhashes) - c := client.MustConn(dhashes[0].GetAddr()) - c.Start() - testClientInterface(t, dhashes, c) + fmt.Println(" === Run testGOBClient") + clearAll(dhashes) + c := client.MustConn(dhashes[0].GetBroadcastAddr()) + c.Start() + testClientInterface(t, dhashes, c) } func testJSONClient(t *testing.T, dhashes []*Node) { - for _, dhash := range dhashes { - clearAll(dhashes) - addr, err := net.ResolveTCPAddr("tcp", dhash.node.GetAddr()) - if err != nil { - panic(err) - } - c := JSONClient(fmt.Sprintf("%v:%v", addr.IP, addr.Port+1)) - testClientInterface(t, dhashes, c) - } + fmt.Println(" === Run testJSONClient") + for _, dhash := range dhashes { + clearAll(dhashes) + addr, err := net.ResolveTCPAddr("tcp", dhash.node.GetBroadcastAddr()) + if err != nil { + panic(err) + } + c := JSONClient(fmt.Sprintf("%v:%v", addr.IP, addr.Port+1)) + testClientInterface(t, dhashes, c) + } } func testClientInterface(t *testing.T, dhashes []*Node, c testClient) { - testGetPutDel(t, c) - testSubGetPutDel(t, c) - testSubClear(t, c) - testIndices(t, dhashes, c) - if rc, ok := c.(*client.Conn); ok { - testDump(t, rc) - testSubDump(t, rc) - } - testNextPrev(t, c) - testCounts(t, dhashes, c) - testNextPrevIndices(t, dhashes, c) - testSlices(t, dhashes, c) - testSliceIndices(t, dhashes, c) - testSliceLen(t, dhashes, c) - testSetExpression(t, c) + fmt.Println(" === Run testGetPutDel") + testGetPutDel(t, c) + fmt.Println(" === Run testSubGetPutDel") + testSubGetPutDel(t, c) + fmt.Println(" === Run testSubClear") + testSubClear(t, c) + fmt.Println(" === Run testIndices") + testIndices(t, dhashes, c) + if rc, ok := c.(*client.Conn); ok { + fmt.Println(" === Run testDump") + testDump(t, rc) + fmt.Println(" === Run testSubDump") + testSubDump(t, rc) + } + fmt.Println(" === Run testNextPrev") + testNextPrev(t, c) + fmt.Println(" === Run testCounts") + testCounts(t, dhashes, c) + fmt.Println(" === Run testNextPrevIndices") + testNextPrevIndices(t, dhashes, c) + fmt.Println(" === Run testSlices") + testSlices(t, dhashes, c) + fmt.Println(" === Run testSliceIndices") + testSliceIndices(t, dhashes, c) + fmt.Println(" === Run testSliceLen") + testSliceLen(t, dhashes, c) + fmt.Println(" === Run testSetExpression") + testSetExpression(t, c) } func assertSetOps(t *testing.T, res []setop.SetOpResult, keys, values []byte) { - _, file, line, _ := runtime.Caller(1) - if len(res) == len(keys) && len(res) == len(values) { - for index, item := range res { - if len(item.Values) != 1 { - t.Errorf("%v:%v: assertSetOps only accepts singular values") - } - if string(item.Key) != string([]byte{keys[index]}) || string(item.Values[0]) != string([]byte{values[index]}) { - t.Errorf("%v:%v: wanted %v, %v but got %v", file, line, keys, values, res) - } - } - } else { - t.Errorf("%v:%v: wanted %v, %v but got %v", file, line, keys, values, res) - } + _, file, line, _ := runtime.Caller(1) + if len(res) == len(keys) && len(res) == len(values) { + for index, item := range res { + if len(item.Values) != 1 { + t.Errorf("%v:%v: assertSetOps only accepts singular values") + } + if string(item.Key) != string([]byte{keys[index]}) || string(item.Values[0]) != string([]byte{values[index]}) { + t.Errorf("%v:%v: wanted %v, %v but got %v", file, line, keys, values, res) + } + } + } else { + t.Errorf("%v:%v: wanted %v, %v but got %v", file, line, keys, values, res) + } } func assertItems(t *testing.T, items []common.Item, keys, values []byte) { - _, file, line, _ := runtime.Caller(1) - if len(items) == len(keys) && len(items) == len(values) { - for index, item := range items { - if string(item.Key) != string([]byte{keys[index]}) || string(item.Value) != string([]byte{values[index]}) { - t.Errorf("%v:%v: wanted %v, %v but got %v", file, line, keys, values, items) - } - } - } else { - t.Errorf("%v:%v: wanted %v, %v but got %v", file, line, keys, values, items) - } + _, file, line, _ := runtime.Caller(1) + if len(items) == len(keys) && len(items) == len(values) { + for index, item := range items { + if string(item.Key) != string([]byte{keys[index]}) || string(item.Value) != string([]byte{values[index]}) { + t.Errorf("%v:%v: wanted %v, %v but got %v", file, line, keys, values, items) + } + } + } else { + t.Errorf("%v:%v: wanted %v, %v but got %v", file, line, keys, values, items) + } } func assertMirrored(t *testing.T, dhashes []*Node, c testClient, subTree []byte) { - common.AssertWithin(t, func() (string, bool) { - for _, n := range dhashes { - var conf common.Conf - n.SubConfiguration(subTree, &conf) - var s int - n.SubSize(subTree, &s) - if s > 0 { - if conf.Data["mirrored"] != "yes" { - return fmt.Sprint(n, conf.Data), false - } - } - } - return "", true - }, time.Second*10) + common.AssertWithin(t, func() (string, bool) { + for _, n := range dhashes { + var conf common.Conf + n.SubConfiguration(subTree, &conf) + var s int + n.SubSize(subTree, &s) + if s > 0 { + if conf.Data["mirrored"] != "yes" { + return fmt.Sprint(n, conf.Data), false + } + } + } + return "", true + }, time.Second*10) } func testSetExpression(t *testing.T, c testClient) { - t1 := []byte("sete1") - t2 := []byte("sete2") - for i := byte(0); i < 10; i++ { - c.SubPut(t1, []byte{i}, common.EncodeBigInt(big.NewInt(1))) - } - for i := byte(5); i < 15; i++ { - c.SubPut(t2, []byte{i}, common.EncodeBigInt(big.NewInt(1))) - } - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), - }), []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Min: []byte{2}, - Max: []byte{6}, - Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), - }), []byte{3, 4, 5}, []byte{1, 1, 1}) - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Min: []byte{2}, - Max: []byte{6}, - MinInc: true, - MaxInc: true, - Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), - }), []byte{2, 3, 4, 5, 6}, []byte{1, 1, 1, 1, 1}) - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Min: []byte{2}, - Max: []byte{6}, - MinInc: true, - MaxInc: true, - Len: 3, - Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), - }), []byte{2, 3, 4}, []byte{1, 1, 1}) - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Min: []byte{2}, - Max: []byte{6}, - MinInc: true, - MaxInc: true, - Len: 3, - Dest: []byte("sete3"), - Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), - }), []byte{}, []byte{}) - min := 0 - max := 100 - assertItems(t, c.SliceIndex([]byte("sete3"), &min, &max), []byte{2, 3, 4}, []byte{1, 1, 1}) - - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Code: "(U:BigIntAnd sete1 sete2)", - }), []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Min: []byte{2}, - Max: []byte{6}, - Code: "(U:BigIntAnd sete1 sete2)", - }), []byte{3, 4, 5}, []byte{1, 1, 1}) - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Min: []byte{2}, - Max: []byte{6}, - MinInc: true, - MaxInc: true, - Code: "(U:BigIntAnd sete1 sete2)", - }), []byte{2, 3, 4, 5, 6}, []byte{1, 1, 1, 1, 1}) - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Min: []byte{2}, - Max: []byte{6}, - MinInc: true, - MaxInc: true, - Len: 3, - Code: "(U:BigIntAnd sete1 sete2)", - }), []byte{2, 3, 4}, []byte{1, 1, 1}) - assertSetOps(t, c.SetExpression(setop.SetExpression{ - Min: []byte{2}, - Max: []byte{6}, - MinInc: true, - MaxInc: true, - Len: 3, - Dest: []byte("sete4"), - Code: "(U:BigIntAnd sete1 sete2)", - }), []byte{}, []byte{}) - assertItems(t, c.SliceIndex([]byte("sete4"), &min, &max), []byte{2, 3, 4}, []byte{1, 1, 1}) + t1 := []byte("sete1") + t2 := []byte("sete2") + for i := byte(0); i < 10; i++ { + c.SubPut(t1, []byte{i}, setop.EncodeBigInt(big.NewInt(1))) + } + for i := byte(5); i < 15; i++ { + c.SubPut(t2, []byte{i}, setop.EncodeBigInt(big.NewInt(1))) + } + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), + }), []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Min: []byte{2}, + Max: []byte{6}, + Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), + }), []byte{3, 4, 5}, []byte{1, 1, 1}) + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Min: []byte{2}, + Max: []byte{6}, + MinInc: true, + MaxInc: true, + Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), + }), []byte{2, 3, 4, 5, 6}, []byte{1, 1, 1, 1, 1}) + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Min: []byte{2}, + Max: []byte{6}, + MinInc: true, + MaxInc: true, + Len: 3, + Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), + }), []byte{2, 3, 4}, []byte{1, 1, 1}) + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Min: []byte{2}, + Max: []byte{6}, + MinInc: true, + MaxInc: true, + Len: 3, + Dest: []byte("sete3"), + Op: setop.MustParse("(U:BigIntAnd sete1 sete2)"), + }), []byte{}, []byte{}) + min := 0 + max := 100 + assertItems(t, c.SliceIndex([]byte("sete3"), &min, &max), []byte{2, 3, 4}, []byte{1, 1, 1}) + + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Code: "(U:BigIntAnd sete1 sete2)", + }), []byte{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14}, []byte{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}) + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Min: []byte{2}, + Max: []byte{6}, + Code: "(U:BigIntAnd sete1 sete2)", + }), []byte{3, 4, 5}, []byte{1, 1, 1}) + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Min: []byte{2}, + Max: []byte{6}, + MinInc: true, + MaxInc: true, + Code: "(U:BigIntAnd sete1 sete2)", + }), []byte{2, 3, 4, 5, 6}, []byte{1, 1, 1, 1, 1}) + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Min: []byte{2}, + Max: []byte{6}, + MinInc: true, + MaxInc: true, + Len: 3, + Code: "(U:BigIntAnd sete1 sete2)", + }), []byte{2, 3, 4}, []byte{1, 1, 1}) + assertSetOps(t, c.SetExpression(setop.SetExpression{ + Min: []byte{2}, + Max: []byte{6}, + MinInc: true, + MaxInc: true, + Len: 3, + Dest: []byte("sete4"), + Code: "(U:BigIntAnd sete1 sete2)", + }), []byte{}, []byte{}) + assertItems(t, c.SliceIndex([]byte("sete4"), &min, &max), []byte{2, 3, 4}, []byte{1, 1, 1}) } func testNextPrev(t *testing.T, c testClient) { - c.SPut([]byte("testNextPrev1"), []byte("v1")) - c.SPut([]byte("testNextPrev2"), []byte("v2")) - if k, v, e := c.Prev([]byte("testNextPrev2")); string(k) != "testNextPrev1" || string(v) != "v1" || !e { - t.Errorf("wrong next") - } - if k, v, e := c.Next([]byte("testNextPrev1")); string(k) != "testNextPrev2" || string(v) != "v2" || !e { - t.Errorf("wrong next") - } + c.SPut([]byte("testNextPrev1"), []byte("v1")) + c.SPut([]byte("testNextPrev2"), []byte("v2")) + if k, v, e := c.Prev([]byte("testNextPrev2")); string(k) != "testNextPrev1" || string(v) != "v1" || !e { + t.Errorf("wrong next") + } + if k, v, e := c.Next([]byte("testNextPrev1")); string(k) != "testNextPrev2" || string(v) != "v2" || !e { + t.Errorf("wrong next") + } } func testSubDump(t *testing.T, c *client.Conn) { - ch, wa := c.SubDump([]byte("hest")) - ch <- [2][]byte{[]byte("testSubDumpk1"), []byte("testSubDumpv1")} - ch <- [2][]byte{[]byte("testSubDumpk2"), []byte("testSubDumpv2")} - close(ch) - wa.Wait() - if val, ex := c.SubGet([]byte("hest"), []byte("testSubDumpk1")); !ex || bytes.Compare(val, []byte("testSubDumpv1")) != 0 { - t.Errorf("wrong value") - } - if val, ex := c.SubGet([]byte("hest"), []byte("testSubDumpk2")); !ex || bytes.Compare(val, []byte("testSubDumpv2")) != 0 { - t.Errorf("wrong value") - } + ch, wa := c.SubDump([]byte("hest")) + ch <- [2][]byte{[]byte("testSubDumpk1"), []byte("testSubDumpv1")} + ch <- [2][]byte{[]byte("testSubDumpk2"), []byte("testSubDumpv2")} + close(ch) + wa.Wait() + if val, ex := c.SubGet([]byte("hest"), []byte("testSubDumpk1")); !ex || bytes.Compare(val, []byte("testSubDumpv1")) != 0 { + t.Errorf("wrong value") + } + if val, ex := c.SubGet([]byte("hest"), []byte("testSubDumpk2")); !ex || bytes.Compare(val, []byte("testSubDumpv2")) != 0 { + t.Errorf("wrong value") + } } func testDump(t *testing.T, c *client.Conn) { - ch, wa := c.Dump() - ch <- [2][]byte{[]byte("testDumpk1"), []byte("testDumpv1")} - ch <- [2][]byte{[]byte("testDumpk2"), []byte("testDumpv2")} - close(ch) - wa.Wait() - if val, ex := c.Get([]byte("testDumpk1")); !ex || bytes.Compare(val, []byte("testDumpv1")) != 0 { - t.Errorf("wrong value") - } - if val, ex := c.Get([]byte("testDumpk2")); !ex || bytes.Compare(val, []byte("testDumpv2")) != 0 { - t.Errorf("wrong value") - } + ch, wa := c.Dump() + ch <- [2][]byte{[]byte("testDumpk1"), []byte("testDumpv1")} + ch <- [2][]byte{[]byte("testDumpk2"), []byte("testDumpv2")} + close(ch) + wa.Wait() + if val, ex := c.Get([]byte("testDumpk1")); !ex || bytes.Compare(val, []byte("testDumpv1")) != 0 { + t.Errorf("wrong value") + } + if val, ex := c.Get([]byte("testDumpk2")); !ex || bytes.Compare(val, []byte("testDumpv2")) != 0 { + t.Errorf("wrong value") + } } func testSubGetPutDel(t *testing.T, c testClient) { - var key []byte - var value []byte - var subKey []byte - for j := 0; j < 100; j++ { - key = murmur.HashString(fmt.Sprint(j)) - for i := 0; i < 10; i++ { - subKey = murmur.HashString(fmt.Sprint(i)) - value = murmur.HashString(fmt.Sprint(i)) - if v, e := c.SubGet(key, subKey); v != nil || e { - t.Errorf("shouldn't exist") - } - c.SSubPut(key, subKey, value) - if v, e := c.SubGet(key, subKey); bytes.Compare(value, v) != 0 || !e { - t.Errorf("should exist, but got %v => %v, %v", key, v, e) - } - c.SSubDel(key, subKey) - if v, e := c.SubGet(key, subKey); v != nil || e { - t.Errorf("shouldn't exist, but got %v => %v, %v", key, v, e) - } - } - } + var key []byte + var value []byte + var subKey []byte + for j := 0; j < 100; j++ { + key = murmur.HashString(fmt.Sprint(j)) + for i := 0; i < 10; i++ { + subKey = murmur.HashString(fmt.Sprint(i)) + value = murmur.HashString(fmt.Sprint(i)) + if v, e := c.SubGet(key, subKey); v != nil || e { + t.Errorf("shouldn't exist") + } + c.SSubPut(key, subKey, value) + if v, e := c.SubGet(key, subKey); bytes.Compare(value, v) != 0 || !e { + t.Errorf("should exist, but got %v => %v, %v", key, v, e) + } + c.SSubDel(key, subKey) + if v, e := c.SubGet(key, subKey); v != nil || e { + t.Errorf("shouldn't exist, but got %v => %v, %v", key, v, e) + } + } + } } func testSliceLen(t *testing.T, dhashes []*Node, c testClient) { - var key []byte - var value []byte - subTree := []byte("jaguar2") - c.SubAddConfiguration(subTree, "mirrored", "yes") - for i := byte(1); i < 9; i++ { - key = []byte{i} - value = []byte{9 - i} - c.SSubPut(subTree, key, value) - if ss := c.SubSize(subTree); ss != int(i) { - t.Errorf("wrong size, wanted %v but got %v", i, ss) - } - } - assertMirrored(t, dhashes, c, subTree) - assertItems(t, c.SliceLen(subTree, []byte{2}, true, 3), []byte{2, 3, 4}, []byte{7, 6, 5}) - assertItems(t, c.SliceLen(subTree, []byte{2}, false, 3), []byte{3, 4, 5}, []byte{6, 5, 4}) - assertItems(t, c.ReverseSliceLen(subTree, []byte{6}, true, 3), []byte{6, 5, 4}, []byte{3, 4, 5}) - assertItems(t, c.ReverseSliceLen(subTree, []byte{6}, false, 3), []byte{5, 4, 3}, []byte{4, 5, 6}) - assertItems(t, c.MirrorSliceLen(subTree, []byte{2}, true, 3), []byte{2, 3, 4}, []byte{7, 6, 5}) - assertItems(t, c.MirrorSliceLen(subTree, []byte{2}, false, 3), []byte{3, 4, 5}, []byte{6, 5, 4}) - assertItems(t, c.MirrorReverseSliceLen(subTree, []byte{6}, true, 3), []byte{6, 5, 4}, []byte{3, 4, 5}) - assertItems(t, c.MirrorReverseSliceLen(subTree, []byte{6}, false, 3), []byte{5, 4, 3}, []byte{4, 5, 6}) + var key []byte + var value []byte + subTree := []byte("jaguar2") + c.SubAddConfiguration(subTree, "mirrored", "yes") + for i := byte(1); i < 9; i++ { + key = []byte{i} + value = []byte{9 - i} + c.SSubPut(subTree, key, value) + if ss := c.SubSize(subTree); ss != int(i) { + t.Errorf("wrong size, wanted %v but got %v", i, ss) + } + } + assertMirrored(t, dhashes, c, subTree) + assertItems(t, c.SliceLen(subTree, []byte{2}, true, 3), []byte{2, 3, 4}, []byte{7, 6, 5}) + assertItems(t, c.SliceLen(subTree, []byte{2}, false, 3), []byte{3, 4, 5}, []byte{6, 5, 4}) + assertItems(t, c.ReverseSliceLen(subTree, []byte{6}, true, 3), []byte{6, 5, 4}, []byte{3, 4, 5}) + assertItems(t, c.ReverseSliceLen(subTree, []byte{6}, false, 3), []byte{5, 4, 3}, []byte{4, 5, 6}) + assertItems(t, c.MirrorSliceLen(subTree, []byte{2}, true, 3), []byte{2, 3, 4}, []byte{7, 6, 5}) + assertItems(t, c.MirrorSliceLen(subTree, []byte{2}, false, 3), []byte{3, 4, 5}, []byte{6, 5, 4}) + assertItems(t, c.MirrorReverseSliceLen(subTree, []byte{6}, true, 3), []byte{6, 5, 4}, []byte{3, 4, 5}) + assertItems(t, c.MirrorReverseSliceLen(subTree, []byte{6}, false, 3), []byte{5, 4, 3}, []byte{4, 5, 6}) } func testCounts(t *testing.T, dhashes []*Node, c testClient) { - var key []byte - var value []byte - subTree := []byte("jaguar") - c.SubAddConfiguration(subTree, "mirrored", "yes") - for i := byte(1); i < 9; i++ { - key = []byte{i} - value = []byte{19 - i} - c.SSubPut(subTree, key, value) - } - assertMirrored(t, dhashes, c, subTree) - for i := byte(0); i < 10; i++ { - for j := byte(0); j < 10; j++ { - wanted := common.Max(0, common.Min(int(j+1), 9)-common.Max(int(i), 1)) - found := c.Count([]byte("jaguar"), []byte{i}, []byte{j}, true, true) - if found != wanted { - t.Errorf("wrong count for %v-%v true true, wanted %v but found %v", i, j, wanted, found) - } - wanted = common.Max(0, common.Min(int(j), 9)-common.Max(int(i), 1)) - found = c.Count([]byte("jaguar"), []byte{i}, []byte{j}, true, false) - if found != wanted { - t.Errorf("wrong count for %v-%v true false, wanted %v but found %v", i, j, wanted, found) - } - wanted = common.Max(0, common.Min(int(j+1), 9)-common.Max(int(i+1), 1)) - found = c.Count([]byte("jaguar"), []byte{i}, []byte{j}, false, true) - if found != wanted { - t.Errorf("wrong count for %v-%v true false, wanted %v but found %v", i, j, wanted, found) - } - wanted = common.Max(0, common.Min(int(j), 9)-common.Max(int(i+1), 1)) - found = c.Count([]byte("jaguar"), []byte{i}, []byte{j}, false, false) - if found != wanted { - t.Errorf("wrong count for %v-%v false false, wanted %v but found %v", i, j, wanted, found) - } - - wanted = common.Max(0, common.Min(int(j+10), 19)-common.Max(int(i+11), 11)) - found = c.MirrorCount([]byte("jaguar"), []byte{i + 10}, []byte{j + 10}, false, false) - if found != wanted { - t.Errorf("wrong count for mirror %v-%v false false, wanted %v but found %v", i+10, j+10, wanted, found) - } - wanted = common.Max(0, common.Min(int(j+10), 19)-common.Max(int(i+10), 11)) - found = c.MirrorCount([]byte("jaguar"), []byte{i + 10}, []byte{j + 10}, true, false) - if found != wanted { - t.Errorf("wrong count for mirror %v-%v true false, wanted %v but found %v", i+10, j+10, wanted, found) - } - wanted = common.Max(0, common.Min(int(j+11), 19)-common.Max(int(i+11), 11)) - found = c.MirrorCount([]byte("jaguar"), []byte{i + 10}, []byte{j + 10}, false, true) - if found != wanted { - t.Errorf("wrong count for mirror %v-%v false true, wanted %v but found %v", i+10, j+10, wanted, found) - } - wanted = common.Max(0, common.Min(int(j+11), 19)-common.Max(int(i+10), 11)) - found = c.MirrorCount([]byte("jaguar"), []byte{i + 10}, []byte{j + 10}, true, true) - if found != wanted { - t.Errorf("wrong count for mirror %v-%v true true, wanted %v but found %v", i+10, j+10, wanted, found) - } - } - } + var key []byte + var value []byte + subTree := []byte("jaguar") + c.SubAddConfiguration(subTree, "mirrored", "yes") + for i := byte(1); i < 9; i++ { + key = []byte{i} + value = []byte{19 - i} + c.SSubPut(subTree, key, value) + } + assertMirrored(t, dhashes, c, subTree) + for i := byte(0); i < 10; i++ { + for j := byte(0); j < 10; j++ { + wanted := common.Max(0, common.Min(int(j+1), 9)-common.Max(int(i), 1)) + found := c.Count([]byte("jaguar"), []byte{i}, []byte{j}, true, true) + if found != wanted { + t.Errorf("wrong count for %v-%v true true, wanted %v but found %v", i, j, wanted, found) + } + wanted = common.Max(0, common.Min(int(j), 9)-common.Max(int(i), 1)) + found = c.Count([]byte("jaguar"), []byte{i}, []byte{j}, true, false) + if found != wanted { + t.Errorf("wrong count for %v-%v true false, wanted %v but found %v", i, j, wanted, found) + } + wanted = common.Max(0, common.Min(int(j+1), 9)-common.Max(int(i+1), 1)) + found = c.Count([]byte("jaguar"), []byte{i}, []byte{j}, false, true) + if found != wanted { + t.Errorf("wrong count for %v-%v true false, wanted %v but found %v", i, j, wanted, found) + } + wanted = common.Max(0, common.Min(int(j), 9)-common.Max(int(i+1), 1)) + found = c.Count([]byte("jaguar"), []byte{i}, []byte{j}, false, false) + if found != wanted { + t.Errorf("wrong count for %v-%v false false, wanted %v but found %v", i, j, wanted, found) + } + + wanted = common.Max(0, common.Min(int(j+10), 19)-common.Max(int(i+11), 11)) + found = c.MirrorCount([]byte("jaguar"), []byte{i + 10}, []byte{j + 10}, false, false) + if found != wanted { + t.Errorf("wrong count for mirror %v-%v false false, wanted %v but found %v", i+10, j+10, wanted, found) + } + wanted = common.Max(0, common.Min(int(j+10), 19)-common.Max(int(i+10), 11)) + found = c.MirrorCount([]byte("jaguar"), []byte{i + 10}, []byte{j + 10}, true, false) + if found != wanted { + t.Errorf("wrong count for mirror %v-%v true false, wanted %v but found %v", i+10, j+10, wanted, found) + } + wanted = common.Max(0, common.Min(int(j+11), 19)-common.Max(int(i+11), 11)) + found = c.MirrorCount([]byte("jaguar"), []byte{i + 10}, []byte{j + 10}, false, true) + if found != wanted { + t.Errorf("wrong count for mirror %v-%v false true, wanted %v but found %v", i+10, j+10, wanted, found) + } + wanted = common.Max(0, common.Min(int(j+11), 19)-common.Max(int(i+10), 11)) + found = c.MirrorCount([]byte("jaguar"), []byte{i + 10}, []byte{j + 10}, true, true) + if found != wanted { + t.Errorf("wrong count for mirror %v-%v true true, wanted %v but found %v", i+10, j+10, wanted, found) + } + } + } } func testSliceIndices(t *testing.T, dhashes []*Node, c testClient) { - var key []byte - var value []byte - subTree := []byte("banan2") - c.SubAddConfiguration(subTree, "mirrored", "yes") - for i := byte(1); i < 9; i++ { - key = []byte{i} - value = []byte{9 - i} - c.SSubPut(subTree, key, value) - } - assertMirrored(t, dhashes, c, subTree) - min := 2 - max := 5 - assertItems(t, c.SliceIndex(subTree, &min, &max), []byte{3, 4, 5, 6}, []byte{6, 5, 4, 3}) - assertItems(t, c.SliceIndex(subTree, nil, &max), []byte{1, 2, 3, 4, 5, 6}, []byte{8, 7, 6, 5, 4, 3}) - assertItems(t, c.SliceIndex(subTree, &min, nil), []byte{3, 4, 5, 6, 7, 8}, []byte{6, 5, 4, 3, 2, 1}) - assertItems(t, c.SliceIndex(subTree, nil, nil), []byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{8, 7, 6, 5, 4, 3, 2, 1}) - assertItems(t, c.ReverseSliceIndex(subTree, &min, &max), []byte{6, 5, 4, 3}, []byte{3, 4, 5, 6}) - assertItems(t, c.ReverseSliceIndex(subTree, nil, &max), []byte{8, 7, 6, 5, 4, 3}, []byte{1, 2, 3, 4, 5, 6}) - assertItems(t, c.ReverseSliceIndex(subTree, &min, nil), []byte{6, 5, 4, 3, 2, 1}, []byte{3, 4, 5, 6, 7, 8}) - assertItems(t, c.ReverseSliceIndex(subTree, nil, nil), []byte{8, 7, 6, 5, 4, 3, 2, 1}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) - assertItems(t, c.MirrorSliceIndex(subTree, &min, &max), []byte{3, 4, 5, 6}, []byte{6, 5, 4, 3}) - assertItems(t, c.MirrorSliceIndex(subTree, nil, &max), []byte{1, 2, 3, 4, 5, 6}, []byte{8, 7, 6, 5, 4, 3}) - assertItems(t, c.MirrorSliceIndex(subTree, &min, nil), []byte{3, 4, 5, 6, 7, 8}, []byte{6, 5, 4, 3, 2, 1}) - assertItems(t, c.MirrorSliceIndex(subTree, nil, nil), []byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{8, 7, 6, 5, 4, 3, 2, 1}) - assertItems(t, c.MirrorReverseSliceIndex(subTree, &min, &max), []byte{6, 5, 4, 3}, []byte{3, 4, 5, 6}) - assertItems(t, c.MirrorReverseSliceIndex(subTree, nil, &max), []byte{8, 7, 6, 5, 4, 3}, []byte{1, 2, 3, 4, 5, 6}) - assertItems(t, c.MirrorReverseSliceIndex(subTree, &min, nil), []byte{6, 5, 4, 3, 2, 1}, []byte{3, 4, 5, 6, 7, 8}) - assertItems(t, c.MirrorReverseSliceIndex(subTree, nil, nil), []byte{8, 7, 6, 5, 4, 3, 2, 1}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) + var key []byte + var value []byte + subTree := []byte("banan2") + c.SubAddConfiguration(subTree, "mirrored", "yes") + for i := byte(1); i < 9; i++ { + key = []byte{i} + value = []byte{9 - i} + c.SSubPut(subTree, key, value) + } + assertMirrored(t, dhashes, c, subTree) + min := 2 + max := 5 + assertItems(t, c.SliceIndex(subTree, &min, &max), []byte{3, 4, 5, 6}, []byte{6, 5, 4, 3}) + assertItems(t, c.SliceIndex(subTree, nil, &max), []byte{1, 2, 3, 4, 5, 6}, []byte{8, 7, 6, 5, 4, 3}) + assertItems(t, c.SliceIndex(subTree, &min, nil), []byte{3, 4, 5, 6, 7, 8}, []byte{6, 5, 4, 3, 2, 1}) + assertItems(t, c.SliceIndex(subTree, nil, nil), []byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{8, 7, 6, 5, 4, 3, 2, 1}) + assertItems(t, c.ReverseSliceIndex(subTree, &min, &max), []byte{6, 5, 4, 3}, []byte{3, 4, 5, 6}) + assertItems(t, c.ReverseSliceIndex(subTree, nil, &max), []byte{8, 7, 6, 5, 4, 3}, []byte{1, 2, 3, 4, 5, 6}) + assertItems(t, c.ReverseSliceIndex(subTree, &min, nil), []byte{6, 5, 4, 3, 2, 1}, []byte{3, 4, 5, 6, 7, 8}) + assertItems(t, c.ReverseSliceIndex(subTree, nil, nil), []byte{8, 7, 6, 5, 4, 3, 2, 1}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) + assertItems(t, c.MirrorSliceIndex(subTree, &min, &max), []byte{3, 4, 5, 6}, []byte{6, 5, 4, 3}) + assertItems(t, c.MirrorSliceIndex(subTree, nil, &max), []byte{1, 2, 3, 4, 5, 6}, []byte{8, 7, 6, 5, 4, 3}) + assertItems(t, c.MirrorSliceIndex(subTree, &min, nil), []byte{3, 4, 5, 6, 7, 8}, []byte{6, 5, 4, 3, 2, 1}) + assertItems(t, c.MirrorSliceIndex(subTree, nil, nil), []byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{8, 7, 6, 5, 4, 3, 2, 1}) + assertItems(t, c.MirrorReverseSliceIndex(subTree, &min, &max), []byte{6, 5, 4, 3}, []byte{3, 4, 5, 6}) + assertItems(t, c.MirrorReverseSliceIndex(subTree, nil, &max), []byte{8, 7, 6, 5, 4, 3}, []byte{1, 2, 3, 4, 5, 6}) + assertItems(t, c.MirrorReverseSliceIndex(subTree, &min, nil), []byte{6, 5, 4, 3, 2, 1}, []byte{3, 4, 5, 6, 7, 8}) + assertItems(t, c.MirrorReverseSliceIndex(subTree, nil, nil), []byte{8, 7, 6, 5, 4, 3, 2, 1}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) } func testSlices(t *testing.T, dhashes []*Node, c testClient) { - var key []byte - var value []byte - subTree := []byte("banan") - c.SubAddConfiguration(subTree, "mirrored", "yes") - for i := byte(1); i < 9; i++ { - key = []byte{i} - value = []byte{9 - i} - c.SSubPut(subTree, key, value) - } - assertMirrored(t, dhashes, c, subTree) - assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, []byte{5}, true, true), []byte{5, 4, 3, 2}, []byte{4, 5, 6, 7}) - assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, []byte{5}, true, false), []byte{4, 3, 2}, []byte{5, 6, 7}) - assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, []byte{5}, false, true), []byte{5, 4, 3}, []byte{4, 5, 6}) - assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, []byte{5}, false, false), []byte{4, 3}, []byte{5, 6}) - assertItems(t, c.MirrorSlice(subTree, []byte{2}, []byte{5}, true, true), []byte{2, 3, 4, 5}, []byte{7, 6, 5, 4}) - assertItems(t, c.MirrorSlice(subTree, []byte{2}, []byte{5}, true, false), []byte{2, 3, 4}, []byte{7, 6, 5}) - assertItems(t, c.MirrorSlice(subTree, []byte{2}, []byte{5}, false, true), []byte{3, 4, 5}, []byte{6, 5, 4}) - assertItems(t, c.MirrorSlice(subTree, []byte{2}, []byte{5}, false, false), []byte{3, 4}, []byte{6, 5}) - assertItems(t, c.ReverseSlice(subTree, []byte{2}, []byte{5}, true, true), []byte{5, 4, 3, 2}, []byte{4, 5, 6, 7}) - assertItems(t, c.ReverseSlice(subTree, []byte{2}, []byte{5}, true, false), []byte{4, 3, 2}, []byte{5, 6, 7}) - assertItems(t, c.ReverseSlice(subTree, []byte{2}, []byte{5}, false, true), []byte{5, 4, 3}, []byte{4, 5, 6}) - assertItems(t, c.ReverseSlice(subTree, []byte{2}, []byte{5}, false, false), []byte{4, 3}, []byte{5, 6}) - assertItems(t, c.Slice(subTree, []byte{2}, []byte{5}, true, true), []byte{2, 3, 4, 5}, []byte{7, 6, 5, 4}) - assertItems(t, c.Slice(subTree, []byte{2}, []byte{5}, true, false), []byte{2, 3, 4}, []byte{7, 6, 5}) - assertItems(t, c.Slice(subTree, []byte{2}, []byte{5}, false, true), []byte{3, 4, 5}, []byte{6, 5, 4}) - assertItems(t, c.Slice(subTree, []byte{2}, []byte{5}, false, false), []byte{3, 4}, []byte{6, 5}) - - assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, nil, true, true), []byte{8, 7, 6, 5, 4, 3, 2}, []byte{1, 2, 3, 4, 5, 6, 7}) - assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, nil, false, true), []byte{8, 7, 6, 5, 4, 3}, []byte{1, 2, 3, 4, 5, 6}) - assertItems(t, c.MirrorSlice(subTree, []byte{2}, nil, true, true), []byte{2, 3, 4, 5, 6, 7, 8}, []byte{7, 6, 5, 4, 3, 2, 1}) - assertItems(t, c.MirrorSlice(subTree, []byte{2}, nil, false, true), []byte{3, 4, 5, 6, 7, 8}, []byte{6, 5, 4, 3, 2, 1}) - assertItems(t, c.ReverseSlice(subTree, []byte{2}, nil, true, true), []byte{8, 7, 6, 5, 4, 3, 2}, []byte{1, 2, 3, 4, 5, 6, 7}) - assertItems(t, c.ReverseSlice(subTree, []byte{2}, nil, false, true), []byte{8, 7, 6, 5, 4, 3}, []byte{1, 2, 3, 4, 5, 6}) - assertItems(t, c.Slice(subTree, []byte{2}, nil, true, true), []byte{2, 3, 4, 5, 6, 7, 8}, []byte{7, 6, 5, 4, 3, 2, 1}) - assertItems(t, c.Slice(subTree, []byte{2}, nil, false, true), []byte{3, 4, 5, 6, 7, 8}, []byte{6, 5, 4, 3, 2, 1}) - - assertItems(t, c.MirrorReverseSlice(subTree, nil, []byte{5}, true, true), []byte{5, 4, 3, 2, 1}, []byte{4, 5, 6, 7, 8}) - assertItems(t, c.MirrorReverseSlice(subTree, nil, []byte{5}, true, false), []byte{4, 3, 2, 1}, []byte{5, 6, 7, 8}) - assertItems(t, c.MirrorSlice(subTree, nil, []byte{5}, true, true), []byte{1, 2, 3, 4, 5}, []byte{8, 7, 6, 5, 4}) - assertItems(t, c.MirrorSlice(subTree, nil, []byte{5}, true, false), []byte{1, 2, 3, 4}, []byte{8, 7, 6, 5}) - assertItems(t, c.ReverseSlice(subTree, nil, []byte{5}, true, true), []byte{5, 4, 3, 2, 1}, []byte{4, 5, 6, 7, 8}) - assertItems(t, c.ReverseSlice(subTree, nil, []byte{5}, true, false), []byte{4, 3, 2, 1}, []byte{5, 6, 7, 8}) - assertItems(t, c.Slice(subTree, nil, []byte{5}, true, true), []byte{1, 2, 3, 4, 5}, []byte{8, 7, 6, 5, 4}) - assertItems(t, c.Slice(subTree, nil, []byte{5}, true, false), []byte{1, 2, 3, 4}, []byte{8, 7, 6, 5}) - - assertItems(t, c.MirrorReverseSlice(subTree, nil, nil, true, true), []byte{8, 7, 6, 5, 4, 3, 2, 1}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) - assertItems(t, c.MirrorSlice(subTree, nil, nil, true, true), []byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{8, 7, 6, 5, 4, 3, 2, 1}) - assertItems(t, c.ReverseSlice(subTree, nil, nil, true, true), []byte{8, 7, 6, 5, 4, 3, 2, 1}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) - assertItems(t, c.Slice(subTree, nil, nil, true, true), []byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{8, 7, 6, 5, 4, 3, 2, 1}) + var key []byte + var value []byte + subTree := []byte("banan") + c.SubAddConfiguration(subTree, "mirrored", "yes") + for i := byte(1); i < 9; i++ { + key = []byte{i} + value = []byte{9 - i} + c.SSubPut(subTree, key, value) + } + assertMirrored(t, dhashes, c, subTree) + assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, []byte{5}, true, true), []byte{5, 4, 3, 2}, []byte{4, 5, 6, 7}) + assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, []byte{5}, true, false), []byte{4, 3, 2}, []byte{5, 6, 7}) + assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, []byte{5}, false, true), []byte{5, 4, 3}, []byte{4, 5, 6}) + assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, []byte{5}, false, false), []byte{4, 3}, []byte{5, 6}) + assertItems(t, c.MirrorSlice(subTree, []byte{2}, []byte{5}, true, true), []byte{2, 3, 4, 5}, []byte{7, 6, 5, 4}) + assertItems(t, c.MirrorSlice(subTree, []byte{2}, []byte{5}, true, false), []byte{2, 3, 4}, []byte{7, 6, 5}) + assertItems(t, c.MirrorSlice(subTree, []byte{2}, []byte{5}, false, true), []byte{3, 4, 5}, []byte{6, 5, 4}) + assertItems(t, c.MirrorSlice(subTree, []byte{2}, []byte{5}, false, false), []byte{3, 4}, []byte{6, 5}) + assertItems(t, c.ReverseSlice(subTree, []byte{2}, []byte{5}, true, true), []byte{5, 4, 3, 2}, []byte{4, 5, 6, 7}) + assertItems(t, c.ReverseSlice(subTree, []byte{2}, []byte{5}, true, false), []byte{4, 3, 2}, []byte{5, 6, 7}) + assertItems(t, c.ReverseSlice(subTree, []byte{2}, []byte{5}, false, true), []byte{5, 4, 3}, []byte{4, 5, 6}) + assertItems(t, c.ReverseSlice(subTree, []byte{2}, []byte{5}, false, false), []byte{4, 3}, []byte{5, 6}) + assertItems(t, c.Slice(subTree, []byte{2}, []byte{5}, true, true), []byte{2, 3, 4, 5}, []byte{7, 6, 5, 4}) + assertItems(t, c.Slice(subTree, []byte{2}, []byte{5}, true, false), []byte{2, 3, 4}, []byte{7, 6, 5}) + assertItems(t, c.Slice(subTree, []byte{2}, []byte{5}, false, true), []byte{3, 4, 5}, []byte{6, 5, 4}) + assertItems(t, c.Slice(subTree, []byte{2}, []byte{5}, false, false), []byte{3, 4}, []byte{6, 5}) + + assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, nil, true, true), []byte{8, 7, 6, 5, 4, 3, 2}, []byte{1, 2, 3, 4, 5, 6, 7}) + assertItems(t, c.MirrorReverseSlice(subTree, []byte{2}, nil, false, true), []byte{8, 7, 6, 5, 4, 3}, []byte{1, 2, 3, 4, 5, 6}) + assertItems(t, c.MirrorSlice(subTree, []byte{2}, nil, true, true), []byte{2, 3, 4, 5, 6, 7, 8}, []byte{7, 6, 5, 4, 3, 2, 1}) + assertItems(t, c.MirrorSlice(subTree, []byte{2}, nil, false, true), []byte{3, 4, 5, 6, 7, 8}, []byte{6, 5, 4, 3, 2, 1}) + assertItems(t, c.ReverseSlice(subTree, []byte{2}, nil, true, true), []byte{8, 7, 6, 5, 4, 3, 2}, []byte{1, 2, 3, 4, 5, 6, 7}) + assertItems(t, c.ReverseSlice(subTree, []byte{2}, nil, false, true), []byte{8, 7, 6, 5, 4, 3}, []byte{1, 2, 3, 4, 5, 6}) + assertItems(t, c.Slice(subTree, []byte{2}, nil, true, true), []byte{2, 3, 4, 5, 6, 7, 8}, []byte{7, 6, 5, 4, 3, 2, 1}) + assertItems(t, c.Slice(subTree, []byte{2}, nil, false, true), []byte{3, 4, 5, 6, 7, 8}, []byte{6, 5, 4, 3, 2, 1}) + + assertItems(t, c.MirrorReverseSlice(subTree, nil, []byte{5}, true, true), []byte{5, 4, 3, 2, 1}, []byte{4, 5, 6, 7, 8}) + assertItems(t, c.MirrorReverseSlice(subTree, nil, []byte{5}, true, false), []byte{4, 3, 2, 1}, []byte{5, 6, 7, 8}) + assertItems(t, c.MirrorSlice(subTree, nil, []byte{5}, true, true), []byte{1, 2, 3, 4, 5}, []byte{8, 7, 6, 5, 4}) + assertItems(t, c.MirrorSlice(subTree, nil, []byte{5}, true, false), []byte{1, 2, 3, 4}, []byte{8, 7, 6, 5}) + assertItems(t, c.ReverseSlice(subTree, nil, []byte{5}, true, true), []byte{5, 4, 3, 2, 1}, []byte{4, 5, 6, 7, 8}) + assertItems(t, c.ReverseSlice(subTree, nil, []byte{5}, true, false), []byte{4, 3, 2, 1}, []byte{5, 6, 7, 8}) + assertItems(t, c.Slice(subTree, nil, []byte{5}, true, true), []byte{1, 2, 3, 4, 5}, []byte{8, 7, 6, 5, 4}) + assertItems(t, c.Slice(subTree, nil, []byte{5}, true, false), []byte{1, 2, 3, 4}, []byte{8, 7, 6, 5}) + + assertItems(t, c.MirrorReverseSlice(subTree, nil, nil, true, true), []byte{8, 7, 6, 5, 4, 3, 2, 1}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) + assertItems(t, c.MirrorSlice(subTree, nil, nil, true, true), []byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{8, 7, 6, 5, 4, 3, 2, 1}) + assertItems(t, c.ReverseSlice(subTree, nil, nil, true, true), []byte{8, 7, 6, 5, 4, 3, 2, 1}, []byte{1, 2, 3, 4, 5, 6, 7, 8}) + assertItems(t, c.Slice(subTree, nil, nil, true, true), []byte{1, 2, 3, 4, 5, 6, 7, 8}, []byte{8, 7, 6, 5, 4, 3, 2, 1}) } func testNextPrevIndices(t *testing.T, dhashes []*Node, c testClient) { - var key []byte - var value []byte - subTree := []byte("gris") - c.SubAddConfiguration(subTree, "mirrored", "yes") - for i := byte(1); i < 9; i++ { - key = []byte{i} - value = []byte{9 - i} - c.SSubPut(subTree, key, value) - } - assertMirrored(t, dhashes, c, subTree) - if k, v, i, e := c.NextIndex(subTree, -1); string(k) != string([]byte{1}) || string(v) != string([]byte{8}) || i != 0 || !e { - t.Errorf("wrong next index! wanted %v, %v, %v, %v but got %v, %v, %v, %v", 1, 8, 0, true, k, v, i, e) - } - if _, _, _, e := c.NextIndex(subTree, 7); e { - t.Errorf("wrong next index! wanted %v but got %v", false, e) - } - if k, v, i, e := c.PrevIndex(subTree, 8); string(k) != string([]byte{8}) || string(v) != string([]byte{1}) || i != 7 || !e { - t.Errorf("wrong prev index! wanted %v, %v, %v, %v but got %v, %v, %v, %v", 8, 1, 7, true, k, v, i, e) - } - if _, _, _, e := c.PrevIndex(subTree, 0); e { - t.Errorf("wrong prev index! wanted %v but got %v", false, e) - } - - for j := 0; j < 7; j++ { - if k, v, i, e := c.NextIndex(subTree, j); string(k) != string([]byte{byte(j + 2)}) || string(v) != string([]byte{byte(7 - j)}) || i != j+1 || !e { - t.Errorf("wrong next index for %v! wanted %v, %v, %v, %v but got %v, %v, %v, %v", j, j+2, 7-j, j+1, true, k, v, i, e) - } - } - for j := 1; j < 8; j++ { - if k, v, i, e := c.PrevIndex(subTree, j); string(k) != string([]byte{byte(j)}) || string(v) != string([]byte{byte(9 - j)}) || i != j-1 || !e { - t.Errorf("wrong prev index for %v! wanted %v, %v, %v, %v but got %v, %v, %v, %v", j, j, 9-j, j-1, true, k, v, i, e) - } - } - - if k, v, i, e := c.MirrorNextIndex(subTree, -1); string(k) != string([]byte{1}) || string(v) != string([]byte{8}) || i != 0 || !e { - t.Errorf("wrong next index! wanted %v, %v, %v, %v but got %v, %v, %v, %v", 1, 8, 0, true, k, v, i, e) - } - if _, _, _, e := c.MirrorNextIndex(subTree, 7); e { - t.Errorf("wrong next index! wanted %v but got %v", false, e) - } - if k, v, i, e := c.MirrorPrevIndex(subTree, 8); string(k) != string([]byte{8}) || string(v) != string([]byte{1}) || i != 7 || !e { - t.Errorf("wrong prev index! wanted %v, %v, %v, %v but got %v, %v, %v, %v", 8, 1, 7, true, k, v, i, e) - } - if _, _, _, e := c.MirrorPrevIndex(subTree, 0); e { - t.Errorf("wrong prev index! wanted %v but got %v", false, e) - } - - for j := 1; j < 8; j++ { - if k, v, i, e := c.MirrorPrevIndex(subTree, j); string(k) != string([]byte{byte(j)}) || string(v) != string([]byte{byte(9 - j)}) || i != j-1 || !e { - t.Errorf("wrong mirror next index for %v! wanted %v, %v, %v, %v but got %v, %v, %v, %v", j, j, 9-j, j-1, true, k, v, i, e) - } - } - for j := 1; j < 8; j++ { - if k, v, i, e := c.MirrorPrevIndex(subTree, j); string(k) != string([]byte{byte(j)}) || string(v) != string([]byte{byte(9 - j)}) || i != j-1 || !e { - t.Errorf("wrong mirror prev index for %v! wanted %v, %v, %v, %v but got %v, %v, %v, %v", j, j, 9-j, j-1, true, k, v, i, e) - } - } + var key []byte + var value []byte + subTree := []byte("gris") + c.SubAddConfiguration(subTree, "mirrored", "yes") + for i := byte(1); i < 9; i++ { + key = []byte{i} + value = []byte{9 - i} + c.SSubPut(subTree, key, value) + } + assertMirrored(t, dhashes, c, subTree) + if k, v, i, e := c.NextIndex(subTree, -1); string(k) != string([]byte{1}) || string(v) != string([]byte{8}) || i != 0 || !e { + t.Errorf("wrong next index! wanted %v, %v, %v, %v but got %v, %v, %v, %v", 1, 8, 0, true, k, v, i, e) + } + if _, _, _, e := c.NextIndex(subTree, 7); e { + t.Errorf("wrong next index! wanted %v but got %v", false, e) + } + if k, v, i, e := c.PrevIndex(subTree, 8); string(k) != string([]byte{8}) || string(v) != string([]byte{1}) || i != 7 || !e { + t.Errorf("wrong prev index! wanted %v, %v, %v, %v but got %v, %v, %v, %v", 8, 1, 7, true, k, v, i, e) + } + if _, _, _, e := c.PrevIndex(subTree, 0); e { + t.Errorf("wrong prev index! wanted %v but got %v", false, e) + } + + for j := 0; j < 7; j++ { + if k, v, i, e := c.NextIndex(subTree, j); string(k) != string([]byte{byte(j + 2)}) || string(v) != string([]byte{byte(7 - j)}) || i != j+1 || !e { + t.Errorf("wrong next index for %v! wanted %v, %v, %v, %v but got %v, %v, %v, %v", j, j+2, 7-j, j+1, true, k, v, i, e) + } + } + for j := 1; j < 8; j++ { + if k, v, i, e := c.PrevIndex(subTree, j); string(k) != string([]byte{byte(j)}) || string(v) != string([]byte{byte(9 - j)}) || i != j-1 || !e { + t.Errorf("wrong prev index for %v! wanted %v, %v, %v, %v but got %v, %v, %v, %v", j, j, 9-j, j-1, true, k, v, i, e) + } + } + + if k, v, i, e := c.MirrorNextIndex(subTree, -1); string(k) != string([]byte{1}) || string(v) != string([]byte{8}) || i != 0 || !e { + t.Errorf("wrong next index! wanted %v, %v, %v, %v but got %v, %v, %v, %v", 1, 8, 0, true, k, v, i, e) + } + if _, _, _, e := c.MirrorNextIndex(subTree, 7); e { + t.Errorf("wrong next index! wanted %v but got %v", false, e) + } + if k, v, i, e := c.MirrorPrevIndex(subTree, 8); string(k) != string([]byte{8}) || string(v) != string([]byte{1}) || i != 7 || !e { + t.Errorf("wrong prev index! wanted %v, %v, %v, %v but got %v, %v, %v, %v", 8, 1, 7, true, k, v, i, e) + } + if _, _, _, e := c.MirrorPrevIndex(subTree, 0); e { + t.Errorf("wrong prev index! wanted %v but got %v", false, e) + } + + for j := 1; j < 8; j++ { + if k, v, i, e := c.MirrorPrevIndex(subTree, j); string(k) != string([]byte{byte(j)}) || string(v) != string([]byte{byte(9 - j)}) || i != j-1 || !e { + t.Errorf("wrong mirror next index for %v! wanted %v, %v, %v, %v but got %v, %v, %v, %v", j, j, 9-j, j-1, true, k, v, i, e) + } + } + for j := 1; j < 8; j++ { + if k, v, i, e := c.MirrorPrevIndex(subTree, j); string(k) != string([]byte{byte(j)}) || string(v) != string([]byte{byte(9 - j)}) || i != j-1 || !e { + t.Errorf("wrong mirror prev index for %v! wanted %v, %v, %v, %v but got %v, %v, %v, %v", j, j, 9-j, j-1, true, k, v, i, e) + } + } } func testIndices(t *testing.T, dhashes []*Node, c testClient) { - var key []byte - var value []byte - subTree := []byte("ko") - c.SubAddConfiguration(subTree, "mirrored", "yes") - for i := byte(1); i < 9; i++ { - key = []byte{i} - value = []byte{9 - i} - c.SSubPut(subTree, key, value) - } - assertMirrored(t, dhashes, c, subTree) - if ind, ok := c.ReverseIndexOf(subTree, []byte{9}); ind != 0 || ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 0, false, ind, ok) - } - if ind, ok := c.MirrorReverseIndexOf(subTree, []byte{9}); ind != 0 || ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 0, false, ind, ok) - } - if ind, ok := c.ReverseIndexOf(subTree, []byte{0}); ind != 8 || ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 8, false, ind, ok) - } - if ind, ok := c.MirrorReverseIndexOf(subTree, []byte{0}); ind != 8 || ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 8, false, ind, ok) - } - if ind, ok := c.IndexOf(subTree, []byte{9}); ind != 8 || ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 8, false, ind, ok) - } - if ind, ok := c.MirrorIndexOf(subTree, []byte{9}); ind != 8 || ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 8, false, ind, ok) - } - if ind, ok := c.IndexOf(subTree, []byte{0}); ind != 0 || ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 0, false, ind, ok) - } - if ind, ok := c.MirrorIndexOf(subTree, []byte{0}); ind != 0 || ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 0, false, ind, ok) - } - for i := byte(1); i < 9; i++ { - if ind, ok := c.MirrorIndexOf(subTree, []byte{i}); ind != int(i-1) || !ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", i-1, true, ind, ok) - } - if ind, ok := c.MirrorReverseIndexOf(subTree, []byte{i}); ind != int(8-i) || !ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 9-i, true, ind, ok) - } - if ind, ok := c.IndexOf(subTree, []byte{i}); ind != int(i-1) || !ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", i-1, true, ind, ok) - } - if ind, ok := c.ReverseIndexOf(subTree, []byte{i}); ind != int(8-i) || !ok { - t.Errorf("wrong index! wanted %v, %v but got %v, %v", 9-i, true, ind, ok) - } - } + var key []byte + var value []byte + subTree := []byte("ko") + c.SubAddConfiguration(subTree, "mirrored", "yes") + for i := byte(1); i < 9; i++ { + key = []byte{i} + value = []byte{9 - i} + c.SSubPut(subTree, key, value) + } + assertMirrored(t, dhashes, c, subTree) + if ind, ok := c.ReverseIndexOf(subTree, []byte{9}); ind != 0 || ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 0, false, ind, ok) + } + if ind, ok := c.MirrorReverseIndexOf(subTree, []byte{9}); ind != 0 || ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 0, false, ind, ok) + } + if ind, ok := c.ReverseIndexOf(subTree, []byte{0}); ind != 8 || ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 8, false, ind, ok) + } + if ind, ok := c.MirrorReverseIndexOf(subTree, []byte{0}); ind != 8 || ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 8, false, ind, ok) + } + if ind, ok := c.IndexOf(subTree, []byte{9}); ind != 8 || ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 8, false, ind, ok) + } + if ind, ok := c.MirrorIndexOf(subTree, []byte{9}); ind != 8 || ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 8, false, ind, ok) + } + if ind, ok := c.IndexOf(subTree, []byte{0}); ind != 0 || ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 0, false, ind, ok) + } + if ind, ok := c.MirrorIndexOf(subTree, []byte{0}); ind != 0 || ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 0, false, ind, ok) + } + for i := byte(1); i < 9; i++ { + if ind, ok := c.MirrorIndexOf(subTree, []byte{i}); ind != int(i-1) || !ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", i-1, true, ind, ok) + } + if ind, ok := c.MirrorReverseIndexOf(subTree, []byte{i}); ind != int(8-i) || !ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 9-i, true, ind, ok) + } + if ind, ok := c.IndexOf(subTree, []byte{i}); ind != int(i-1) || !ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", i-1, true, ind, ok) + } + if ind, ok := c.ReverseIndexOf(subTree, []byte{i}); ind != int(8-i) || !ok { + t.Errorf("wrong index! wanted %v, %v but got %v, %v", 9-i, true, ind, ok) + } + } } func testSubClear(t *testing.T, c testClient) { - var key []byte - var value []byte - subTree := []byte("apa") - for i := 0; i < 10; i++ { - key = murmur.HashString(fmt.Sprint(i)) - value = murmur.HashString(fmt.Sprint(i)) - c.SSubPut(subTree, key, value) - } - if c.SubSize(subTree) != 10 { - t.Errorf("wrong size") - } - c.SSubClear(subTree) - if c.SubSize(subTree) != 0 { - t.Errorf("wrong size") - } + var key []byte + var value []byte + subTree := []byte("apa") + for i := 0; i < 10; i++ { + key = murmur.HashString(fmt.Sprint(i)) + value = murmur.HashString(fmt.Sprint(i)) + c.SSubPut(subTree, key, value) + } + if c.SubSize(subTree) != 10 { + t.Errorf("wrong size") + } + c.SSubClear(subTree) + if c.SubSize(subTree) != 0 { + t.Errorf("wrong size") + } } func testGetPutDel(t *testing.T, c testClient) { - var key []byte - var value []byte - for i := 0; i < 1000; i++ { - key = murmur.HashString(fmt.Sprint(i)) - value = murmur.HashString(fmt.Sprint(i)) - if v, e := c.Get(key); v != nil || e { - t.Errorf("shouldn't exist") - } - c.SPut(key, value) - if v, e := c.Get(key); bytes.Compare(value, v) != 0 || !e { - t.Fatalf("should exist, but got %v => %v, %v", key, v, e) - } - c.SDel(key) - if v, e := c.Get(key); v != nil || e { - t.Errorf("shouldn't exist, but got %v => %v, %v", key, v, e) - } - } + var key []byte + var value []byte + for i := 0; i < 1000; i++ { + key = murmur.HashString(fmt.Sprint(i)) + value = murmur.HashString(fmt.Sprint(i)) + if v, e := c.Get(key); v != nil || e { + t.Errorf("shouldn't exist") + } + c.SPut(key, value) + if v, e := c.Get(key); bytes.Compare(value, v) != 0 || !e { + t.Fatalf("should exist, but got %v => %v, %v", key, v, e) + } + c.SDel(key) + if v, e := c.Get(key); v != nil || e { + t.Errorf("shouldn't exist, but got %v => %v, %v", key, v, e) + } + } } diff --git a/dhash/dhash.go b/dhash/dhash.go index 20acf45..e2c9a0c 100644 --- a/dhash/dhash.go +++ b/dhash/dhash.go @@ -1,16 +1,17 @@ package dhash import ( - "bytes" - "fmt" - "github.com/zond/god/common" - "github.com/zond/god/discord" - "github.com/zond/god/murmur" - "github.com/zond/god/radix" - "github.com/zond/god/timenet" - "sync" - "sync/atomic" - "time" + "bytes" + "fmt" + "sync" + "sync/atomic" + "time" + + "github.com/zond/god/common" + "github.com/zond/god/discord" + "github.com/zond/god/murmur" + "github.com/zond/god/radix" + "github.com/zond/god/timenet" ) // SyncListener is a function listening for sync events where one dhash.Node has pushed items to, and pulled items from, another dhash.Node. @@ -26,392 +27,395 @@ type MigrateListener func(dhash *Node, source, destination []byte) (keep bool) type CommListener func(comm Comm) (keep bool) type commListenerContainer struct { - channel chan Comm - listener CommListener - node *Node + channel chan Comm + listener CommListener + node *Node } func (self *commListenerContainer) run() { - for self.listener(<-self.channel) { - } - self.node.removeCommListener(self) + for self.listener(<-self.channel) { + } + self.node.removeCommListener(self) } // Comm contains metadata about one communication between two dhash.Nodes. type Comm struct { - Source common.Remote - Destination common.Remote - Key []byte - SubKey []byte - Type string + Source common.Remote + Destination common.Remote + Key []byte + SubKey []byte + Type string } const ( - syncInterval = time.Second - migrateHysteresis = 1.5 - migrateWaitFactor = 2 + syncInterval = time.Second + migrateHysteresis = 1.5 + migrateWaitFactor = 2 ) const ( - created = iota - started - stopped + created = iota + started + stopped ) -// Node is a node in the database. It contains a discord.Node containing routing and rpc functionality, +// Node is a node in the database. It contains a discord.Node containing routing and rpc functionality, // a timenet.Timer containing time synchronization functionality and a radix.Tree containing the actual data. type Node struct { - state int32 - lastSync int64 - lastMigrate int64 - lastReroute int64 - lock *sync.RWMutex - syncListeners []SyncListener - cleanListeners []CleanListener - migrateListeners []MigrateListener - commListeners map[*commListenerContainer]bool - nCommListeners int32 - node *discord.Node - timer *timenet.Timer - tree *radix.Tree + lastSync int64 + lastMigrate int64 + lastReroute int64 + state int32 + lock *sync.RWMutex + syncListeners []SyncListener + cleanListeners []CleanListener + migrateListeners []MigrateListener + commListeners map[*commListenerContainer]bool + nCommListeners int32 + node *discord.Node + timer *timenet.Timer + tree *radix.Tree } -func NewNode(addr string) *Node { - return NewNodeDir(addr, addr) +func NewNode(listenAddr, broadcastAddr string) *Node { + return NewNodeDir(listenAddr, broadcastAddr, broadcastAddr) } -// NewNode will return a dhash.Node publishing itself on the given address. -func NewNodeDir(addr, dir string) (result *Node) { - result = &Node{ - node: discord.NewNode(addr), - lock: new(sync.RWMutex), - commListeners: make(map[*commListenerContainer]bool), - state: created, - } - result.node.AddCommListener(func(source, dest common.Remote, typ string) bool { - if result.hasState(started) { - if result.hasCommListeners() { - result.triggerCommListeners(Comm{ - Source: source, - Destination: dest, - Type: typ, - }) - } - } - return !result.hasState(stopped) - }) - result.AddChangeListener(func(r *common.Ring) bool { - atomic.StoreInt64(&result.lastReroute, time.Now().UnixNano()) - return true - }) - result.timer = timenet.NewTimer((*dhashPeerProducer)(result)) - result.tree = radix.NewTreeTimer(result.timer) - if dir != "" { - result.tree.Log(dir).Restore() - } - result.node.Export("Timenet", (*timerServer)(result.timer)) - result.node.Export("DHash", (*dhashServer)(result)) - result.node.Export("HashTree", (*hashTreeServer)(result)) - return +// NewNodeDir will return a dhash.Node publishing itself on the given address. +func NewNodeDir(listenAddr, broadcastAddr, dir string) (result *Node) { + result = &Node{ + node: discord.NewNode(listenAddr, broadcastAddr), + lock: new(sync.RWMutex), + commListeners: make(map[*commListenerContainer]bool), + state: created, + } + result.node.AddCommListener(func(source, dest common.Remote, typ string) bool { + if result.hasState(started) { + if result.hasCommListeners() { + result.triggerCommListeners(Comm{ + Source: source, + Destination: dest, + Type: typ, + }) + } + } + return !result.hasState(stopped) + }) + result.AddChangeListener(func(r *common.Ring) bool { + atomic.StoreInt64(&result.lastReroute, time.Now().UnixNano()) + return true + }) + result.timer = timenet.NewTimer((*dhashPeerProducer)(result)) + result.tree = radix.NewTreeTimer(result.timer) + if dir != "" { + result.tree.Log(dir).Restore() + } + result.node.Export("Timenet", (*timerServer)(result.timer)) + result.node.Export("DHash", (*dhashServer)(result)) + result.node.Export("HashTree", (*hashTreeServer)(result)) + return } func (self *Node) AddCommListener(l CommListener) { - self.lock.Lock() - defer self.lock.Unlock() - newListener := &commListenerContainer{ - listener: l, - channel: make(chan Comm), - node: self, - } - atomic.AddInt32(&self.nCommListeners, 1) - self.commListeners[newListener] = true - go newListener.run() + self.lock.Lock() + defer self.lock.Unlock() + newListener := &commListenerContainer{ + listener: l, + channel: make(chan Comm), + node: self, + } + atomic.AddInt32(&self.nCommListeners, 1) + self.commListeners[newListener] = true + go newListener.run() } func (self *Node) removeCommListener(lc *commListenerContainer) { - self.lock.Lock() - defer self.lock.Unlock() - if _, ok := self.commListeners[lc]; ok { - atomic.AddInt32(&self.nCommListeners, -1) - } - delete(self.commListeners, lc) - close(lc.channel) + self.lock.Lock() + defer self.lock.Unlock() + if _, ok := self.commListeners[lc]; ok { + atomic.AddInt32(&self.nCommListeners, -1) + } + delete(self.commListeners, lc) + close(lc.channel) } func (self *Node) hasCommListeners() bool { - return atomic.LoadInt32(&self.nCommListeners) > 0 + return atomic.LoadInt32(&self.nCommListeners) > 0 } func (self *Node) triggerCommListeners(comm Comm) { - self.lock.RLock() - for lc, _ := range self.commListeners { - self.lock.RUnlock() - select { - case lc.channel <- comm: - default: - } - self.lock.RLock() - } - self.lock.RUnlock() + self.lock.RLock() + for lc, _ := range self.commListeners { + self.lock.RUnlock() + select { + case lc.channel <- comm: + default: + } + self.lock.RLock() + } + self.lock.RUnlock() } func (self *Node) AddCleanListener(l CleanListener) { - self.lock.Lock() - defer self.lock.Unlock() - self.cleanListeners = append(self.cleanListeners, l) + self.lock.Lock() + defer self.lock.Unlock() + self.cleanListeners = append(self.cleanListeners, l) } func (self *Node) AddMigrateListener(l MigrateListener) { - self.lock.Lock() - defer self.lock.Unlock() - self.migrateListeners = append(self.migrateListeners, l) + self.lock.Lock() + defer self.lock.Unlock() + self.migrateListeners = append(self.migrateListeners, l) } func (self *Node) AddSyncListener(l SyncListener) { - self.lock.Lock() - defer self.lock.Unlock() - self.syncListeners = append(self.syncListeners, l) + self.lock.Lock() + defer self.lock.Unlock() + self.syncListeners = append(self.syncListeners, l) } func (self *Node) hasState(s int32) bool { - return atomic.LoadInt32(&self.state) == s + return atomic.LoadInt32(&self.state) == s } func (self *Node) changeState(old, neu int32) bool { - return atomic.CompareAndSwapInt32(&self.state, old, neu) + return atomic.CompareAndSwapInt32(&self.state, old, neu) +} +func (self *Node) GetListenAddr() string { + return self.node.GetListenAddr() } -func (self *Node) GetAddr() string { - return self.node.GetAddr() +func (self *Node) GetBroadcastAddr() string { + return self.node.GetBroadcastAddr() } func (self *Node) AddChangeListener(f common.RingChangeListener) { - self.node.AddChangeListener(f) + self.node.AddChangeListener(f) } // Stop will shut down this dhash.Node, including its discord.Node and timenet.Timer, permanently. func (self *Node) Stop() { - if self.changeState(started, stopped) { - self.node.Stop() - self.timer.Stop() - } + if self.changeState(started, stopped) { + self.node.Stop() + self.timer.Stop() + } } // Start will spin up this dhash.Node, including its discord.Node and timenet.Timer. // It will also start the sync, clean and migrate jobs. func (self *Node) Start() (err error) { - if !self.changeState(created, started) { - return fmt.Errorf("%v can only be started when in state 'created'", self) - } - if err = self.node.Start(); err != nil { - return - } - self.timer.Start() - go self.syncPeriodically() - go self.cleanPeriodically() - go self.migratePeriodically() - self.startJson() - return + if !self.changeState(created, started) { + return fmt.Errorf("%v can only be started when in state 'created'", self) + } + if err = self.node.Start(); err != nil { + return + } + self.timer.Start() + go self.syncPeriodically() + go self.cleanPeriodically() + go self.migratePeriodically() + self.startJson() + return } func (self *Node) triggerSyncListeners(source, dest common.Remote, pulled, pushed int) { - self.lock.RLock() - newListeners := make([]SyncListener, 0, len(self.syncListeners)) - for _, l := range self.syncListeners { - self.lock.RUnlock() - if l(source, dest, pulled, pushed) { - newListeners = append(newListeners, l) - } - self.lock.RLock() - } - self.lock.RUnlock() - self.lock.Lock() - defer self.lock.Unlock() - self.syncListeners = newListeners + self.lock.RLock() + newListeners := make([]SyncListener, 0, len(self.syncListeners)) + for _, l := range self.syncListeners { + self.lock.RUnlock() + if l(source, dest, pulled, pushed) { + newListeners = append(newListeners, l) + } + self.lock.RLock() + } + self.lock.RUnlock() + self.lock.Lock() + defer self.lock.Unlock() + self.syncListeners = newListeners } func (self *Node) sync() { - var pulled int - var pushed int - selfRemote := self.node.Remote() - nextSuccessor := self.node.GetSuccessor() - for i := 0; i < self.node.Redundancy()-1; i++ { - myPos := self.node.GetPosition() - remoteHash := remoteHashTree{ - source: selfRemote, - destination: nextSuccessor, - node: self, - } - pushed = radix.NewSync(self.tree, remoteHash).From(self.node.GetPredecessor().Pos).To(myPos).Run().PutCount() - pulled = radix.NewSync(remoteHash, self.tree).From(self.node.GetPredecessor().Pos).To(myPos).Run().PutCount() - if pushed != 0 || pulled != 0 { - self.triggerSyncListeners(selfRemote, nextSuccessor, pulled, pushed) - } - nextSuccessor = self.node.GetSuccessorForRemote(nextSuccessor) - } + var pulled int + var pushed int + selfRemote := self.node.Remote() + nextSuccessor := self.node.GetSuccessor() + for i := 0; i < self.node.Redundancy()-1; i++ { + myPos := self.node.GetPosition() + remoteHash := remoteHashTree{ + source: selfRemote, + destination: nextSuccessor, + node: self, + } + pushed = radix.NewSync(self.tree, remoteHash).From(self.node.GetPredecessor().Pos).To(myPos).Run().PutCount() + pulled = radix.NewSync(remoteHash, self.tree).From(self.node.GetPredecessor().Pos).To(myPos).Run().PutCount() + if pushed != 0 || pulled != 0 { + self.triggerSyncListeners(selfRemote, nextSuccessor, pulled, pushed) + } + nextSuccessor = self.node.GetSuccessorForRemote(nextSuccessor) + } } func (self *Node) syncPeriodically() { - for self.hasState(started) { - self.sync() - time.Sleep(syncInterval) - } + for self.hasState(started) { + self.sync() + time.Sleep(syncInterval) + } } func (self *Node) cleanPeriodically() { - for self.hasState(started) { - self.clean() - time.Sleep(syncInterval) - } + for self.hasState(started) { + self.clean() + time.Sleep(syncInterval) + } } func (self *Node) triggerMigrateListeners(oldPos, newPos []byte) { - self.lock.RLock() - newListeners := make([]MigrateListener, 0, len(self.migrateListeners)) - for _, l := range self.migrateListeners { - self.lock.RUnlock() - if l(self, oldPos, newPos) { - newListeners = append(newListeners, l) - } - self.lock.RLock() - } - self.lock.RUnlock() - self.lock.Lock() - defer self.lock.Unlock() - self.migrateListeners = newListeners + self.lock.RLock() + newListeners := make([]MigrateListener, 0, len(self.migrateListeners)) + for _, l := range self.migrateListeners { + self.lock.RUnlock() + if l(self, oldPos, newPos) { + newListeners = append(newListeners, l) + } + self.lock.RLock() + } + self.lock.RUnlock() + self.lock.Lock() + defer self.lock.Unlock() + self.migrateListeners = newListeners } func (self *Node) changePosition(newPos []byte) { - for len(newPos) < murmur.Size { - newPos = append(newPos, 0) - } - oldPos := self.node.GetPosition() - if bytes.Compare(newPos, oldPos) != 0 { - self.node.SetPosition(newPos) - atomic.StoreInt64(&self.lastMigrate, time.Now().UnixNano()) - self.triggerMigrateListeners(oldPos, newPos) - } + for len(newPos) < murmur.Size { + newPos = append(newPos, 0) + } + oldPos := self.node.GetPosition() + if bytes.Compare(newPos, oldPos) != 0 { + self.node.SetPosition(newPos) + atomic.StoreInt64(&self.lastMigrate, time.Now().UnixNano()) + self.triggerMigrateListeners(oldPos, newPos) + } } func (self *Node) isLeader() bool { - return bytes.Compare(self.node.GetPredecessor().Pos, self.node.GetPosition()) > 0 + return bytes.Compare(self.node.GetPredecessor().Pos, self.node.GetPosition()) > 0 } func (self *Node) migratePeriodically() { - for self.hasState(started) { - self.migrate() - time.Sleep(syncInterval) - } + for self.hasState(started) { + self.migrate() + time.Sleep(syncInterval) + } } func (self *Node) migrate() { - lastAllowedChange := time.Now().Add(-1 * migrateWaitFactor * syncInterval).UnixNano() - if lastAllowedChange > common.Max64(atomic.LoadInt64(&self.lastSync), atomic.LoadInt64(&self.lastReroute), atomic.LoadInt64(&self.lastMigrate)) { - var succSize int - succ := self.node.GetSuccessor() - if err := succ.Call("DHash.Owned", 0, &succSize); err != nil { - self.node.RemoveNode(succ) - } else { - mySize := self.Owned() - if mySize > 10 && float64(mySize) > float64(succSize)*migrateHysteresis { - wantedDelta := (mySize - succSize) / 2 - var existed bool - var wantedPos []byte - pred := self.node.GetPredecessor() - if bytes.Compare(pred.Pos, self.node.GetPosition()) < 1 { - if wantedPos, existed = self.tree.NextMarkerIndex(self.tree.RealSizeBetween(nil, self.node.GetPosition(), true, false) - wantedDelta); !existed { - return - } - } else { - ownedAfterNil := self.tree.RealSizeBetween(nil, succ.Pos, true, false) - if ownedAfterNil > wantedDelta { - if wantedPos, existed = self.tree.NextMarkerIndex(ownedAfterNil - wantedDelta); !existed { - return - } - } else { - if wantedPos, existed = self.tree.NextMarkerIndex(self.tree.RealSize() + ownedAfterNil - wantedDelta); !existed { - return - } - } - } - if common.BetweenIE(wantedPos, self.node.GetPredecessor().Pos, self.node.GetPosition()) { - self.changePosition(wantedPos) - } - } - } - } + lastAllowedChange := time.Now().Add(-1 * migrateWaitFactor * syncInterval).UnixNano() + if lastAllowedChange > common.Max64(atomic.LoadInt64(&self.lastSync), atomic.LoadInt64(&self.lastReroute), atomic.LoadInt64(&self.lastMigrate)) { + var succSize int + succ := self.node.GetSuccessor() + if err := succ.Call("DHash.Owned", 0, &succSize); err != nil { + self.node.RemoveNode(succ) + } else { + mySize := self.Owned() + if mySize > 10 && float64(mySize) > float64(succSize)*migrateHysteresis { + wantedDelta := (mySize - succSize) / 2 + var existed bool + var wantedPos []byte + pred := self.node.GetPredecessor() + if bytes.Compare(pred.Pos, self.node.GetPosition()) < 1 { + if wantedPos, existed = self.tree.NextMarkerIndex(self.tree.RealSizeBetween(nil, self.node.GetPosition(), true, false) - wantedDelta); !existed { + return + } + } else { + ownedAfterNil := self.tree.RealSizeBetween(nil, succ.Pos, true, false) + if ownedAfterNil > wantedDelta { + if wantedPos, existed = self.tree.NextMarkerIndex(ownedAfterNil - wantedDelta); !existed { + return + } + } else { + if wantedPos, existed = self.tree.NextMarkerIndex(self.tree.RealSize() + ownedAfterNil - wantedDelta); !existed { + return + } + } + } + if common.BetweenIE(wantedPos, self.node.GetPredecessor().Pos, self.node.GetPosition()) { + self.changePosition(wantedPos) + } + } + } + } } func (self *Node) circularNext(key []byte) (nextKey []byte, existed bool) { - if nextKey, existed = self.tree.NextMarker(key); existed { - return - } - nextKey = make([]byte, murmur.Size) - if _, _, existed = self.tree.Get(nextKey); existed { - return - } - nextKey, existed = self.tree.NextMarker(nextKey) - return + if nextKey, existed = self.tree.NextMarker(key); existed { + return + } + nextKey = make([]byte, murmur.Size) + if _, _, existed = self.tree.Get(nextKey); existed { + return + } + nextKey, existed = self.tree.NextMarker(nextKey) + return } func (self *Node) owners(key []byte) (owners common.Remotes, isOwner bool) { - owners = append(owners, self.node.GetSuccessorFor(key)) - if owners[0].Addr == self.node.GetAddr() { - isOwner = true - } - for i := 1; i < self.node.Redundancy(); i++ { - owners = append(owners, self.node.GetSuccessorForRemote(owners[i-1])) - if owners[i].Addr == self.node.GetAddr() { - isOwner = true - } - } - return + owners = append(owners, self.node.GetSuccessorFor(key)) + if owners[0].Addr == self.node.GetBroadcastAddr() { + isOwner = true + } + for i := 1; i < self.node.Redundancy(); i++ { + owners = append(owners, self.node.GetSuccessorForRemote(owners[i-1])) + if owners[i].Addr == self.node.GetBroadcastAddr() { + isOwner = true + } + } + return } func (self *Node) triggerCleanListeners(source, dest common.Remote, cleaned, pushed int) { - self.lock.RLock() - newListeners := make([]CleanListener, 0, len(self.cleanListeners)) - for _, l := range self.cleanListeners { - self.lock.RUnlock() - if l(source, dest, cleaned, pushed) { - newListeners = append(newListeners, l) - } - self.lock.RLock() - } - self.lock.RUnlock() - self.lock.Lock() - defer self.lock.Unlock() - self.cleanListeners = newListeners + self.lock.RLock() + newListeners := make([]CleanListener, 0, len(self.cleanListeners)) + for _, l := range self.cleanListeners { + self.lock.RUnlock() + if l(source, dest, cleaned, pushed) { + newListeners = append(newListeners, l) + } + self.lock.RLock() + } + self.lock.RUnlock() + self.lock.Lock() + defer self.lock.Unlock() + self.cleanListeners = newListeners } func (self *Node) clean() { - selfRemote := self.node.Remote() - var cleaned int - var pushed int - if nextKey, existed := self.circularNext(self.node.GetPosition()); existed { - if owners, isOwner := self.owners(nextKey); !isOwner { - var sync *radix.Sync - for index, owner := range owners { - sync = radix.NewSync(self.tree, remoteHashTree{ - source: selfRemote, - destination: owner, - node: self, - }).From(nextKey).To(owners[0].Pos) - if index == len(owners)-2 { - sync.Destroy() - } - sync.Run() - cleaned = sync.DelCount() - pushed = sync.PutCount() - if cleaned != 0 || pushed != 0 { - self.triggerCleanListeners(selfRemote, owner, cleaned, pushed) - } - } - } - } + selfRemote := self.node.Remote() + var cleaned int + var pushed int + if nextKey, existed := self.circularNext(self.node.GetPosition()); existed { + if owners, isOwner := self.owners(nextKey); !isOwner { + var sync *radix.Sync + for index, owner := range owners { + sync = radix.NewSync(self.tree, remoteHashTree{ + source: selfRemote, + destination: owner, + node: self, + }).From(nextKey).To(owners[0].Pos) + if index == len(owners)-2 { + sync.Destroy() + } + sync.Run() + cleaned = sync.DelCount() + pushed = sync.PutCount() + if cleaned != 0 || pushed != 0 { + self.triggerCleanListeners(selfRemote, owner, cleaned, pushed) + } + } + } + } } func (self *Node) MustStart() *Node { - if err := self.Start(); err != nil { - panic(err) - } - return self + if err := self.Start(); err != nil { + panic(err) + } + return self } func (self *Node) MustJoin(addr string) { - self.timer.Conform(remotePeer(common.Remote{Addr: addr})) - self.node.MustJoin(addr) + self.timer.Conform(remotePeer(common.Remote{Addr: addr})) + self.node.MustJoin(addr) } func (self *Node) Time() time.Time { - return time.Unix(0, self.timer.ContinuousTime()) + return time.Unix(0, self.timer.ContinuousTime()) } // Owned returns the number of items, including tombstones, that this node has responsibility for. func (self *Node) Owned() int { - pred := self.node.GetPredecessor() - me := self.node.Remote() - cmp := bytes.Compare(pred.Pos, me.Pos) - if cmp < 0 { - return self.tree.RealSizeBetween(pred.Pos, me.Pos, true, false) - } else if cmp > 0 { - return self.tree.RealSizeBetween(pred.Pos, nil, true, false) + self.tree.RealSizeBetween(nil, me.Pos, true, false) - } - if pred.Less(me) { - return 0 - } - return self.tree.RealSize() + pred := self.node.GetPredecessor() + me := self.node.Remote() + cmp := bytes.Compare(pred.Pos, me.Pos) + if cmp < 0 { + return self.tree.RealSizeBetween(pred.Pos, me.Pos, true, false) + } else if cmp > 0 { + return self.tree.RealSizeBetween(pred.Pos, nil, true, false) + self.tree.RealSizeBetween(nil, me.Pos, true, false) + } + if pred.Less(me) { + return 0 + } + return self.tree.RealSize() } diff --git a/dhash/dhash_server.go b/dhash/dhash_server.go index a7e4d4a..5c2aeb1 100644 --- a/dhash/dhash_server.go +++ b/dhash/dhash_server.go @@ -1,193 +1,193 @@ package dhash import ( - "github.com/zond/god/common" - "github.com/zond/god/setop" + "github.com/zond/god/common" + "github.com/zond/setop" ) type dhashServer Node func (self *dhashServer) Clear(x int, y *int) error { - (*Node)(self).Clear() - return nil + (*Node)(self).Clear() + return nil } func (self *dhashServer) SlaveSubPut(data common.Item, x *int) error { - return (*Node)(self).subPut(data) + return (*Node)(self).subPut(data) } func (self *dhashServer) SlaveSubClear(data common.Item, x *int) error { - return (*Node)(self).subClear(data) + return (*Node)(self).subClear(data) } func (self *dhashServer) SlaveSubDel(data common.Item, x *int) error { - return (*Node)(self).subDel(data) + return (*Node)(self).subDel(data) } func (self *dhashServer) SlaveDel(data common.Item, x *int) error { - return (*Node)(self).del(data) + return (*Node)(self).del(data) } func (self *dhashServer) SlavePut(data common.Item, x *int) error { - return (*Node)(self).put(data) + return (*Node)(self).put(data) } func (self *dhashServer) SubDel(data common.Item, x *int) error { - return (*Node)(self).SubDel(data) + return (*Node)(self).SubDel(data) } func (self *dhashServer) SubClear(data common.Item, x *int) error { - return (*Node)(self).SubClear(data) + return (*Node)(self).SubClear(data) } func (self *dhashServer) SubPut(data common.Item, x *int) error { - return (*Node)(self).SubPut(data) + return (*Node)(self).SubPut(data) } func (self *dhashServer) Del(data common.Item, x *int) error { - return (*Node)(self).Del(data) + return (*Node)(self).Del(data) } func (self *dhashServer) Put(data common.Item, x *int) error { - return (*Node)(self).Put(data) + return (*Node)(self).Put(data) } func (self *dhashServer) RingHash(x int, result *[]byte) error { - return (*Node)(self).RingHash(x, result) + return (*Node)(self).RingHash(x, result) } func (self *dhashServer) MirrorCount(r common.Range, result *int) error { - return (*Node)(self).MirrorCount(r, result) + return (*Node)(self).MirrorCount(r, result) } func (self *dhashServer) Count(r common.Range, result *int) error { - return (*Node)(self).Count(r, result) + return (*Node)(self).Count(r, result) } func (self *dhashServer) Next(data common.Item, result *common.Item) error { - return (*Node)(self).Next(data, result) + return (*Node)(self).Next(data, result) } func (self *dhashServer) Prev(data common.Item, result *common.Item) error { - return (*Node)(self).Prev(data, result) + return (*Node)(self).Prev(data, result) } func (self *dhashServer) SubGet(data common.Item, result *common.Item) error { - return (*Node)(self).SubGet(data, result) + return (*Node)(self).SubGet(data, result) } func (self *dhashServer) Get(data common.Item, result *common.Item) error { - return (*Node)(self).Get(data, result) + return (*Node)(self).Get(data, result) } func (self *dhashServer) Size(x int, result *int) error { - *result = (*Node)(self).Size() - return nil + *result = (*Node)(self).Size() + return nil } func (self *dhashServer) SubSize(key []byte, result *int) error { - return (*Node)(self).SubSize(key, result) + return (*Node)(self).SubSize(key, result) } func (self *dhashServer) Owned(x int, result *int) error { - *result = (*Node)(self).Owned() - return nil + *result = (*Node)(self).Owned() + return nil } func (self *dhashServer) Describe(x int, result *common.DHashDescription) error { - *result = (*Node)(self).Description() - return nil + *result = (*Node)(self).Description() + return nil } func (self *dhashServer) DescribeTree(x int, result *string) error { - *result = (*Node)(self).DescribeTree() - return nil + *result = (*Node)(self).DescribeTree() + return nil } func (self *dhashServer) MirrorPrevIndex(data common.Item, result *common.Item) error { - return (*Node)(self).MirrorPrevIndex(data, result) + return (*Node)(self).MirrorPrevIndex(data, result) } func (self *dhashServer) MirrorNextIndex(data common.Item, result *common.Item) error { - return (*Node)(self).MirrorNextIndex(data, result) + return (*Node)(self).MirrorNextIndex(data, result) } func (self *dhashServer) PrevIndex(data common.Item, result *common.Item) error { - return (*Node)(self).PrevIndex(data, result) + return (*Node)(self).PrevIndex(data, result) } func (self *dhashServer) NextIndex(data common.Item, result *common.Item) error { - return (*Node)(self).NextIndex(data, result) + return (*Node)(self).NextIndex(data, result) } func (self *dhashServer) MirrorReverseIndexOf(data common.Item, result *common.Index) error { - return (*Node)(self).MirrorReverseIndexOf(data, result) + return (*Node)(self).MirrorReverseIndexOf(data, result) } func (self *dhashServer) MirrorIndexOf(data common.Item, result *common.Index) error { - return (*Node)(self).MirrorIndexOf(data, result) + return (*Node)(self).MirrorIndexOf(data, result) } func (self *dhashServer) ReverseIndexOf(data common.Item, result *common.Index) error { - return (*Node)(self).ReverseIndexOf(data, result) + return (*Node)(self).ReverseIndexOf(data, result) } func (self *dhashServer) IndexOf(data common.Item, result *common.Index) error { - return (*Node)(self).IndexOf(data, result) + return (*Node)(self).IndexOf(data, result) } func (self *dhashServer) SubMirrorPrev(data common.Item, result *common.Item) error { - return (*Node)(self).SubMirrorPrev(data, result) + return (*Node)(self).SubMirrorPrev(data, result) } func (self *dhashServer) SubMirrorNext(data common.Item, result *common.Item) error { - return (*Node)(self).SubMirrorNext(data, result) + return (*Node)(self).SubMirrorNext(data, result) } func (self *dhashServer) SubPrev(data common.Item, result *common.Item) error { - return (*Node)(self).SubPrev(data, result) + return (*Node)(self).SubPrev(data, result) } func (self *dhashServer) SubNext(data common.Item, result *common.Item) error { - return (*Node)(self).SubNext(data, result) + return (*Node)(self).SubNext(data, result) } func (self *dhashServer) MirrorFirst(data common.Item, result *common.Item) error { - return (*Node)(self).MirrorFirst(data, result) + return (*Node)(self).MirrorFirst(data, result) } func (self *dhashServer) MirrorLast(data common.Item, result *common.Item) error { - return (*Node)(self).MirrorLast(data, result) + return (*Node)(self).MirrorLast(data, result) } func (self *dhashServer) First(data common.Item, result *common.Item) error { - return (*Node)(self).First(data, result) + return (*Node)(self).First(data, result) } func (self *dhashServer) Last(data common.Item, result *common.Item) error { - return (*Node)(self).Last(data, result) + return (*Node)(self).Last(data, result) } func (self *dhashServer) MirrorReverseSlice(r common.Range, result *[]common.Item) error { - return (*Node)(self).MirrorReverseSlice(r, result) + return (*Node)(self).MirrorReverseSlice(r, result) } func (self *dhashServer) MirrorSlice(r common.Range, result *[]common.Item) error { - return (*Node)(self).MirrorSlice(r, result) + return (*Node)(self).MirrorSlice(r, result) } func (self *dhashServer) MirrorSliceIndex(r common.Range, result *[]common.Item) error { - return (*Node)(self).MirrorSliceIndex(r, result) + return (*Node)(self).MirrorSliceIndex(r, result) } func (self *dhashServer) MirrorReverseSliceIndex(r common.Range, result *[]common.Item) error { - return (*Node)(self).MirrorReverseSliceIndex(r, result) + return (*Node)(self).MirrorReverseSliceIndex(r, result) } func (self *dhashServer) MirrorSliceLen(r common.Range, result *[]common.Item) error { - return (*Node)(self).MirrorSliceLen(r, result) + return (*Node)(self).MirrorSliceLen(r, result) } func (self *dhashServer) MirrorReverseSliceLen(r common.Range, result *[]common.Item) error { - return (*Node)(self).MirrorReverseSliceLen(r, result) + return (*Node)(self).MirrorReverseSliceLen(r, result) } func (self *dhashServer) ReverseSlice(r common.Range, result *[]common.Item) error { - return (*Node)(self).ReverseSlice(r, result) + return (*Node)(self).ReverseSlice(r, result) } func (self *dhashServer) Slice(r common.Range, result *[]common.Item) error { - return (*Node)(self).Slice(r, result) + return (*Node)(self).Slice(r, result) } func (self *dhashServer) SliceIndex(r common.Range, result *[]common.Item) error { - return (*Node)(self).SliceIndex(r, result) + return (*Node)(self).SliceIndex(r, result) } func (self *dhashServer) ReverseSliceIndex(r common.Range, result *[]common.Item) error { - return (*Node)(self).ReverseSliceIndex(r, result) + return (*Node)(self).ReverseSliceIndex(r, result) } func (self *dhashServer) SliceLen(r common.Range, result *[]common.Item) error { - return (*Node)(self).SliceLen(r, result) + return (*Node)(self).SliceLen(r, result) } func (self *dhashServer) ReverseSliceLen(r common.Range, result *[]common.Item) error { - return (*Node)(self).ReverseSliceLen(r, result) + return (*Node)(self).ReverseSliceLen(r, result) } func (self *dhashServer) SetExpression(expr setop.SetExpression, items *[]setop.SetOpResult) error { - return (*Node)(self).SetExpression(expr, items) + return (*Node)(self).SetExpression(expr, items) } func (self *dhashServer) AddConfiguration(c common.ConfItem, x *int) error { - (*Node)(self).AddConfiguration(c) - return nil + (*Node)(self).AddConfiguration(c) + return nil } func (self *dhashServer) SlaveSubAddConfiguration(c common.ConfItem, x *int) error { - (*Node)(self).subAddConfiguration(c) - return nil + (*Node)(self).subAddConfiguration(c) + return nil } func (self *dhashServer) SubAddConfiguration(c common.ConfItem, x *int) error { - (*Node)(self).SubAddConfiguration(c) - return nil + (*Node)(self).SubAddConfiguration(c) + return nil } func (self *dhashServer) Configuration(x int, result *common.Conf) error { - *result = common.Conf{} - (*result).Data, (*result).Timestamp = (*Node)(self).tree.Configuration() - return nil + *result = common.Conf{} + (*result).Data, (*result).Timestamp = (*Node)(self).tree.Configuration() + return nil } func (self *dhashServer) SubConfiguration(key []byte, result *common.Conf) error { - *result = common.Conf{TreeKey: key} - (*result).Data, (*result).Timestamp = (*Node)(self).tree.SubConfiguration(key) - return nil + *result = common.Conf{TreeKey: key} + (*result).Data, (*result).Timestamp = (*Node)(self).tree.SubConfiguration(key) + return nil } diff --git a/dhash/dhash_test.go b/dhash/dhash_test.go index 93cbedf..af94d8c 100644 --- a/dhash/dhash_test.go +++ b/dhash/dhash_test.go @@ -1,135 +1,135 @@ package dhash import ( - "bytes" - "fmt" - "github.com/zond/god/common" - "os" - "runtime" - "sort" - "testing" - "time" + "bytes" + "fmt" + "github.com/zond/god/common" + "os" + "runtime" + "sort" + "testing" + "time" ) type dhashAry []*Node func (self dhashAry) Less(i, j int) bool { - return self[i].node.Remote().Less(self[j].node.Remote()) + return self[i].node.Remote().Less(self[j].node.Remote()) } func (self dhashAry) Swap(i, j int) { - self[i], self[j] = self[j], self[i] + self[i], self[j] = self[j], self[i] } func (self dhashAry) Len() int { - return len(self) + return len(self) } func countHaving(t *testing.T, dhashes []*Node, key, value []byte) (result int) { - for _, d := range dhashes { - if foundValue, _, existed := d.tree.Get(key); existed && bytes.Compare(foundValue, value) == 0 { - result++ - } - } - return + for _, d := range dhashes { + if foundValue, _, existed := d.tree.Get(key); existed && bytes.Compare(foundValue, value) == 0 { + result++ + } + } + return } func testStartup(t *testing.T, n, port int) (dhashes []*Node) { - for i := 0; i < n; i++ { - os.RemoveAll(fmt.Sprintf("127.0.0.1:%v", port+i*2)) - } - dhashes = make([]*Node, n) - for i := 0; i < n; i++ { - dhashes[i] = NewNode(fmt.Sprintf("127.0.0.1:%v", port+i*2)) - dhashes[i].MustStart() - } - for i := 1; i < n; i++ { - dhashes[i].MustJoin(fmt.Sprintf("127.0.0.1:%v", port)) - } - common.AssertWithin(t, func() (string, bool) { - routes := make(map[string]bool) - for _, dhash := range dhashes { - routes[dhash.node.GetNodes().Describe()] = true - } - return fmt.Sprint(routes), len(routes) == 1 - }, time.Second*10) - return + for i := 0; i < n; i++ { + os.RemoveAll(fmt.Sprintf("127.0.0.1:%v", port+i*2)) + } + dhashes = make([]*Node, n) + for i := 0; i < n; i++ { + dhashes[i] = NewNode(fmt.Sprintf("127.0.0.1:%v", port+i*2), fmt.Sprintf("127.0.0.1:%v", port+i*2)) + dhashes[i].MustStart() + } + for i := 1; i < n; i++ { + dhashes[i].MustJoin(fmt.Sprintf("127.0.0.1:%v", port)) + } + common.AssertWithin(t, func() (string, bool) { + routes := make(map[string]bool) + for _, dhash := range dhashes { + routes[dhash.node.GetNodes().Describe()] = true + } + return fmt.Sprint(routes), len(routes) == 1 + }, time.Second*10) + return } func testSync(t *testing.T, dhashes []*Node) { - dhashes[0].tree.Put([]byte{3}, []byte{0}, 1) - common.AssertWithin(t, func() (string, bool) { - having := countHaving(t, dhashes, []byte{3}, []byte{0}) - return fmt.Sprint(having), having == common.Redundancy - }, time.Second*10) + dhashes[0].tree.Put([]byte{3}, []byte{0}, 1) + common.AssertWithin(t, func() (string, bool) { + having := countHaving(t, dhashes, []byte{3}, []byte{0}) + return fmt.Sprint(having), having == common.Redundancy + }, time.Second*10) } func testClean(t *testing.T, dhashes []*Node) { - for _, n := range dhashes { - n.tree.Put([]byte{1}, []byte{1}, 1) - } - common.AssertWithin(t, func() (string, bool) { - having := countHaving(t, dhashes, []byte{1}, []byte{1}) - return fmt.Sprint(having), having == common.Redundancy - }, time.Second*20) + for _, n := range dhashes { + n.tree.Put([]byte{1}, []byte{1}, 1) + } + common.AssertWithin(t, func() (string, bool) { + having := countHaving(t, dhashes, []byte{1}, []byte{1}) + return fmt.Sprint(having), having == common.Redundancy + }, time.Second*20) } func testPut(t *testing.T, dhashes []*Node) { - for index, n := range dhashes { - n.Put(common.Item{Key: []byte{byte(index + 100)}, Timestamp: 1, Value: []byte{byte(index + 100)}}) - } - common.AssertWithin(t, func() (string, bool) { - haves := make(map[int]bool) - for index, _ := range dhashes { - count := countHaving(t, dhashes, []byte{byte(index + 100)}, []byte{byte(index + 100)}) - haves[count] = true - } - return fmt.Sprint(haves), len(haves) == 1 && haves[common.Redundancy] == true - }, time.Second*10) + for index, n := range dhashes { + n.Put(common.Item{Key: []byte{byte(index + 100)}, Timestamp: 1, Value: []byte{byte(index + 100)}}) + } + common.AssertWithin(t, func() (string, bool) { + haves := make(map[int]bool) + for index, _ := range dhashes { + count := countHaving(t, dhashes, []byte{byte(index + 100)}, []byte{byte(index + 100)}) + haves[count] = true + } + return fmt.Sprint(haves), len(haves) == 1 && haves[common.Redundancy] == true + }, time.Second*10) } func testMigrate(t *testing.T, dhashes []*Node) { - for _, d := range dhashes { - d.Clear() - } - var item common.Item - for i := 0; i < 1000; i++ { - item.Key = []byte(fmt.Sprint(i)) - item.Value = []byte(fmt.Sprint(i)) - item.Timestamp = 1 - dhashes[0].Put(item) - } - common.AssertWithin(t, func() (string, bool) { - sum := 0 - status := new(bytes.Buffer) - ordered := dhashAry(dhashes) - sort.Sort(ordered) - lastOwned := ordered[len(ordered)-1].Owned() - ok := true - for _, d := range ordered { - sum += d.Owned() - fmt.Fprintf(status, "%v %v %v\n", d.node.GetAddr(), common.HexEncode(d.node.GetPosition()), d.Owned()) - if float64(lastOwned)/float64(d.Owned()) > migrateHysteresis { - ok = false - } - if d.Owned() == 0 { - ok = false - } - lastOwned = d.Owned() - } - return string(status.Bytes()), ok && sum == 1000 - }, time.Second*100) + for _, d := range dhashes { + d.Clear() + } + var item common.Item + for i := 0; i < 1000; i++ { + item.Key = []byte(fmt.Sprint(i)) + item.Value = []byte(fmt.Sprint(i)) + item.Timestamp = 1 + dhashes[0].Put(item) + } + common.AssertWithin(t, func() (string, bool) { + sum := 0 + status := new(bytes.Buffer) + ordered := dhashAry(dhashes) + sort.Sort(ordered) + lastOwned := ordered[len(ordered)-1].Owned() + ok := true + for _, d := range ordered { + sum += d.Owned() + fmt.Fprintf(status, "%v %v %v\n", d.node.GetBroadcastAddr(), common.HexEncode(d.node.GetPosition()), d.Owned()) + if float64(lastOwned)/float64(d.Owned()) > migrateHysteresis { + ok = false + } + if d.Owned() == 0 { + ok = false + } + lastOwned = d.Owned() + } + return string(status.Bytes()), ok && sum == 1000 + }, time.Second*100) } func stopServers(servers []*Node) { - for _, d := range servers { - d.Stop() - } + for _, d := range servers { + d.Stop() + } } func TestDHash(t *testing.T) { - runtime.GOMAXPROCS(runtime.NumCPU()) - dhashes := testStartup(t, 6, 10191) - testSync(t, dhashes) - testClean(t, dhashes) - testPut(t, dhashes) - testMigrate(t, dhashes) + runtime.GOMAXPROCS(runtime.NumCPU()) + dhashes := testStartup(t, 6, 10191) + testSync(t, dhashes) + testClean(t, dhashes) + testPut(t, dhashes) + testMigrate(t, dhashes) } diff --git a/dhash/hash_tree_server.go b/dhash/hash_tree_server.go index 17ad1c1..e5739f7 100644 --- a/dhash/hash_tree_server.go +++ b/dhash/hash_tree_server.go @@ -1,84 +1,84 @@ package dhash import ( - "github.com/zond/god/common" - "github.com/zond/god/radix" - "sync/atomic" - "time" + "github.com/zond/god/common" + "github.com/zond/god/radix" + "sync/atomic" + "time" ) type HashTreeItem struct { - Key []radix.Nibble - SubKey []radix.Nibble - Timestamp int64 - Expected int64 - Value []byte - Exists bool + Key []radix.Nibble + SubKey []radix.Nibble + Timestamp int64 + Expected int64 + Value []byte + Exists bool } type hashTreeServer Node func (self *hashTreeServer) Configure(conf common.Conf, x *int) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - (*Node)(self).tree.Configure(conf.Data, conf.Timestamp) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + (*Node)(self).tree.Configure(conf.Data, conf.Timestamp) + return nil } func (self *hashTreeServer) SubConfigure(conf common.Conf, x *int) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - (*Node)(self).tree.SubConfigure(conf.TreeKey, conf.Data, conf.Timestamp) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + (*Node)(self).tree.SubConfigure(conf.TreeKey, conf.Data, conf.Timestamp) + return nil } func (self *hashTreeServer) Hash(x int, result *[]byte) error { - *result = (*Node)(self).tree.Hash() - return nil + *result = (*Node)(self).tree.Hash() + return nil } func (self *hashTreeServer) Finger(key []radix.Nibble, result *radix.Print) error { - *result = *((*Node)(self).tree.Finger(key)) - return nil + *result = *((*Node)(self).tree.Finger(key)) + return nil } func (self *hashTreeServer) GetTimestamp(key []radix.Nibble, result *HashTreeItem) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - *result = HashTreeItem{Key: key} - result.Value, result.Timestamp, result.Exists = (*Node)(self).tree.GetTimestamp(key) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + *result = HashTreeItem{Key: key} + result.Value, result.Timestamp, result.Exists = (*Node)(self).tree.GetTimestamp(key) + return nil } func (self *hashTreeServer) PutTimestamp(data HashTreeItem, changed *bool) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - *changed = (*Node)(self).tree.PutTimestamp(data.Key, data.Value, data.Exists, data.Expected, data.Timestamp) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + *changed = (*Node)(self).tree.PutTimestamp(data.Key, data.Value, data.Exists, data.Expected, data.Timestamp) + return nil } func (self *hashTreeServer) DelTimestamp(data HashTreeItem, changed *bool) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - *changed = (*Node)(self).tree.DelTimestamp(data.Key, data.Expected) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + *changed = (*Node)(self).tree.DelTimestamp(data.Key, data.Expected) + return nil } func (self *hashTreeServer) SubFinger(data HashTreeItem, result *radix.Print) error { - *result = *((*Node)(self).tree.SubFinger(data.Key, data.SubKey)) - return nil + *result = *((*Node)(self).tree.SubFinger(data.Key, data.SubKey)) + return nil } func (self *hashTreeServer) SubGetTimestamp(data HashTreeItem, result *HashTreeItem) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - *result = data - result.Value, result.Timestamp, result.Exists = (*Node)(self).tree.SubGetTimestamp(data.Key, data.SubKey) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + *result = data + result.Value, result.Timestamp, result.Exists = (*Node)(self).tree.SubGetTimestamp(data.Key, data.SubKey) + return nil } func (self *hashTreeServer) SubPutTimestamp(data HashTreeItem, changed *bool) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - *changed = (*Node)(self).tree.SubPutTimestamp(data.Key, data.SubKey, data.Value, data.Exists, data.Expected, data.Timestamp) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + *changed = (*Node)(self).tree.SubPutTimestamp(data.Key, data.SubKey, data.Value, data.Exists, data.Expected, data.Timestamp) + return nil } func (self *hashTreeServer) SubDelTimestamp(data HashTreeItem, changed *bool) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - *changed = (*Node)(self).tree.SubDelTimestamp(data.Key, data.SubKey, data.Expected) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + *changed = (*Node)(self).tree.SubDelTimestamp(data.Key, data.SubKey, data.Expected) + return nil } func (self *hashTreeServer) SubClearTimestamp(data HashTreeItem, changed *int) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - *changed = (*Node)(self).tree.SubClearTimestamp(data.Key, data.Expected, data.Timestamp) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + *changed = (*Node)(self).tree.SubClearTimestamp(data.Key, data.Expected, data.Timestamp) + return nil } func (self *hashTreeServer) SubKillTimestamp(data HashTreeItem, changed *int) error { - atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) - *changed = (*Node)(self).tree.SubKillTimestamp(data.Key, data.Expected) - return nil + atomic.StoreInt64(&(*Node)(self).lastSync, time.Now().UnixNano()) + *changed = (*Node)(self).tree.SubKillTimestamp(data.Key, data.Expected) + return nil } diff --git a/dhash/json_client.go b/dhash/json_client.go index ca7e947..b71d73c 100644 --- a/dhash/json_client.go +++ b/dhash/json_client.go @@ -4,9 +4,12 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/zond/god/common" - "github.com/zond/god/setop" + "io/ioutil" "net/http" + "os/exec" + + "github.com/zond/god/common" + "github.com/zond/setop" ) // JSONClient is used in the tests to ensure that the JSON API provides roughly the same functionality as the gob API. @@ -14,8 +17,11 @@ import ( // It is NOT meant to be used as a real client, since if you are using Go anyway the client.Conn type is much more efficient. type JSONClient string +var jsonClient = &http.Client{} + +var lastOpen int32 = 0 + func (self JSONClient) call(action string, params, result interface{}) { - client := new(http.Client) buf := new(bytes.Buffer) if params != nil { err := json.NewEncoder(buf).Encode(params) @@ -28,15 +34,20 @@ func (self JSONClient) call(action string, params, result interface{}) { panic(err) } req.Header.Set("Accept", "application/json") - resp, err := client.Do(req) + resp, err := jsonClient.Do(req) if err != nil { + outp, e := exec.Command("sysctl", "kern.num_files").Output() + if e != nil { + panic(e) + } + fmt.Println(string(outp)) panic(err) } err = json.NewDecoder(resp.Body).Decode(result) if err != nil { panic(err) } - resp.Body.Close() + ioutil.ReadAll(resp.Body) } func (self JSONClient) SSubPut(key, subKey, value []byte) { var x Nothing diff --git a/dhash/json_dhash_server.go b/dhash/json_dhash_server.go index 2858406..e492cc0 100644 --- a/dhash/json_dhash_server.go +++ b/dhash/json_dhash_server.go @@ -1,795 +1,799 @@ package dhash import ( - "github.com/zond/god/common" - "github.com/zond/god/setop" + "github.com/zond/god/common" + "github.com/zond/setop" ) type Nothing struct{} type SubValueRes struct { - Key []byte - SubKey []byte - Value []byte - Exists bool + Key []byte + SubKey []byte + Value []byte + Exists bool } type SubValueIndexRes struct { - Key []byte - SubKey []byte - Value []byte - Index int - Exists bool + Key []byte + SubKey []byte + Value []byte + Index int + Exists bool } type SubValueOp struct { - Key []byte - SubKey []byte - Value []byte - Sync bool + Key []byte + SubKey []byte + Value []byte + Sync bool } type SubKeyOp struct { - Key []byte - SubKey []byte - Sync bool + Key []byte + SubKey []byte + Sync bool } type SubKeyReq struct { - Key []byte - SubKey []byte + Key []byte + SubKey []byte } type SubIndex struct { - Key []byte - Index int + Key []byte + Index int } type ValueOp struct { - Key []byte - Value []byte - Sync bool + Key []byte + Value []byte + Sync bool } type ValueRes struct { - Key []byte - Value []byte - Exists bool + Key []byte + Value []byte + Exists bool } type KeyOp struct { - Key []byte - Sync bool + Key []byte + Sync bool } type KeyReq struct { - Key []byte + Key []byte } type KeyRange struct { - Key []byte - Min []byte - Max []byte - MinInc bool - MaxInc bool + Key []byte + Min []byte + Max []byte + MinInc bool + MaxInc bool } type IndexRange struct { - Key []byte - MinIndex *int - MaxIndex *int + Key []byte + MinIndex *int + MaxIndex *int } type PageRange struct { - Key []byte - From []byte - FromInc bool - Len int + Key []byte + From []byte + FromInc bool + Len int } type SubConf struct { - TreeKey []byte - Key string - Value string + TreeKey []byte + Key string + Value string } type Conf struct { - Key string - Value string + Key string + Value string } type JSONApi Node func (self *JSONApi) convert(items []common.Item, result *[]ValueRes) { - for _, item := range items { - *result = append(*result, ValueRes{ - Key: item.Key, - Value: item.Value, - Exists: true, - }) - } + for _, item := range items { + *result = append(*result, ValueRes{ + Key: item.Key, + Value: item.Value, + Exists: true, + }) + } } func (self *JSONApi) forwardUnlessMe(cmd string, key []byte, in, out interface{}) (forwarded bool, err error) { - succ := (*Node)(self).node.GetSuccessorFor(key) - if succ.Addr != (*Node)(self).node.GetAddr() { - forwarded, err = true, succ.Call(cmd, in, out) - } - return + succ := (*Node)(self).node.GetSuccessorFor(key) + if succ.Addr != (*Node)(self).node.GetBroadcastAddr() { + forwarded, err = true, succ.Call(cmd, in, out) + } + return } func (self *JSONApi) Clear(x Nothing, y *Nothing) (err error) { - (*Node)(self).Clear() - return nil + (*Node)(self).Clear() + return nil +} +func (self *JSONApi) Nodes(x Nothing, result *common.Remotes) (err error) { + *result = (*Node)(self).node.GetNodes() + return nil } func (self *JSONApi) SubDel(d SubKeyOp, n *Nothing) (err error) { - data := common.Item{ - Key: d.Key, - SubKey: d.SubKey, - Sync: d.Sync, - } - var x int - var f bool - if f, err = self.forwardUnlessMe("DHash.SubDel", data.Key, data, &x); !f { - err = (*Node)(self).SubDel(data) - } - return + data := common.Item{ + Key: d.Key, + SubKey: d.SubKey, + Sync: d.Sync, + } + var x int + var f bool + if f, err = self.forwardUnlessMe("DHash.SubDel", data.Key, data, &x); !f { + err = (*Node)(self).SubDel(data) + } + return } func (self *JSONApi) SubClear(d SubKeyOp, n *Nothing) (err error) { - data := common.Item{ - Key: d.Key, - SubKey: d.SubKey, - Sync: d.Sync, - } - var x int - var f bool - if f, err = self.forwardUnlessMe("DHash.SubClear", data.Key, data, &x); !f { - err = (*Node)(self).SubClear(data) - } - return + data := common.Item{ + Key: d.Key, + SubKey: d.SubKey, + Sync: d.Sync, + } + var x int + var f bool + if f, err = self.forwardUnlessMe("DHash.SubClear", data.Key, data, &x); !f { + err = (*Node)(self).SubClear(data) + } + return } func (self *JSONApi) SubPut(d SubValueOp, n *Nothing) (err error) { - data := common.Item{ - Key: d.Key, - SubKey: d.SubKey, - Value: d.Value, - Sync: d.Sync, - } - var x int - var f bool - if f, err = self.forwardUnlessMe("DHash.SubPut", data.Key, data, &x); !f { - err = (*Node)(self).SubPut(data) - } - return + data := common.Item{ + Key: d.Key, + SubKey: d.SubKey, + Value: d.Value, + Sync: d.Sync, + } + var x int + var f bool + if f, err = self.forwardUnlessMe("DHash.SubPut", data.Key, data, &x); !f { + err = (*Node)(self).SubPut(data) + } + return } func (self *JSONApi) Del(d KeyOp, n *Nothing) (err error) { - data := common.Item{ - Key: d.Key, - Sync: d.Sync, - } - var x int - var f bool - if f, err = self.forwardUnlessMe("DHash.Del", data.Key, data, &x); !f { - err = (*Node)(self).Del(data) - } - return + data := common.Item{ + Key: d.Key, + Sync: d.Sync, + } + var x int + var f bool + if f, err = self.forwardUnlessMe("DHash.Del", data.Key, data, &x); !f { + err = (*Node)(self).Del(data) + } + return } func (self *JSONApi) Put(d ValueOp, n *Nothing) (err error) { - data := common.Item{ - Key: d.Key, - Value: d.Value, - Sync: d.Sync, - } - var x int - var f bool - if f, err = self.forwardUnlessMe("DHash.Put", data.Key, data, &x); !f { - err = (*Node)(self).Put(data) - } - return + data := common.Item{ + Key: d.Key, + Value: d.Value, + Sync: d.Sync, + } + var x int + var f bool + if f, err = self.forwardUnlessMe("DHash.Put", data.Key, data, &x); !f { + err = (*Node)(self).Put(data) + } + return } func (self *JSONApi) MirrorCount(kr KeyRange, result *int) (err error) { - r := common.Range{ - Key: kr.Key, - Min: kr.Min, - Max: kr.Max, - MinInc: kr.MinInc, - MaxInc: kr.MaxInc, - } - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorCount", r.Key, r, result); !f { - err = (*Node)(self).MirrorCount(r, result) - } - return + r := common.Range{ + Key: kr.Key, + Min: kr.Min, + Max: kr.Max, + MinInc: kr.MinInc, + MaxInc: kr.MaxInc, + } + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorCount", r.Key, r, result); !f { + err = (*Node)(self).MirrorCount(r, result) + } + return } func (self *JSONApi) Count(kr KeyRange, result *int) (err error) { - r := common.Range{ - Key: kr.Key, - Min: kr.Min, - Max: kr.Max, - MinInc: kr.MinInc, - MaxInc: kr.MaxInc, - } - var f bool - if f, err = self.forwardUnlessMe("DHash.Count", r.Key, r, result); !f { - err = (*Node)(self).Count(r, result) - } - return + r := common.Range{ + Key: kr.Key, + Min: kr.Min, + Max: kr.Max, + MinInc: kr.MinInc, + MaxInc: kr.MaxInc, + } + var f bool + if f, err = self.forwardUnlessMe("DHash.Count", r.Key, r, result); !f { + err = (*Node)(self).Count(r, result) + } + return } func (self *JSONApi) Next(kr KeyReq, result *ValueRes) (err error) { - k, v, e := (*Node)(self).client().Next(kr.Key) - *result = ValueRes{ - Key: k, - Value: v, - Exists: e, - } - return nil + k, v, e := (*Node)(self).client().Next(kr.Key) + *result = ValueRes{ + Key: k, + Value: v, + Exists: e, + } + return nil } func (self *JSONApi) Prev(kr KeyReq, result *ValueRes) (err error) { - k, v, e := (*Node)(self).client().Prev(kr.Key) - *result = ValueRes{ - Key: k, - Value: v, - Exists: e, - } - return nil + k, v, e := (*Node)(self).client().Prev(kr.Key) + *result = ValueRes{ + Key: k, + Value: v, + Exists: e, + } + return nil } func (self *JSONApi) SubGet(k SubKeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - SubKey: k.SubKey, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.SubGet", data.Key, data, &item); !f { - err = (*Node)(self).SubGet(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + SubKey: k.SubKey, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.SubGet", data.Key, data, &item); !f { + err = (*Node)(self).SubGet(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) Get(k KeyReq, result *ValueRes) (err error) { - data := common.Item{ - Key: k.Key, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.Get", data.Key, data, &item); !f { - err = (*Node)(self).Get(data, &item) - } - *result = ValueRes{ - Key: item.Key, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.Get", data.Key, data, &item); !f { + err = (*Node)(self).Get(data, &item) + } + *result = ValueRes{ + Key: item.Key, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) Size(x Nothing, result *int) (err error) { - *result = (*Node)(self).Size() - return nil + *result = (*Node)(self).Size() + return nil } func (self *JSONApi) SubSize(k KeyReq, result *int) (err error) { - key := k.Key - var f bool - if f, err = self.forwardUnlessMe("DHash.SubSize", key, key, result); !f { - err = (*Node)(self).SubSize(key, result) - } - return + key := k.Key + var f bool + if f, err = self.forwardUnlessMe("DHash.SubSize", key, key, result); !f { + err = (*Node)(self).SubSize(key, result) + } + return } func (self *JSONApi) Owned(x Nothing, result *int) (err error) { - *result = (*Node)(self).Owned() - return nil + *result = (*Node)(self).Owned() + return nil } func (self *JSONApi) Describe(x Nothing, result *common.DHashDescription) (err error) { - *result = (*Node)(self).Description() - return nil + *result = (*Node)(self).Description() + return nil } func (self *JSONApi) DescribeTree(x Nothing, result *string) (err error) { - *result = (*Node)(self).DescribeTree() - return nil + *result = (*Node)(self).DescribeTree() + return nil } func (self *JSONApi) PrevIndex(i SubIndex, result *SubValueIndexRes) (err error) { - data := common.Item{ - Key: i.Key, - Index: i.Index, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.PrevIndex", data.Key, data, &item); !f { - err = (*Node)(self).PrevIndex(data, &item) - } - *result = SubValueIndexRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Index: item.Index, - Exists: item.Exists, - } - return + data := common.Item{ + Key: i.Key, + Index: i.Index, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.PrevIndex", data.Key, data, &item); !f { + err = (*Node)(self).PrevIndex(data, &item) + } + *result = SubValueIndexRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Index: item.Index, + Exists: item.Exists, + } + return } func (self *JSONApi) MirrorPrevIndex(i SubIndex, result *SubValueIndexRes) (err error) { - data := common.Item{ - Key: i.Key, - Index: i.Index, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorPrevIndex", data.Key, data, &item); !f { - err = (*Node)(self).MirrorPrevIndex(data, &item) - } - *result = SubValueIndexRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Index: item.Index, - Exists: item.Exists, - } - return + data := common.Item{ + Key: i.Key, + Index: i.Index, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorPrevIndex", data.Key, data, &item); !f { + err = (*Node)(self).MirrorPrevIndex(data, &item) + } + *result = SubValueIndexRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Index: item.Index, + Exists: item.Exists, + } + return } func (self *JSONApi) MirrorNextIndex(i SubIndex, result *SubValueIndexRes) (err error) { - data := common.Item{ - Key: i.Key, - Index: i.Index, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorNextIndex", data.Key, data, &item); !f { - err = (*Node)(self).MirrorNextIndex(data, &item) - } - *result = SubValueIndexRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Index: item.Index, - Exists: item.Exists, - } - return + data := common.Item{ + Key: i.Key, + Index: i.Index, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorNextIndex", data.Key, data, &item); !f { + err = (*Node)(self).MirrorNextIndex(data, &item) + } + *result = SubValueIndexRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Index: item.Index, + Exists: item.Exists, + } + return } func (self *JSONApi) NextIndex(i SubIndex, result *SubValueIndexRes) (err error) { - data := common.Item{ - Key: i.Key, - Index: i.Index, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.NextIndex", data.Key, data, &item); !f { - err = (*Node)(self).NextIndex(data, &item) - } - *result = SubValueIndexRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Index: item.Index, - Exists: item.Exists, - } - return + data := common.Item{ + Key: i.Key, + Index: i.Index, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.NextIndex", data.Key, data, &item); !f { + err = (*Node)(self).NextIndex(data, &item) + } + *result = SubValueIndexRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Index: item.Index, + Exists: item.Exists, + } + return } func (self *JSONApi) MirrorReverseIndexOf(i SubKeyReq, result *common.Index) (err error) { - data := common.Item{ - Key: i.Key, - SubKey: i.SubKey, - } - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorReverseIndexOf", data.Key, data, result); !f { - err = (*Node)(self).MirrorReverseIndexOf(data, result) - } - return + data := common.Item{ + Key: i.Key, + SubKey: i.SubKey, + } + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorReverseIndexOf", data.Key, data, result); !f { + err = (*Node)(self).MirrorReverseIndexOf(data, result) + } + return } func (self *JSONApi) MirrorIndexOf(i SubKeyReq, result *common.Index) (err error) { - data := common.Item{ - Key: i.Key, - SubKey: i.SubKey, - } - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorIndexOf", data.Key, data, result); !f { - err = (*Node)(self).MirrorIndexOf(data, result) - } - return + data := common.Item{ + Key: i.Key, + SubKey: i.SubKey, + } + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorIndexOf", data.Key, data, result); !f { + err = (*Node)(self).MirrorIndexOf(data, result) + } + return } func (self *JSONApi) ReverseIndexOf(i SubKeyReq, result *common.Index) (err error) { - data := common.Item{ - Key: i.Key, - SubKey: i.SubKey, - } - var f bool - if f, err = self.forwardUnlessMe("DHash.ReverseIndexOf", data.Key, data, result); !f { - err = (*Node)(self).ReverseIndexOf(data, result) - } - return + data := common.Item{ + Key: i.Key, + SubKey: i.SubKey, + } + var f bool + if f, err = self.forwardUnlessMe("DHash.ReverseIndexOf", data.Key, data, result); !f { + err = (*Node)(self).ReverseIndexOf(data, result) + } + return } func (self *JSONApi) IndexOf(i SubKeyReq, result *common.Index) (err error) { - data := common.Item{ - Key: i.Key, - SubKey: i.SubKey, - } - var f bool - if f, err = self.forwardUnlessMe("DHash.IndexOf", data.Key, data, result); !f { - err = (*Node)(self).IndexOf(data, result) - } - return + data := common.Item{ + Key: i.Key, + SubKey: i.SubKey, + } + var f bool + if f, err = self.forwardUnlessMe("DHash.IndexOf", data.Key, data, result); !f { + err = (*Node)(self).IndexOf(data, result) + } + return } func (self *JSONApi) SubMirrorPrev(k SubKeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - SubKey: k.SubKey, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.SubMirrorPrev", data.Key, data, &item); !f { - err = (*Node)(self).SubMirrorPrev(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + SubKey: k.SubKey, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.SubMirrorPrev", data.Key, data, &item); !f { + err = (*Node)(self).SubMirrorPrev(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) SubMirrorNext(k SubKeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - SubKey: k.SubKey, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.SubMirrorNext", data.Key, data, &item); !f { - err = (*Node)(self).SubMirrorNext(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + SubKey: k.SubKey, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.SubMirrorNext", data.Key, data, &item); !f { + err = (*Node)(self).SubMirrorNext(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) SubPrev(k SubKeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - SubKey: k.SubKey, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.SubPrev", data.Key, data, &item); !f { - err = (*Node)(self).SubPrev(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + SubKey: k.SubKey, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.SubPrev", data.Key, data, &item); !f { + err = (*Node)(self).SubPrev(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) SubNext(k SubKeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - SubKey: k.SubKey, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.SubNext", data.Key, data, &item); !f { - err = (*Node)(self).SubNext(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + SubKey: k.SubKey, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.SubNext", data.Key, data, &item); !f { + err = (*Node)(self).SubNext(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) MirrorFirst(k KeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorFirst", data.Key, data, &item); !f { - err = (*Node)(self).MirrorFirst(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorFirst", data.Key, data, &item); !f { + err = (*Node)(self).MirrorFirst(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) MirrorLast(k KeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorLast", data.Key, data, &item); !f { - err = (*Node)(self).MirrorLast(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorLast", data.Key, data, &item); !f { + err = (*Node)(self).MirrorLast(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) First(k KeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.First", data.Key, data, &item); !f { - err = (*Node)(self).First(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.First", data.Key, data, &item); !f { + err = (*Node)(self).First(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) Last(k KeyReq, result *SubValueRes) (err error) { - data := common.Item{ - Key: k.Key, - } - var item common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.Last", data.Key, data, &item); !f { - err = (*Node)(self).Last(data, &item) - } - *result = SubValueRes{ - Key: item.Key, - SubKey: item.SubKey, - Value: item.Value, - Exists: item.Exists, - } - return + data := common.Item{ + Key: k.Key, + } + var item common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.Last", data.Key, data, &item); !f { + err = (*Node)(self).Last(data, &item) + } + *result = SubValueRes{ + Key: item.Key, + SubKey: item.SubKey, + Value: item.Value, + Exists: item.Exists, + } + return } func (self *JSONApi) MirrorReverseSlice(kr KeyRange, result *[]ValueRes) (err error) { - r := common.Range{ - Key: kr.Key, - Min: kr.Min, - Max: kr.Max, - MinInc: kr.MinInc, - MaxInc: kr.MaxInc, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorReverseSlice", r.Key, r, &items); !f { - err = (*Node)(self).MirrorReverseSlice(r, &items) - } - self.convert(items, result) - return + r := common.Range{ + Key: kr.Key, + Min: kr.Min, + Max: kr.Max, + MinInc: kr.MinInc, + MaxInc: kr.MaxInc, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorReverseSlice", r.Key, r, &items); !f { + err = (*Node)(self).MirrorReverseSlice(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) MirrorSlice(kr KeyRange, result *[]ValueRes) (err error) { - r := common.Range{ - Key: kr.Key, - Min: kr.Min, - Max: kr.Max, - MinInc: kr.MinInc, - MaxInc: kr.MaxInc, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorSlice", r.Key, r, &items); !f { - err = (*Node)(self).MirrorSlice(r, &items) - } - self.convert(items, result) - return + r := common.Range{ + Key: kr.Key, + Min: kr.Min, + Max: kr.Max, + MinInc: kr.MinInc, + MaxInc: kr.MaxInc, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorSlice", r.Key, r, &items); !f { + err = (*Node)(self).MirrorSlice(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) MirrorSliceIndex(ir IndexRange, result *[]ValueRes) (err error) { - var mi int - var ma int - if ir.MinIndex != nil { - mi = *ir.MinIndex - } - if ir.MaxIndex != nil { - ma = *ir.MaxIndex - } - r := common.Range{ - Key: ir.Key, - MinIndex: mi, - MaxIndex: ma, - MinInc: ir.MinIndex != nil, - MaxInc: ir.MaxIndex != nil, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorSliceIndex", r.Key, r, &items); !f { - err = (*Node)(self).MirrorSliceIndex(r, &items) - } - self.convert(items, result) - return + var mi int + var ma int + if ir.MinIndex != nil { + mi = *ir.MinIndex + } + if ir.MaxIndex != nil { + ma = *ir.MaxIndex + } + r := common.Range{ + Key: ir.Key, + MinIndex: mi, + MaxIndex: ma, + MinInc: ir.MinIndex != nil, + MaxInc: ir.MaxIndex != nil, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorSliceIndex", r.Key, r, &items); !f { + err = (*Node)(self).MirrorSliceIndex(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) MirrorReverseSliceIndex(ir IndexRange, result *[]ValueRes) (err error) { - var mi int - var ma int - if ir.MinIndex != nil { - mi = *ir.MinIndex - } - if ir.MaxIndex != nil { - ma = *ir.MaxIndex - } - r := common.Range{ - Key: ir.Key, - MinIndex: mi, - MaxIndex: ma, - MinInc: ir.MinIndex != nil, - MaxInc: ir.MaxIndex != nil, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorReverseSliceIndex", r.Key, r, &items); !f { - err = (*Node)(self).MirrorReverseSliceIndex(r, &items) - } - self.convert(items, result) - return + var mi int + var ma int + if ir.MinIndex != nil { + mi = *ir.MinIndex + } + if ir.MaxIndex != nil { + ma = *ir.MaxIndex + } + r := common.Range{ + Key: ir.Key, + MinIndex: mi, + MaxIndex: ma, + MinInc: ir.MinIndex != nil, + MaxInc: ir.MaxIndex != nil, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorReverseSliceIndex", r.Key, r, &items); !f { + err = (*Node)(self).MirrorReverseSliceIndex(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) MirrorSliceLen(pr PageRange, result *[]ValueRes) (err error) { - r := common.Range{ - Key: pr.Key, - Min: pr.From, - MinInc: pr.FromInc, - Len: pr.Len, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorSliceLen", r.Key, r, &items); !f { - err = (*Node)(self).MirrorSliceLen(r, &items) - } - self.convert(items, result) - return + r := common.Range{ + Key: pr.Key, + Min: pr.From, + MinInc: pr.FromInc, + Len: pr.Len, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorSliceLen", r.Key, r, &items); !f { + err = (*Node)(self).MirrorSliceLen(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) MirrorReverseSliceLen(pr PageRange, result *[]ValueRes) (err error) { - r := common.Range{ - Key: pr.Key, - Max: pr.From, - MaxInc: pr.FromInc, - Len: pr.Len, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.MirrorReverseSliceLen", r.Key, r, &items); !f { - err = (*Node)(self).MirrorReverseSliceLen(r, &items) - } - self.convert(items, result) - return + r := common.Range{ + Key: pr.Key, + Max: pr.From, + MaxInc: pr.FromInc, + Len: pr.Len, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.MirrorReverseSliceLen", r.Key, r, &items); !f { + err = (*Node)(self).MirrorReverseSliceLen(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) ReverseSlice(kr KeyRange, result *[]ValueRes) (err error) { - r := common.Range{ - Key: kr.Key, - Min: kr.Min, - Max: kr.Max, - MinInc: kr.MinInc, - MaxInc: kr.MaxInc, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.ReverseSlice", r.Key, r, &items); !f { - err = (*Node)(self).ReverseSlice(r, &items) - } - self.convert(items, result) - return + r := common.Range{ + Key: kr.Key, + Min: kr.Min, + Max: kr.Max, + MinInc: kr.MinInc, + MaxInc: kr.MaxInc, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.ReverseSlice", r.Key, r, &items); !f { + err = (*Node)(self).ReverseSlice(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) Slice(kr KeyRange, result *[]ValueRes) (err error) { - r := common.Range{ - Key: kr.Key, - Min: kr.Min, - Max: kr.Max, - MinInc: kr.MinInc, - MaxInc: kr.MaxInc, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.Slice", r.Key, r, &items); !f { - err = (*Node)(self).Slice(r, &items) - } - self.convert(items, result) - return + r := common.Range{ + Key: kr.Key, + Min: kr.Min, + Max: kr.Max, + MinInc: kr.MinInc, + MaxInc: kr.MaxInc, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.Slice", r.Key, r, &items); !f { + err = (*Node)(self).Slice(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) SliceIndex(ir IndexRange, result *[]ValueRes) (err error) { - var mi int - var ma int - if ir.MinIndex != nil { - mi = *ir.MinIndex - } - if ir.MaxIndex != nil { - ma = *ir.MaxIndex - } - r := common.Range{ - Key: ir.Key, - MinIndex: mi, - MaxIndex: ma, - MinInc: ir.MinIndex != nil, - MaxInc: ir.MaxIndex != nil, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.SliceIndex", r.Key, r, &items); !f { - err = (*Node)(self).SliceIndex(r, &items) - } - self.convert(items, result) - return + var mi int + var ma int + if ir.MinIndex != nil { + mi = *ir.MinIndex + } + if ir.MaxIndex != nil { + ma = *ir.MaxIndex + } + r := common.Range{ + Key: ir.Key, + MinIndex: mi, + MaxIndex: ma, + MinInc: ir.MinIndex != nil, + MaxInc: ir.MaxIndex != nil, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.SliceIndex", r.Key, r, &items); !f { + err = (*Node)(self).SliceIndex(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) ReverseSliceIndex(ir IndexRange, result *[]ValueRes) (err error) { - var mi int - var ma int - if ir.MinIndex != nil { - mi = *ir.MinIndex - } - if ir.MaxIndex != nil { - ma = *ir.MaxIndex - } - r := common.Range{ - Key: ir.Key, - MinIndex: mi, - MaxIndex: ma, - MinInc: ir.MinIndex != nil, - MaxInc: ir.MaxIndex != nil, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.ReverseSliceIndex", r.Key, r, &items); !f { - err = (*Node)(self).ReverseSliceIndex(r, &items) - } - self.convert(items, result) - return + var mi int + var ma int + if ir.MinIndex != nil { + mi = *ir.MinIndex + } + if ir.MaxIndex != nil { + ma = *ir.MaxIndex + } + r := common.Range{ + Key: ir.Key, + MinIndex: mi, + MaxIndex: ma, + MinInc: ir.MinIndex != nil, + MaxInc: ir.MaxIndex != nil, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.ReverseSliceIndex", r.Key, r, &items); !f { + err = (*Node)(self).ReverseSliceIndex(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) SliceLen(pr PageRange, result *[]ValueRes) (err error) { - r := common.Range{ - Key: pr.Key, - Min: pr.From, - MinInc: pr.FromInc, - Len: pr.Len, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.SliceLen", r.Key, r, &items); !f { - err = (*Node)(self).SliceLen(r, &items) - } - self.convert(items, result) - return + r := common.Range{ + Key: pr.Key, + Min: pr.From, + MinInc: pr.FromInc, + Len: pr.Len, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.SliceLen", r.Key, r, &items); !f { + err = (*Node)(self).SliceLen(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) ReverseSliceLen(pr PageRange, result *[]ValueRes) (err error) { - r := common.Range{ - Key: pr.Key, - Max: pr.From, - MaxInc: pr.FromInc, - Len: pr.Len, - } - var items []common.Item - var f bool - if f, err = self.forwardUnlessMe("DHash.ReverseSliceLen", r.Key, r, &items); !f { - err = (*Node)(self).ReverseSliceLen(r, &items) - } - self.convert(items, result) - return + r := common.Range{ + Key: pr.Key, + Max: pr.From, + MaxInc: pr.FromInc, + Len: pr.Len, + } + var items []common.Item + var f bool + if f, err = self.forwardUnlessMe("DHash.ReverseSliceLen", r.Key, r, &items); !f { + err = (*Node)(self).ReverseSliceLen(r, &items) + } + self.convert(items, result) + return } func (self *JSONApi) SetExpression(expr setop.SetExpression, items *[]setop.SetOpResult) (err error) { - if expr.Op == nil { - var err error - if expr.Op, err = setop.NewSetOpParser(expr.Code).Parse(); err != nil { - return err - } - } - return (*Node)(self).SetExpression(expr, items) + if expr.Op == nil { + var err error + if expr.Op, err = setop.NewSetOpParser(expr.Code).Parse(); err != nil { + return err + } + } + return (*Node)(self).SetExpression(expr, items) } func (self *JSONApi) AddConfiguration(co Conf, x *Nothing) (err error) { - c := common.ConfItem{ - Key: co.Key, - Value: co.Value, - } - (*Node)(self).AddConfiguration(c) - return nil + c := common.ConfItem{ + Key: co.Key, + Value: co.Value, + } + (*Node)(self).AddConfiguration(c) + return nil } func (self *JSONApi) SubAddConfiguration(co SubConf, x *Nothing) (err error) { - c := common.ConfItem{ - TreeKey: co.TreeKey, - Key: co.Key, - Value: co.Value, - } - (*Node)(self).SubAddConfiguration(c) - return nil + c := common.ConfItem{ + TreeKey: co.TreeKey, + Key: co.Key, + Value: co.Value, + } + (*Node)(self).SubAddConfiguration(c) + return nil } func (self *JSONApi) Configuration(x Nothing, result *common.Conf) (err error) { - *result = common.Conf{} - (*result).Data, (*result).Timestamp = (*Node)(self).tree.Configuration() - return nil + *result = common.Conf{} + (*result).Data, (*result).Timestamp = (*Node)(self).tree.Configuration() + return nil } func (self *JSONApi) SubConfiguration(k KeyReq, result *common.Conf) (err error) { - key := k.Key - *result = common.Conf{TreeKey: key} - (*result).Data, (*result).Timestamp = (*Node)(self).tree.SubConfiguration(key) - return nil + key := k.Key + *result = common.Conf{TreeKey: key} + (*result).Data, (*result).Timestamp = (*Node)(self).tree.SubConfiguration(key) + return nil } diff --git a/dhash/json_server.go b/dhash/json_server.go index ed19fd3..409e622 100644 --- a/dhash/json_server.go +++ b/dhash/json_server.go @@ -146,7 +146,7 @@ func (self *Node) jsonDescription() string { func (self *Node) startJson() { var nodeAddr *net.TCPAddr var err error - if nodeAddr, err = net.ResolveTCPAddr("tcp", self.node.GetAddr()); err != nil { + if nodeAddr, err = net.ResolveTCPAddr("tcp", self.node.GetListenAddr()); err != nil { return } rpcServer := rpc.NewServer() diff --git a/dhash/profile/profile.go b/dhash/profile/profile.go index 8b86f06..04e2319 100644 --- a/dhash/profile/profile.go +++ b/dhash/profile/profile.go @@ -2,11 +2,12 @@ package main import ( "fmt" + "os" + "runtime/pprof" + "github.com/zond/god/common" . "github.com/zond/god/dhash" "github.com/zond/god/murmur" - "os" - "runtime/pprof" ) func main() { @@ -23,9 +24,8 @@ func main() { defer pprof.StopCPUProfile() defer pprof.WriteHeapProfile(f2) - benchNode := NewNode("127.0.0.1:1231") + benchNode := NewNodeDir("127.0.0.1:1231", "127.0.0.1:1231", "") benchNode.MustStart() - benchNode.Kill() var k []byte for i := 0; i < 100000; i++ { k = murmur.HashString(fmt.Sprint(i)) diff --git a/dhash/remote_hash_tree.go b/dhash/remote_hash_tree.go index 7fa7198..9cf1b8a 100644 --- a/dhash/remote_hash_tree.go +++ b/dhash/remote_hash_tree.go @@ -1,192 +1,192 @@ package dhash import ( - "github.com/zond/god/common" - "github.com/zond/god/radix" + "github.com/zond/god/common" + "github.com/zond/god/radix" ) type remoteHashTree struct { - destination common.Remote - source common.Remote - node *Node + destination common.Remote + source common.Remote + node *Node } func (self remoteHashTree) Configuration() (conf map[string]string, timestamp int64) { - var result common.Conf - if err := self.destination.Call("DHash.Configuration", 0, &result); err != nil { - conf = make(map[string]string) - } else { - conf, timestamp = result.Data, result.Timestamp - } - return + var result common.Conf + if err := self.destination.Call("DHash.Configuration", 0, &result); err != nil { + conf = make(map[string]string) + } else { + conf, timestamp = result.Data, result.Timestamp + } + return } func (self remoteHashTree) SubConfiguration(key []byte) (conf map[string]string, timestamp int64) { - var result common.Conf - if err := self.destination.Call("DHash.SubConfiguration", key, &result); err != nil { - conf = make(map[string]string) - } else { - conf, timestamp = result.Data, result.Timestamp - } - return + var result common.Conf + if err := self.destination.Call("DHash.SubConfiguration", key, &result); err != nil { + conf = make(map[string]string) + } else { + conf, timestamp = result.Data, result.Timestamp + } + return } func (self remoteHashTree) Configure(conf map[string]string, timestamp int64) { - var x int - self.destination.Call("HashTree.Configure", common.Conf{ - Data: conf, - Timestamp: timestamp, - }, &x) + var x int + self.destination.Call("HashTree.Configure", common.Conf{ + Data: conf, + Timestamp: timestamp, + }, &x) } func (self remoteHashTree) SubConfigure(key []byte, conf map[string]string, timestamp int64) { - var x int - self.destination.Call("HashTree.SubConfigure", common.Conf{ - TreeKey: key, - Data: conf, - Timestamp: timestamp, - }, &x) + var x int + self.destination.Call("HashTree.SubConfigure", common.Conf{ + TreeKey: key, + Data: conf, + Timestamp: timestamp, + }, &x) } func (self remoteHashTree) Hash() (result []byte) { - self.destination.Call("HashTree.Hash", 0, &result) - return + self.destination.Call("HashTree.Hash", 0, &result) + return } func (self remoteHashTree) Finger(key []radix.Nibble) (result *radix.Print) { - result = &radix.Print{} - self.destination.Call("HashTree.Finger", key, result) - return + result = &radix.Print{} + self.destination.Call("HashTree.Finger", key, result) + return } func (self remoteHashTree) GetTimestamp(key []radix.Nibble) (value []byte, timestamp int64, present bool) { - result := HashTreeItem{} - self.destination.Call("HashTree.GetTimestamp", key, &result) - value, timestamp, present = result.Value, result.Timestamp, result.Exists - return + result := HashTreeItem{} + self.destination.Call("HashTree.GetTimestamp", key, &result) + value, timestamp, present = result.Value, result.Timestamp, result.Exists + return } func (self remoteHashTree) PutTimestamp(key []radix.Nibble, value []byte, present bool, expected, timestamp int64) (changed bool) { - data := HashTreeItem{ - Key: key, - Value: value, - Exists: present, - Expected: expected, - Timestamp: timestamp, - } - op := "HashTree.PutTimestamp" - if self.node.hasCommListeners() { - self.node.triggerCommListeners(Comm{ - Key: radix.Stitch(data.Key), - Source: self.source, - Destination: self.destination, - Type: op, - }) - } - self.destination.Call(op, data, &changed) - return + data := HashTreeItem{ + Key: key, + Value: value, + Exists: present, + Expected: expected, + Timestamp: timestamp, + } + op := "HashTree.PutTimestamp" + if self.node.hasCommListeners() { + self.node.triggerCommListeners(Comm{ + Key: radix.Stitch(data.Key), + Source: self.source, + Destination: self.destination, + Type: op, + }) + } + self.destination.Call(op, data, &changed) + return } func (self remoteHashTree) DelTimestamp(key []radix.Nibble, expected int64) (changed bool) { - data := HashTreeItem{ - Key: key, - Expected: expected, - } - op := "HashTree.DelTimestamp" - if self.node.hasCommListeners() { - self.node.triggerCommListeners(Comm{ - Key: radix.Stitch(data.Key), - Source: self.source, - Destination: self.destination, - Type: op, - }) - } - self.destination.Call(op, data, &changed) - return + data := HashTreeItem{ + Key: key, + Expected: expected, + } + op := "HashTree.DelTimestamp" + if self.node.hasCommListeners() { + self.node.triggerCommListeners(Comm{ + Key: radix.Stitch(data.Key), + Source: self.source, + Destination: self.destination, + Type: op, + }) + } + self.destination.Call(op, data, &changed) + return } func (self remoteHashTree) SubFinger(key, subKey []radix.Nibble) (result *radix.Print) { - data := HashTreeItem{ - Key: key, - SubKey: subKey, - } - result = &radix.Print{} - self.destination.Call("HashTree.SubFinger", data, result) - return + data := HashTreeItem{ + Key: key, + SubKey: subKey, + } + result = &radix.Print{} + self.destination.Call("HashTree.SubFinger", data, result) + return } func (self remoteHashTree) SubGetTimestamp(key, subKey []radix.Nibble) (value []byte, timestamp int64, present bool) { - data := HashTreeItem{ - Key: key, - SubKey: subKey, - } - self.destination.Call("HashTree.SubGetTimestamp", data, &data) - value, timestamp, present = data.Value, data.Timestamp, data.Exists - return + data := HashTreeItem{ + Key: key, + SubKey: subKey, + } + self.destination.Call("HashTree.SubGetTimestamp", data, &data) + value, timestamp, present = data.Value, data.Timestamp, data.Exists + return } func (self remoteHashTree) SubPutTimestamp(key, subKey []radix.Nibble, value []byte, present bool, subExpected, subTimestamp int64) (changed bool) { - data := HashTreeItem{ - Key: key, - SubKey: subKey, - Value: value, - Exists: present, - Expected: subExpected, - Timestamp: subTimestamp, - } - op := "HashTree.SubPutTimestamp" - if self.node.hasCommListeners() { - self.node.triggerCommListeners(Comm{ - Key: radix.Stitch(data.Key), - SubKey: radix.Stitch(data.SubKey), - Source: self.source, - Destination: self.destination, - Type: op, - }) - } - self.destination.Call(op, data, &changed) - return + data := HashTreeItem{ + Key: key, + SubKey: subKey, + Value: value, + Exists: present, + Expected: subExpected, + Timestamp: subTimestamp, + } + op := "HashTree.SubPutTimestamp" + if self.node.hasCommListeners() { + self.node.triggerCommListeners(Comm{ + Key: radix.Stitch(data.Key), + SubKey: radix.Stitch(data.SubKey), + Source: self.source, + Destination: self.destination, + Type: op, + }) + } + self.destination.Call(op, data, &changed) + return } func (self remoteHashTree) SubDelTimestamp(key, subKey []radix.Nibble, subExpected int64) (changed bool) { - data := HashTreeItem{ - Key: key, - SubKey: subKey, - Expected: subExpected, - } - op := "HashTree.SubDelTimestamp" - if self.node.hasCommListeners() { - self.node.triggerCommListeners(Comm{ - Key: radix.Stitch(data.Key), - SubKey: radix.Stitch(data.SubKey), - Source: self.source, - Destination: self.destination, - Type: op, - }) - } - self.destination.Call(op, data, &changed) - return + data := HashTreeItem{ + Key: key, + SubKey: subKey, + Expected: subExpected, + } + op := "HashTree.SubDelTimestamp" + if self.node.hasCommListeners() { + self.node.triggerCommListeners(Comm{ + Key: radix.Stitch(data.Key), + SubKey: radix.Stitch(data.SubKey), + Source: self.source, + Destination: self.destination, + Type: op, + }) + } + self.destination.Call(op, data, &changed) + return } func (self remoteHashTree) SubClearTimestamp(key []radix.Nibble, expected, timestamp int64) (deleted int) { - data := HashTreeItem{ - Key: key, - Expected: expected, - Timestamp: timestamp, - } - op := "HashTree.SubClearTimestamp" - if self.node.hasCommListeners() { - self.node.triggerCommListeners(Comm{ - Key: radix.Stitch(data.Key), - Source: self.source, - Destination: self.destination, - Type: op, - }) - } - self.destination.Call(op, data, &deleted) - return + data := HashTreeItem{ + Key: key, + Expected: expected, + Timestamp: timestamp, + } + op := "HashTree.SubClearTimestamp" + if self.node.hasCommListeners() { + self.node.triggerCommListeners(Comm{ + Key: radix.Stitch(data.Key), + Source: self.source, + Destination: self.destination, + Type: op, + }) + } + self.destination.Call(op, data, &deleted) + return } func (self remoteHashTree) SubKillTimestamp(key []radix.Nibble, expected int64) (deleted int) { - data := HashTreeItem{ - Key: key, - Expected: expected, - } - op := "HashTree.SubKillTimestamp" - if self.node.hasCommListeners() { - self.node.triggerCommListeners(Comm{ - Key: radix.Stitch(data.Key), - Source: self.source, - Destination: self.destination, - Type: op, - }) - } - self.destination.Call(op, data, &deleted) - return + data := HashTreeItem{ + Key: key, + Expected: expected, + } + op := "HashTree.SubKillTimestamp" + if self.node.hasCommListeners() { + self.node.triggerCommListeners(Comm{ + Key: radix.Stitch(data.Key), + Source: self.source, + Destination: self.destination, + Type: op, + }) + } + self.destination.Call(op, data, &deleted) + return } diff --git a/dhash/set_ops.go b/dhash/set_ops.go index 4928b77..15f691c 100644 --- a/dhash/set_ops.go +++ b/dhash/set_ops.go @@ -4,7 +4,7 @@ import ( "bytes" "github.com/zond/god/common" "github.com/zond/god/radix" - "github.com/zond/god/setop" + "github.com/zond/setop" ) const ( diff --git a/discord/discord.go b/discord/discord.go deleted file mode 100644 index e1623c2..0000000 --- a/discord/discord.go +++ /dev/null @@ -1,18 +0,0 @@ -package discord - -import ( - "net" -) - -func findAddress() (addr string, err error) { - var udpAddr *net.UDPAddr - if udpAddr, err = net.ResolveUDPAddr("udp", "www.internic.net:80"); err != nil { - return - } - var udpConn *net.UDPConn - if udpConn, err = net.DialUDP("udp", nil, udpAddr); err != nil { - return - } - addr = udpConn.LocalAddr().String() - return -} diff --git a/discord/discord_test.go b/discord/discord_test.go index d5cb2e0..7a31080 100644 --- a/discord/discord_test.go +++ b/discord/discord_test.go @@ -12,13 +12,13 @@ func TestStartup(t *testing.T) { var nodes []*Node n := 10 for i := 0; i < n; i++ { - nodes = append(nodes, NewNode(fmt.Sprintf("%v:%v", "127.0.0.1", firstPort+i))) + nodes = append(nodes, NewNode(fmt.Sprintf("%v:%v", "127.0.0.1", firstPort+i), fmt.Sprintf("%v:%v", "127.0.0.1", firstPort+i))) } for i := 0; i < n; i++ { nodes[i].MustStart() } for i := 1; i < n; i++ { - nodes[i].MustJoin(nodes[0].GetAddr()) + nodes[i].MustJoin(nodes[0].GetBroadcastAddr()) } common.AssertWithin(t, func() (string, bool) { routes := make(map[string]bool) diff --git a/discord/node.go b/discord/node.go index 727f218..6c97a74 100644 --- a/discord/node.go +++ b/discord/node.go @@ -1,15 +1,17 @@ package discord import ( - "bytes" - "fmt" - "github.com/zond/god/common" - "github.com/zond/god/murmur" - "net" - "net/rpc" - "sync" - "sync/atomic" - "time" + "bytes" + "fmt" + "net" + "net/rpc" + "strings" + "sync" + "sync/atomic" + "time" + + "github.com/zond/god/common" + "github.com/zond/god/murmur" ) // CommListener is a function listening for generic communication between two Nodes. @@ -17,14 +19,14 @@ type CommListener func(source, dest common.Remote, typ string) bool // PingPack contains the sender and a hash of its discord ring, to let the receiver compare to its current ring. type PingPack struct { - Caller common.Remote - RingHash []byte + Caller common.Remote + RingHash []byte } const ( - created = iota - started - stopped + created = iota + started + stopped ) // Node is a node in a chord like cluster. @@ -32,362 +34,369 @@ const ( // Like chord networks, it is a ring of nodes ordered by a position metric. Unlike chord, every node has every other node in its routing table. // This allows stable networks to route with a constant time complexity. type Node struct { - ring *common.Ring - position []byte - addr string - listener *net.TCPListener - metaLock *sync.RWMutex - routeLock *sync.Mutex - state int32 - exports map[string]interface{} - commListeners []CommListener + ring *common.Ring + position []byte + listenAddr string + broadcastAddr string + listener *net.TCPListener + metaLock *sync.RWMutex + routeLock *sync.Mutex + state int32 + exports map[string]interface{} + commListeners []CommListener } -func NewNode(addr string) (result *Node) { - return &Node{ - ring: common.NewRing(), - position: make([]byte, murmur.Size), - addr: addr, - exports: make(map[string]interface{}), - metaLock: new(sync.RWMutex), - routeLock: new(sync.Mutex), - state: created, - } +func NewNode(listenAddr, broadcastAddr string) (result *Node) { + return &Node{ + ring: common.NewRing(), + position: make([]byte, murmur.Size), + listenAddr: listenAddr, + broadcastAddr: broadcastAddr, + exports: make(map[string]interface{}), + metaLock: new(sync.RWMutex), + routeLock: new(sync.Mutex), + state: created, + } } // Export will export the given api on a net/rpc server running on this Node. func (self *Node) Export(name string, api interface{}) error { - if self.hasState(created) { - self.metaLock.Lock() - defer self.metaLock.Unlock() - self.exports[name] = api - return nil - } - return fmt.Errorf("%v can only export when in state 'created'") + if self.hasState(created) { + self.metaLock.Lock() + defer self.metaLock.Unlock() + self.exports[name] = api + return nil + } + return fmt.Errorf("%v can only export when in state 'created'") } func (self *Node) AddCommListener(f CommListener) { - self.metaLock.Lock() - defer self.metaLock.Unlock() - self.commListeners = append(self.commListeners, f) + self.metaLock.Lock() + defer self.metaLock.Unlock() + self.commListeners = append(self.commListeners, f) } func (self *Node) triggerCommListeners(source, dest common.Remote, typ string) { - self.metaLock.RLock() - newListeners := make([]CommListener, 0, len(self.commListeners)) - for _, l := range self.commListeners { - self.metaLock.RUnlock() - if l(source, dest, typ) { - newListeners = append(newListeners, l) - } - self.metaLock.RLock() - } - self.metaLock.RUnlock() - self.metaLock.Lock() - defer self.metaLock.Unlock() - self.commListeners = newListeners + self.metaLock.RLock() + newListeners := make([]CommListener, 0, len(self.commListeners)) + for _, l := range self.commListeners { + self.metaLock.RUnlock() + if l(source, dest, typ) { + newListeners = append(newListeners, l) + } + self.metaLock.RLock() + } + self.metaLock.RUnlock() + self.metaLock.Lock() + defer self.metaLock.Unlock() + self.commListeners = newListeners } func (self *Node) AddChangeListener(f common.RingChangeListener) { - self.ring.AddChangeListener(f) + self.ring.AddChangeListener(f) } func (self *Node) SetPosition(position []byte) *Node { - self.metaLock.Lock() - self.position = make([]byte, len(position)) - copy(self.position, position) - self.metaLock.Unlock() - self.routeLock.Lock() - defer self.routeLock.Unlock() - self.ring.Add(self.Remote()) - return self + self.metaLock.Lock() + self.position = make([]byte, len(position)) + copy(self.position, position) + self.metaLock.Unlock() + self.routeLock.Lock() + defer self.routeLock.Unlock() + self.ring.Add(self.Remote()) + return self } // GetNodes will return remotes to all Nodes in the ring. func (self *Node) GetNodes() (result common.Remotes) { - return self.ring.Nodes() + return self.ring.Nodes() } // Redundancy will return the current maximum redundancy in the ring. func (self *Node) Redundancy() int { - return self.ring.Redundancy() + return self.ring.Redundancy() } // CountNodes returns the number of Nodes in the ring. func (self *Node) CountNodes() int { - return self.ring.Size() + return self.ring.Size() } func (self *Node) GetPosition() (result []byte) { - self.metaLock.RLock() - defer self.metaLock.RUnlock() - result = make([]byte, len(self.position)) - copy(result, self.position) - return -} -func (self *Node) GetAddr() string { - self.metaLock.RLock() - defer self.metaLock.RUnlock() - return self.addr + self.metaLock.RLock() + defer self.metaLock.RUnlock() + result = make([]byte, len(self.position)) + copy(result, self.position) + return +} +func (self *Node) GetListenAddr() string { + self.metaLock.RLock() + defer self.metaLock.RUnlock() + return self.listenAddr +} +func (self *Node) GetBroadcastAddr() string { + self.metaLock.RLock() + defer self.metaLock.RUnlock() + return self.broadcastAddr } func (self *Node) String() string { - return fmt.Sprintf("<%v@%v>", common.HexEncode(self.GetPosition()), self.GetAddr()) + return fmt.Sprintf("<%v@%v>", common.HexEncode(self.GetPosition()), self.GetBroadcastAddr()) } -// Describe returns a humanly readable string describing the address, position and ring of this Node. +// Describe returns a humanly readable string describing the broadcast address, position and ring of this Node. func (self *Node) Describe() string { - self.metaLock.RLock() - buffer := bytes.NewBufferString(fmt.Sprintf("%v@%v\n", common.HexEncode(self.position), self.addr)) - self.metaLock.RUnlock() - fmt.Fprint(buffer, self.ring.Describe()) - return string(buffer.Bytes()) + self.metaLock.RLock() + buffer := bytes.NewBufferString(fmt.Sprintf("%v@%v\n", common.HexEncode(self.position), self.broadcastAddr)) + self.metaLock.RUnlock() + fmt.Fprint(buffer, self.ring.Describe()) + return string(buffer.Bytes()) } func (self *Node) hasState(s int32) bool { - return atomic.LoadInt32(&self.state) == s + return atomic.LoadInt32(&self.state) == s } func (self *Node) changeState(old, neu int32) bool { - return atomic.CompareAndSwapInt32(&self.state, old, neu) + return atomic.CompareAndSwapInt32(&self.state, old, neu) } func (self *Node) getListener() *net.TCPListener { - self.metaLock.RLock() - defer self.metaLock.RUnlock() - return self.listener + self.metaLock.RLock() + defer self.metaLock.RUnlock() + return self.listener } func (self *Node) setListener(l *net.TCPListener) { - self.metaLock.Lock() - defer self.metaLock.Unlock() - self.listener = l -} -func (self *Node) setAddr(addr string) { - self.metaLock.Lock() - defer self.metaLock.Unlock() - self.addr = addr + self.metaLock.Lock() + defer self.metaLock.Unlock() + self.listener = l } // Remote returns a remote to this Node. func (self *Node) Remote() common.Remote { - return common.Remote{self.GetPosition(), self.GetAddr()} + return common.Remote{self.GetPosition(), self.GetBroadcastAddr()} } // Stop will shut down this Node permanently. func (self *Node) Stop() { - if self.changeState(started, stopped) { - self.getListener().Close() - } + if self.changeState(started, stopped) { + self.getListener().Close() + } } func (self *Node) MustStart() { - if err := self.Start(); err != nil { - panic(err) - } + if err := self.Start(); err != nil { + panic(err) + } } // Start will spin up this Node, export all its api interfaces and start its notify and ping jobs. func (self *Node) Start() (err error) { - if !self.changeState(created, started) { - return fmt.Errorf("%v can only be started when in state 'created'", self) - } - if self.GetAddr() == "" { - var foundAddr string - if foundAddr, err = findAddress(); err != nil { - return - } - self.setAddr(foundAddr) - } - var addr *net.TCPAddr - if addr, err = net.ResolveTCPAddr("tcp", self.GetAddr()); err != nil { - return - } - var listener *net.TCPListener - if listener, err = net.ListenTCP("tcp", addr); err != nil { - return - } - self.setListener(listener) - server := rpc.NewServer() - if err = server.RegisterName("Discord", (*nodeServer)(self)); err != nil { - return - } - for name, api := range self.exports { - if err = server.RegisterName(name, api); err != nil { - return - } - } - self.ring.Add(self.Remote()) - go server.Accept(self.getListener()) - go self.notifyPeriodically() - go self.pingPeriodically() - return + if !self.changeState(created, started) { + return fmt.Errorf("%v can only be started when in state 'created'", self) + } + if self.listenAddr == "" { + return fmt.Errorf("%v needs to have an address to listen at", self) + } + var addr *net.TCPAddr + if addr, err = net.ResolveTCPAddr("tcp", self.listenAddr); err != nil { + return + } + var listener *net.TCPListener + if listener, err = net.ListenTCP("tcp", addr); err != nil { + return + } + self.setListener(listener) + server := rpc.NewServer() + if err = server.RegisterName("Discord", (*nodeServer)(self)); err != nil { + return + } + for name, api := range self.exports { + if err = server.RegisterName(name, api); err != nil { + return + } + } + self.ring.Add(self.Remote()) + go func() { + var conn net.Conn + for conn, err = self.getListener().Accept(); err == nil; conn, err = self.getListener().Accept() { + go server.ServeConn(conn) + } + if !strings.Contains(err.Error(), "use of closed network connection") { + panic(err) + } + }() + go self.notifyPeriodically() + go self.pingPeriodically() + return } + func (self *Node) notifyPeriodically() { - for self.hasState(started) { - self.notifySuccessor() - time.Sleep(common.PingInterval) - } + for self.hasState(started) { + self.notifySuccessor() + time.Sleep(common.PingInterval) + } } func (self *Node) pingPeriodically() { - for self.hasState(started) { - self.pingPredecessor() - time.Sleep(common.PingInterval) - } + for self.hasState(started) { + self.pingPredecessor() + time.Sleep(common.PingInterval) + } } // RingHash returns a hash of the discord ring of this Node. func (self *Node) RingHash() []byte { - return self.ring.Hash() + return self.ring.Hash() } // Ping will compare the hash of this Node with the one in the received PingPack, and request the entire routing ring from the sender if they are not equal. func (self *Node) Ping(ping PingPack) (me common.Remote) { - me = self.Remote() - if bytes.Compare(ping.RingHash, self.ring.Hash()) != 0 { - var newNodes common.Remotes - if err := ping.Caller.Call("Discord.Nodes", 0, &newNodes); err != nil { - self.RemoveNode(ping.Caller) - } else { - self.routeLock.Lock() - defer self.routeLock.Unlock() - pred := self.ring.Predecessor(me) - self.ring.SetNodes(newNodes) - self.ring.Add(me) - self.ring.Add(pred) - self.ring.Clean(pred, me) - } - } - return + me = self.Remote() + if bytes.Compare(ping.RingHash, self.ring.Hash()) != 0 { + var newNodes common.Remotes + if err := ping.Caller.Call("Discord.Nodes", 0, &newNodes); err != nil { + self.RemoveNode(ping.Caller) + } else { + self.routeLock.Lock() + defer self.routeLock.Unlock() + pred := self.ring.Predecessor(me) + self.ring.SetNodes(newNodes) + self.ring.Add(me) + self.ring.Add(pred) + self.ring.Clean(pred, me) + } + } + return } func (self *Node) pingPredecessor() { - pred := self.GetPredecessor() - ping := PingPack{ - RingHash: self.ring.Hash(), - Caller: self.Remote(), - } - var newPred common.Remote - op := "Discord.Ping" - self.triggerCommListeners(self.Remote(), pred, op) - if err := pred.Call(op, ping, &newPred); err != nil { - self.RemoveNode(pred) - } else { - self.routeLock.Lock() - defer self.routeLock.Unlock() - self.ring.Add(newPred) - } + pred := self.GetPredecessor() + ping := PingPack{ + RingHash: self.ring.Hash(), + Caller: self.Remote(), + } + var newPred common.Remote + op := "Discord.Ping" + self.triggerCommListeners(self.Remote(), pred, op) + if err := pred.Call(op, ping, &newPred); err != nil { + self.RemoveNode(pred) + } else { + self.routeLock.Lock() + defer self.routeLock.Unlock() + self.ring.Add(newPred) + } } // Nodes will return remotes for all Nodes in the ring. func (self *Node) Nodes() common.Remotes { - return self.ring.Nodes() + return self.ring.Nodes() } // Notify will add the caller to the ring of this Node. func (self *Node) Notify(caller common.Remote) common.Remote { - self.routeLock.Lock() - defer self.routeLock.Unlock() - self.ring.Add(caller) - return self.GetPredecessor() + self.routeLock.Lock() + defer self.routeLock.Unlock() + self.ring.Add(caller) + return self.GetPredecessor() } func (self *Node) notifySuccessor() { - succ := self.GetSuccessor() - var otherPred common.Remote - op := "Discord.Notify" - selfRemote := self.Remote() - self.triggerCommListeners(selfRemote, succ, op) - if err := succ.Call(op, selfRemote, &otherPred); err != nil { - self.RemoveNode(succ) - } else { - if otherPred.Addr != self.GetAddr() { - self.routeLock.Lock() - defer self.routeLock.Unlock() - self.ring.Add(otherPred) - } - } + succ := self.GetSuccessor() + var otherPred common.Remote + op := "Discord.Notify" + selfRemote := self.Remote() + self.triggerCommListeners(selfRemote, succ, op) + if err := succ.Call(op, selfRemote, &otherPred); err != nil { + self.RemoveNode(succ) + } else { + if otherPred.Addr != self.GetBroadcastAddr() { + self.routeLock.Lock() + defer self.routeLock.Unlock() + self.ring.Add(otherPred) + } + } } func (self *Node) MustJoin(addr string) { - if err := self.Join(addr); err != nil { - panic(err) - } + if err := self.Join(addr); err != nil { + panic(err) + } } // Join will fetch the routing ring of the Node at addr, pick a location on an empty spot in the received ring and notify the other Node of our joining. func (self *Node) Join(addr string) (err error) { - var newNodes common.Remotes - if err = common.Switch.Call(addr, "Discord.Nodes", 0, &newNodes); err != nil { - return - } - if bytes.Compare(self.GetPosition(), make([]byte, murmur.Size)) == 0 { - self.SetPosition(common.NewRingNodes(newNodes).GetSlot()) - } - self.routeLock.Lock() - self.ring.SetNodes(newNodes) - self.routeLock.Unlock() - var x common.Remote - if err = common.Switch.Call(addr, "Discord.Notify", self.Remote(), &x); err != nil { - return - } - return + var newNodes common.Remotes + if err = common.Switch.Call(addr, "Discord.Nodes", 0, &newNodes); err != nil { + return + } + if bytes.Compare(self.GetPosition(), make([]byte, murmur.Size)) == 0 { + self.SetPosition(common.NewRingNodes(newNodes).GetSlot()) + } + self.routeLock.Lock() + self.ring.SetNodes(newNodes) + self.routeLock.Unlock() + var x common.Remote + if err = common.Switch.Call(addr, "Discord.Notify", self.Remote(), &x); err != nil { + return + } + return } // RemoveNode will remove the provided remote from our routing ring. func (self *Node) RemoveNode(remote common.Remote) { - if remote.Addr == self.GetAddr() { - panic(fmt.Errorf("%v is trying to remove itself from the routing!", self)) - } - self.routeLock.Lock() - defer self.routeLock.Unlock() - self.ring.Remove(remote) + if remote.Addr == self.GetBroadcastAddr() { + panic(fmt.Errorf("%v is trying to remove itself from the routing!", self)) + } + self.routeLock.Lock() + defer self.routeLock.Unlock() + self.ring.Remove(remote) } // GetPredecessor will return our predecessor on the ring. func (self *Node) GetPredecessor() common.Remote { - return self.GetPredecessorForRemote(self.Remote()) + return self.GetPredecessorForRemote(self.Remote()) } // GetPredecessorForRemote will return the predecessor for the provided remote. func (self *Node) GetPredecessorForRemote(r common.Remote) common.Remote { - return self.ring.Predecessor(r) + return self.ring.Predecessor(r) } // GetPredecessorFor will return the predecessor for the provided key. func (self *Node) GetPredecessorFor(key []byte) common.Remote { - pred, _, _ := self.ring.Remotes(key) - return *pred + pred, _, _ := self.ring.Remotes(key) + return *pred } // HasNode will return true if there is a Node on the ring with the given pos. func (self *Node) HasNode(pos []byte) bool { - if _, match, _ := self.ring.Remotes(pos); match != nil { - return true - } - return false + if _, match, _ := self.ring.Remotes(pos); match != nil { + return true + } + return false } // GetSuccessor will return our successor on the ring. func (self *Node) GetSuccessor() common.Remote { - return self.GetSuccessorForRemote(self.Remote()) + return self.GetSuccessorForRemote(self.Remote()) } -// GetSuccessorFor will return the successor for the provided remote. +// GetSuccessorForRemote will return the successor for the provided remote. func (self *Node) GetSuccessorForRemote(r common.Remote) common.Remote { - return self.ring.Successor(r) + return self.ring.Successor(r) } // GetSuccessorFor will return the successor for the provided key. // If the successor is not this Node, it will assert that the provided key is between the found successor and the predecessor it claims to have. func (self *Node) GetSuccessorFor(key []byte) common.Remote { - // Guess according to our route cache - predecessor, match, successor := self.ring.Remotes(key) - if match != nil { - predecessor = match - } - // If we consider ourselves successors, just return us - if successor.Addr != self.GetAddr() { - // Double check by asking the successor we found what predecessor it has - if err := successor.Call("Discord.GetPredecessor", 0, predecessor); err != nil { - self.RemoveNode(*successor) - return self.GetSuccessorFor(key) - } - // If the key we are looking for is between them, just return the successor - if !common.BetweenIE(key, predecessor.Pos, successor.Pos) { - // Otherwise, ask the predecessor we actually found about who is the successor of the key - if err := predecessor.Call("Discord.GetSuccessorFor", key, successor); err != nil { - self.RemoveNode(*predecessor) - return self.GetSuccessorFor(key) - } - } - } - return *successor + // Guess according to our route cache + predecessor, match, successor := self.ring.Remotes(key) + if match != nil { + predecessor = match + } + // If we consider ourselves successors, just return us + if successor.Addr != self.GetBroadcastAddr() { + // Double check by asking the successor we found what predecessor it has + if err := successor.Call("Discord.GetPredecessor", 0, predecessor); err != nil { + self.RemoveNode(*successor) + return self.GetSuccessorFor(key) + } + // If the key we are looking for is between them, just return the successor + if !common.BetweenIE(key, predecessor.Pos, successor.Pos) { + // Otherwise, ask the predecessor we actually found about who is the successor of the key + if err := predecessor.Call("Discord.GetSuccessorFor", key, successor); err != nil { + self.RemoveNode(*predecessor) + return self.GetSuccessorFor(key) + } + } + } + return *successor } diff --git a/god_cli/god_cli.go b/god_cli/god_cli.go index f2d43d8..2fd20b9 100644 --- a/god_cli/god_cli.go +++ b/god_cli/god_cli.go @@ -1,27 +1,27 @@ package main import ( - "bufio" - "encoding/hex" - "flag" - "fmt" - "github.com/zond/god/client" - "github.com/zond/god/common" - "github.com/zond/god/setop" - "io" - "math/big" - "os" - "regexp" - "strconv" - "strings" - "sync" + "bufio" + "encoding/hex" + "flag" + "fmt" + "io" + "math/big" + "os" + "regexp" + "strconv" + "strings" + "sync" + + "github.com/zond/god/client" + "github.com/zond/setop" ) const ( - stringFormat = "string" - floatFormat = "float" - intFormat = "int" - bigFormat = "big" + stringFormat = "string" + floatFormat = "float" + intFormat = "int" + bigFormat = "big" ) var formats = []string{stringFormat, floatFormat, intFormat, bigFormat} @@ -33,501 +33,501 @@ var port = flag.Int("port", 9191, "Port to connect to") var enc = flag.String("enc", stringFormat, fmt.Sprintf("What format to assume when encoding and decoding byte slices: %v", formats)) func encode(s string) []byte { - switch *enc { - case stringFormat: - return []byte(s) - case floatFormat: - result, err := strconv.ParseFloat(s, 64) - if err != nil { - panic(err) - } - return common.EncodeFloat64(result) - case intFormat: - result, err := strconv.ParseInt(s, 10, 64) - if err != nil { - panic(err) - } - return common.EncodeInt64(result) - case bigFormat: - result, ok := new(big.Int).SetString(s, 10) - if !ok { - panic(fmt.Errorf("Bad BigInt format: %v", s)) - } - return common.EncodeBigInt(result) - } - panic(fmt.Errorf("Unknown encoding: %v", *enc)) + switch *enc { + case stringFormat: + return []byte(s) + case floatFormat: + result, err := strconv.ParseFloat(s, 64) + if err != nil { + panic(err) + } + return setop.EncodeFloat64(result) + case intFormat: + result, err := strconv.ParseInt(s, 10, 64) + if err != nil { + panic(err) + } + return setop.EncodeInt64(result) + case bigFormat: + result, ok := new(big.Int).SetString(s, 10) + if !ok { + panic(fmt.Errorf("Bad BigInt format: %v", s)) + } + return setop.EncodeBigInt(result) + } + panic(fmt.Errorf("Unknown encoding: %v", *enc)) } func decode(b []byte) string { - switch *enc { - case stringFormat: - return string(b) - case floatFormat: - res, err := common.DecodeFloat64(b) - if err != nil { - return fmt.Sprint(b) - } - return fmt.Sprint(res) - case intFormat: - res, err := common.DecodeInt64(b) - if err != nil { - return fmt.Sprint(b) - } - return fmt.Sprint(res) - case bigFormat: - return fmt.Sprint(common.DecodeBigInt(b)) - } - panic(fmt.Errorf("Unknown encoding: %v", *enc)) + switch *enc { + case stringFormat: + return string(b) + case floatFormat: + res, err := setop.DecodeFloat64(b) + if err != nil { + return fmt.Sprint(b) + } + return fmt.Sprint(res) + case intFormat: + res, err := setop.DecodeInt64(b) + if err != nil { + return fmt.Sprint(b) + } + return fmt.Sprint(res) + case bigFormat: + return fmt.Sprint(setop.DecodeBigInt(b)) + } + panic(fmt.Errorf("Unknown encoding: %v", *enc)) } type actionSpec struct { - cmd string - args []*regexp.Regexp + cmd string + args []*regexp.Regexp } func newActionSpec(pattern string) (result *actionSpec) { - result = &actionSpec{} - parts := strings.Split(pattern, " ") - result.cmd = parts[0] - for _, r := range parts[1:] { - result.args = append(result.args, regexp.MustCompile(r)) - } - return + result = &actionSpec{} + parts := strings.Split(pattern, " ") + result.cmd = parts[0] + for _, r := range parts[1:] { + result.args = append(result.args, regexp.MustCompile(r)) + } + return } var actions = map[*actionSpec]action{ - newActionSpec("mirrorReverseSliceIndex \\S+ \\d+ \\d+"): mirrorReverseSliceIndex, - newActionSpec("mirrorSliceIndex \\S+ \\d+ \\d+"): mirrorSliceIndex, - newActionSpec("mirrorReverseSlice \\S+ \\S+ \\S+"): mirrorReverseSlice, - newActionSpec("mirrorSlice \\S+ \\S+ \\S+"): mirrorSlice, - newActionSpec("mirrorSliceLen \\S+ \\S+ \\d+"): mirrorSliceLen, - newActionSpec("mirrorReverseSliceLen \\S+ \\S+ \\d+"): mirrorReverseSliceLen, - newActionSpec("reverseSliceIndex \\S+ \\d+ \\d+"): reverseSliceIndex, - newActionSpec("sliceIndex \\S+ \\d+ \\d+"): sliceIndex, - newActionSpec("reverseSlice \\S+ \\S+ \\S+"): reverseSlice, - newActionSpec("slice \\S+ \\S+ \\S+"): slice, - newActionSpec("sliceLen \\S+ \\S+ \\d+"): sliceLen, - newActionSpec("reverseSliceLen \\S+ \\S+ \\d+"): reverseSliceLen, - newActionSpec("setOp .+"): setOp, - newActionSpec("dumpSetOp \\S+ .+"): dumpSetOp, - newActionSpec("put \\S+ \\S+"): put, - newActionSpec("clear"): clear, - newActionSpec("dump"): dump, - newActionSpec("subDump \\S+"): subDump, - newActionSpec("subSize \\S+"): subSize, - newActionSpec("size"): size, - newActionSpec("count \\S+ \\S+ \\S+"): count, - newActionSpec("mirrorCount \\S+ \\S+ \\S+"): mirrorCount, - newActionSpec("get \\S+"): get, - newActionSpec("del \\S+"): del, - newActionSpec("subPut \\S+ \\S+ \\S+"): subPut, - newActionSpec("subGet \\S+ \\S+"): subGet, - newActionSpec("subDel \\S+ \\S+"): subDel, - newActionSpec("subClear \\S+"): subClear, - newActionSpec("describeAll"): describeAll, - newActionSpec("describe \\S+"): describe, - newActionSpec("describeTree \\S+"): describeTree, - newActionSpec("describeAllTrees"): describeAllTrees, - newActionSpec("mirrorFirst \\S+"): mirrorFirst, - newActionSpec("mirrorLast \\S+"): mirrorLast, - newActionSpec("mirrorPrevIndex \\S+ \\d+"): mirrorPrevIndex, - newActionSpec("mirrorNextIndex \\S+ \\d+"): mirrorNextIndex, - newActionSpec("first \\S+"): first, - newActionSpec("last \\S+"): last, - newActionSpec("prevIndex \\S+ \\d+"): prevIndex, - newActionSpec("nextIndex \\S+ \\d+"): nextIndex, - newActionSpec("next \\S+"): next, - newActionSpec("prev \\S+"): prev, - newActionSpec("subMirrorNext \\S+ \\S+"): subMirrorNext, - newActionSpec("subMirrorPrev \\S+ \\S+"): subMirrorPrev, - newActionSpec("mirrorIndexOf \\S+ \\S+"): mirrorIndexOf, - newActionSpec("mirrorReverseIndexOf \\S+ \\S+"): mirrorReverseIndexOf, - newActionSpec("subNext \\S+ \\S+"): subNext, - newActionSpec("subPrev \\S+ \\S+"): subPrev, - newActionSpec("indexOf \\S+ \\S+"): indexOf, - newActionSpec("reverseIndexOf \\S+ \\S+"): reverseIndexOf, - newActionSpec("configuration"): configuration, - newActionSpec("subConfiguration \\S+"): subConfiguration, - newActionSpec("configure \\S+ \\S+"): configure, - newActionSpec("subConfigure \\S+ \\S+ \\S+"): subConfigure, + newActionSpec("mirrorReverseSliceIndex \\S+ \\d+ \\d+"): mirrorReverseSliceIndex, + newActionSpec("mirrorSliceIndex \\S+ \\d+ \\d+"): mirrorSliceIndex, + newActionSpec("mirrorReverseSlice \\S+ \\S+ \\S+"): mirrorReverseSlice, + newActionSpec("mirrorSlice \\S+ \\S+ \\S+"): mirrorSlice, + newActionSpec("mirrorSliceLen \\S+ \\S+ \\d+"): mirrorSliceLen, + newActionSpec("mirrorReverseSliceLen \\S+ \\S+ \\d+"): mirrorReverseSliceLen, + newActionSpec("reverseSliceIndex \\S+ \\d+ \\d+"): reverseSliceIndex, + newActionSpec("sliceIndex \\S+ \\d+ \\d+"): sliceIndex, + newActionSpec("reverseSlice \\S+ \\S+ \\S+"): reverseSlice, + newActionSpec("slice \\S+ \\S+ \\S+"): slice, + newActionSpec("sliceLen \\S+ \\S+ \\d+"): sliceLen, + newActionSpec("reverseSliceLen \\S+ \\S+ \\d+"): reverseSliceLen, + newActionSpec("setOp .+"): setOp, + newActionSpec("dumpSetOp \\S+ .+"): dumpSetOp, + newActionSpec("put \\S+ \\S+"): put, + newActionSpec("clear"): clear, + newActionSpec("dump"): dump, + newActionSpec("subDump \\S+"): subDump, + newActionSpec("subSize \\S+"): subSize, + newActionSpec("size"): size, + newActionSpec("count \\S+ \\S+ \\S+"): count, + newActionSpec("mirrorCount \\S+ \\S+ \\S+"): mirrorCount, + newActionSpec("get \\S+"): get, + newActionSpec("del \\S+"): del, + newActionSpec("subPut \\S+ \\S+ \\S+"): subPut, + newActionSpec("subGet \\S+ \\S+"): subGet, + newActionSpec("subDel \\S+ \\S+"): subDel, + newActionSpec("subClear \\S+"): subClear, + newActionSpec("describeAll"): describeAll, + newActionSpec("describe \\S+"): describe, + newActionSpec("describeTree \\S+"): describeTree, + newActionSpec("describeAllTrees"): describeAllTrees, + newActionSpec("mirrorFirst \\S+"): mirrorFirst, + newActionSpec("mirrorLast \\S+"): mirrorLast, + newActionSpec("mirrorPrevIndex \\S+ \\d+"): mirrorPrevIndex, + newActionSpec("mirrorNextIndex \\S+ \\d+"): mirrorNextIndex, + newActionSpec("first \\S+"): first, + newActionSpec("last \\S+"): last, + newActionSpec("prevIndex \\S+ \\d+"): prevIndex, + newActionSpec("nextIndex \\S+ \\d+"): nextIndex, + newActionSpec("next \\S+"): next, + newActionSpec("prev \\S+"): prev, + newActionSpec("subMirrorNext \\S+ \\S+"): subMirrorNext, + newActionSpec("subMirrorPrev \\S+ \\S+"): subMirrorPrev, + newActionSpec("mirrorIndexOf \\S+ \\S+"): mirrorIndexOf, + newActionSpec("mirrorReverseIndexOf \\S+ \\S+"): mirrorReverseIndexOf, + newActionSpec("subNext \\S+ \\S+"): subNext, + newActionSpec("subPrev \\S+ \\S+"): subPrev, + newActionSpec("indexOf \\S+ \\S+"): indexOf, + newActionSpec("reverseIndexOf \\S+ \\S+"): reverseIndexOf, + newActionSpec("configuration"): configuration, + newActionSpec("subConfiguration \\S+"): subConfiguration, + newActionSpec("configure \\S+ \\S+"): configure, + newActionSpec("subConfigure \\S+ \\S+ \\S+"): subConfigure, } func mustAtoi(s string) *int { - i, err := strconv.Atoi(s) - if err != nil { - panic(err) - } - return &i + i, err := strconv.Atoi(s) + if err != nil { + panic(err) + } + return &i } func configuration(conn *client.Conn, args []string) { - fmt.Println(conn.Configuration()) + fmt.Println(conn.Configuration()) } func subConfiguration(conn *client.Conn, args []string) { - fmt.Println(conn.SubConfiguration([]byte(args[1]))) + fmt.Println(conn.SubConfiguration([]byte(args[1]))) } func configure(conn *client.Conn, args []string) { - conn.AddConfiguration(args[1], args[2]) + conn.AddConfiguration(args[1], args[2]) } func subConfigure(conn *client.Conn, args []string) { - conn.SubAddConfiguration([]byte(args[1]), args[2], args[3]) + conn.SubAddConfiguration([]byte(args[1]), args[2], args[3]) } func subSize(conn *client.Conn, args []string) { - fmt.Println(conn.SubSize([]byte(args[1]))) + fmt.Println(conn.SubSize([]byte(args[1]))) } func size(conn *client.Conn, args []string) { - fmt.Println(conn.Size()) + fmt.Println(conn.Size()) } func mirrorReverseSliceIndex(conn *client.Conn, args []string) { - for _, item := range conn.MirrorReverseSliceIndex([]byte(args[1]), mustAtoi(args[2]), mustAtoi(args[3])) { - fmt.Printf("%v: %v => %v\n", item.Index, decode(item.Key), string(item.Value)) - } + for _, item := range conn.MirrorReverseSliceIndex([]byte(args[1]), mustAtoi(args[2]), mustAtoi(args[3])) { + fmt.Printf("%v: %v => %v\n", item.Index, decode(item.Key), string(item.Value)) + } } func mirrorSliceIndex(conn *client.Conn, args []string) { - for _, item := range conn.MirrorSliceIndex([]byte(args[1]), mustAtoi(args[2]), mustAtoi(args[3])) { - fmt.Printf("%v: %v => %v\n", item.Index, decode(item.Key), string(item.Value)) - } + for _, item := range conn.MirrorSliceIndex([]byte(args[1]), mustAtoi(args[2]), mustAtoi(args[3])) { + fmt.Printf("%v: %v => %v\n", item.Index, decode(item.Key), string(item.Value)) + } } func mirrorReverseSlice(conn *client.Conn, args []string) { - for i, item := range conn.MirrorReverseSlice([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false) { - fmt.Printf("%v: %v => %v\n", i, decode(item.Key), string(item.Value)) - } + for i, item := range conn.MirrorReverseSlice([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false) { + fmt.Printf("%v: %v => %v\n", i, decode(item.Key), string(item.Value)) + } } func mirrorSlice(conn *client.Conn, args []string) { - for i, item := range conn.MirrorSlice([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false) { - fmt.Printf("%v: %v => %v\n", i, decode(item.Key), string(item.Value)) - } + for i, item := range conn.MirrorSlice([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false) { + fmt.Printf("%v: %v => %v\n", i, decode(item.Key), string(item.Value)) + } } func mirrorSliceLen(conn *client.Conn, args []string) { - for _, item := range conn.MirrorSliceLen([]byte(args[1]), []byte(args[2]), true, *(mustAtoi(args[3]))) { - fmt.Printf("%v => %v\n", decode(item.Key), string(item.Value)) - } + for _, item := range conn.MirrorSliceLen([]byte(args[1]), []byte(args[2]), true, *(mustAtoi(args[3]))) { + fmt.Printf("%v => %v\n", decode(item.Key), string(item.Value)) + } } func mirrorReverseSliceLen(conn *client.Conn, args []string) { - for _, item := range conn.MirrorReverseSliceLen([]byte(args[1]), []byte(args[2]), true, *(mustAtoi(args[3]))) { - fmt.Printf("%v => %v\n", decode(item.Key), string(item.Value)) - } + for _, item := range conn.MirrorReverseSliceLen([]byte(args[1]), []byte(args[2]), true, *(mustAtoi(args[3]))) { + fmt.Printf("%v => %v\n", decode(item.Key), string(item.Value)) + } } func reverseSliceIndex(conn *client.Conn, args []string) { - for _, item := range conn.ReverseSliceIndex([]byte(args[1]), mustAtoi(args[2]), mustAtoi(args[3])) { - fmt.Printf("%v: %v => %v\n", item.Index, string(item.Key), decode(item.Value)) - } + for _, item := range conn.ReverseSliceIndex([]byte(args[1]), mustAtoi(args[2]), mustAtoi(args[3])) { + fmt.Printf("%v: %v => %v\n", item.Index, string(item.Key), decode(item.Value)) + } } func sliceIndex(conn *client.Conn, args []string) { - for _, item := range conn.SliceIndex([]byte(args[1]), mustAtoi(args[2]), mustAtoi(args[3])) { - fmt.Printf("%v: %v => %v\n", item.Index, string(item.Key), decode(item.Value)) - } + for _, item := range conn.SliceIndex([]byte(args[1]), mustAtoi(args[2]), mustAtoi(args[3])) { + fmt.Printf("%v: %v => %v\n", item.Index, string(item.Key), decode(item.Value)) + } } func reverseSlice(conn *client.Conn, args []string) { - for i, item := range conn.ReverseSlice([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false) { - fmt.Printf("%v: %v => %v\n", i, string(item.Key), decode(item.Value)) - } + for i, item := range conn.ReverseSlice([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false) { + fmt.Printf("%v: %v => %v\n", i, string(item.Key), decode(item.Value)) + } } func slice(conn *client.Conn, args []string) { - for i, item := range conn.Slice([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false) { - fmt.Printf("%v: %v => %v\n", i, string(item.Key), decode(item.Value)) - } + for i, item := range conn.Slice([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false) { + fmt.Printf("%v: %v => %v\n", i, string(item.Key), decode(item.Value)) + } } func sliceLen(conn *client.Conn, args []string) { - for _, item := range conn.SliceLen([]byte(args[1]), []byte(args[2]), true, *(mustAtoi(args[3]))) { - fmt.Printf("%v => %v\n", string(item.Key), decode(item.Value)) - } + for _, item := range conn.SliceLen([]byte(args[1]), []byte(args[2]), true, *(mustAtoi(args[3]))) { + fmt.Printf("%v => %v\n", string(item.Key), decode(item.Value)) + } } func reverseSliceLen(conn *client.Conn, args []string) { - for _, item := range conn.ReverseSliceLen([]byte(args[1]), []byte(args[2]), true, *(mustAtoi(args[3]))) { - fmt.Printf("%v => %v\n", string(item.Key), decode(item.Value)) - } + for _, item := range conn.ReverseSliceLen([]byte(args[1]), []byte(args[2]), true, *(mustAtoi(args[3]))) { + fmt.Printf("%v => %v\n", string(item.Key), decode(item.Value)) + } } func printSetOpRes(res setop.SetOpResult) { - var vals []string - for _, val := range res.Values { - vals = append(vals, decode(val)) - } - fmt.Printf("%v => %v\n", string(res.Key), vals) + var vals []string + for _, val := range res.Values { + vals = append(vals, decode(val)) + } + fmt.Printf("%v => %v\n", string(res.Key), vals) } func setOp(conn *client.Conn, args []string) { - op, err := setop.NewSetOpParser(args[1]).Parse() - if err != nil { - fmt.Println(err) - } else { - for _, res := range conn.SetExpression(setop.SetExpression{Op: op}) { - printSetOpRes(res) - } - } + op, err := setop.NewSetOpParser(args[1]).Parse() + if err != nil { + fmt.Println(err) + } else { + for _, res := range conn.SetExpression(setop.SetExpression{Op: op}) { + printSetOpRes(res) + } + } } func dumpSetOp(conn *client.Conn, args []string) { - op, err := setop.NewSetOpParser(args[2]).Parse() - if err != nil { - fmt.Println(err) - } else { - for _, res := range conn.SetExpression(setop.SetExpression{Dest: []byte(args[1]), Op: op}) { - printSetOpRes(res) - } - } + op, err := setop.NewSetOpParser(args[2]).Parse() + if err != nil { + fmt.Println(err) + } else { + for _, res := range conn.SetExpression(setop.SetExpression{Dest: []byte(args[1]), Op: op}) { + printSetOpRes(res) + } + } } func mirrorReverseIndexOf(conn *client.Conn, args []string) { - if index, existed := conn.MirrorReverseIndexOf([]byte(args[1]), []byte(args[2])); existed { - fmt.Println(index) - } + if index, existed := conn.MirrorReverseIndexOf([]byte(args[1]), []byte(args[2])); existed { + fmt.Println(index) + } } func mirrorIndexOf(conn *client.Conn, args []string) { - if index, existed := conn.MirrorIndexOf([]byte(args[1]), []byte(args[2])); existed { - fmt.Println(index) - } + if index, existed := conn.MirrorIndexOf([]byte(args[1]), []byte(args[2])); existed { + fmt.Println(index) + } } func reverseIndexOf(conn *client.Conn, args []string) { - if index, existed := conn.ReverseIndexOf([]byte(args[1]), []byte(args[2])); existed { - fmt.Println(index) - } + if index, existed := conn.ReverseIndexOf([]byte(args[1]), []byte(args[2])); existed { + fmt.Println(index) + } } func indexOf(conn *client.Conn, args []string) { - if index, existed := conn.IndexOf([]byte(args[1]), []byte(args[2])); existed { - fmt.Println(index) - } + if index, existed := conn.IndexOf([]byte(args[1]), []byte(args[2])); existed { + fmt.Println(index) + } } func show(conn *client.Conn) { - fmt.Println(conn.Describe()) + fmt.Println(conn.Describe()) } func mirrorCount(conn *client.Conn, args []string) { - fmt.Println(conn.MirrorCount([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false)) + fmt.Println(conn.MirrorCount([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false)) } func count(conn *client.Conn, args []string) { - fmt.Println(conn.Count([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false)) + fmt.Println(conn.Count([]byte(args[1]), []byte(args[2]), []byte(args[3]), true, false)) } func mirrorPrevIndex(conn *client.Conn, args []string) { - if key, value, index, existed := conn.MirrorPrevIndex([]byte(args[1]), *(mustAtoi(args[2]))); existed { - fmt.Printf("%v: %v => %v\n", index, decode(key), string(value)) - } + if key, value, index, existed := conn.MirrorPrevIndex([]byte(args[1]), *(mustAtoi(args[2]))); existed { + fmt.Printf("%v: %v => %v\n", index, decode(key), string(value)) + } } func mirrorNextIndex(conn *client.Conn, args []string) { - if key, value, index, existed := conn.MirrorNextIndex([]byte(args[1]), *(mustAtoi(args[2]))); existed { - fmt.Printf("%v: %v => %v\n", index, decode(key), string(value)) - } + if key, value, index, existed := conn.MirrorNextIndex([]byte(args[1]), *(mustAtoi(args[2]))); existed { + fmt.Printf("%v: %v => %v\n", index, decode(key), string(value)) + } } func prevIndex(conn *client.Conn, args []string) { - if key, value, index, existed := conn.PrevIndex([]byte(args[1]), *(mustAtoi(args[2]))); existed { - fmt.Printf("%v: %v => %v\n", index, string(key), decode(value)) - } + if key, value, index, existed := conn.PrevIndex([]byte(args[1]), *(mustAtoi(args[2]))); existed { + fmt.Printf("%v: %v => %v\n", index, string(key), decode(value)) + } } func nextIndex(conn *client.Conn, args []string) { - if key, value, index, existed := conn.NextIndex([]byte(args[1]), *(mustAtoi(args[2]))); existed { - fmt.Printf("%v: %v => %v\n", index, string(key), decode(value)) - } + if key, value, index, existed := conn.NextIndex([]byte(args[1]), *(mustAtoi(args[2]))); existed { + fmt.Printf("%v: %v => %v\n", index, string(key), decode(value)) + } } func prev(conn *client.Conn, args []string) { - if key, value, existed := conn.Prev([]byte(args[1])); existed { - fmt.Printf("%v => %v\n", string(key), decode(value)) - } + if key, value, existed := conn.Prev([]byte(args[1])); existed { + fmt.Printf("%v => %v\n", string(key), decode(value)) + } } func next(conn *client.Conn, args []string) { - if key, value, existed := conn.Next([]byte(args[1])); existed { - fmt.Printf("%v => %v\n", string(key), decode(value)) - } + if key, value, existed := conn.Next([]byte(args[1])); existed { + fmt.Printf("%v => %v\n", string(key), decode(value)) + } } func mirrorFirst(conn *client.Conn, args []string) { - if key, value, existed := conn.MirrorFirst([]byte(args[1])); existed { - fmt.Println(decode(key), "=>", string(value)) - } + if key, value, existed := conn.MirrorFirst([]byte(args[1])); existed { + fmt.Println(decode(key), "=>", string(value)) + } } func mirrorLast(conn *client.Conn, args []string) { - if key, value, existed := conn.MirrorLast([]byte(args[1])); existed { - fmt.Println(decode(key), "=>", string(value)) - } + if key, value, existed := conn.MirrorLast([]byte(args[1])); existed { + fmt.Println(decode(key), "=>", string(value)) + } } func first(conn *client.Conn, args []string) { - if key, value, existed := conn.First([]byte(args[1])); existed { - fmt.Println(string(key), "=>", decode(value)) - } + if key, value, existed := conn.First([]byte(args[1])); existed { + fmt.Println(string(key), "=>", decode(value)) + } } func last(conn *client.Conn, args []string) { - if key, value, existed := conn.Last([]byte(args[1])); existed { - fmt.Println(string(key), "=>", decode(value)) - } + if key, value, existed := conn.Last([]byte(args[1])); existed { + fmt.Println(string(key), "=>", decode(value)) + } } func subMirrorNext(conn *client.Conn, args []string) { - if key, value, existed := conn.SubMirrorNext([]byte(args[1]), []byte(args[2])); existed { - fmt.Printf("%v => %v\n", decode(key), string(value)) - } + if key, value, existed := conn.SubMirrorNext([]byte(args[1]), []byte(args[2])); existed { + fmt.Printf("%v => %v\n", decode(key), string(value)) + } } func subMirrorPrev(conn *client.Conn, args []string) { - if key, value, existed := conn.SubMirrorPrev([]byte(args[1]), []byte(args[2])); existed { - fmt.Printf("%v => %v\n", decode(key), string(value)) - } + if key, value, existed := conn.SubMirrorPrev([]byte(args[1]), []byte(args[2])); existed { + fmt.Printf("%v => %v\n", decode(key), string(value)) + } } func subNext(conn *client.Conn, args []string) { - if key, value, existed := conn.SubNext([]byte(args[1]), []byte(args[2])); existed { - fmt.Printf("%v => %v\n", string(key), decode(value)) - } + if key, value, existed := conn.SubNext([]byte(args[1]), []byte(args[2])); existed { + fmt.Printf("%v => %v\n", string(key), decode(value)) + } } func subPrev(conn *client.Conn, args []string) { - if key, value, existed := conn.SubPrev([]byte(args[1]), []byte(args[2])); existed { - fmt.Printf("%v => %v\n", string(key), decode(value)) - } + if key, value, existed := conn.SubPrev([]byte(args[1]), []byte(args[2])); existed { + fmt.Printf("%v => %v\n", string(key), decode(value)) + } } func describeAll(conn *client.Conn, args []string) { - for _, description := range conn.DescribeAllNodes() { - fmt.Println(description.Describe()) - } + for _, description := range conn.DescribeAllNodes() { + fmt.Println(description.Describe()) + } } func describeAllTrees(conn *client.Conn, args []string) { - fmt.Print(conn.DescribeAllTrees()) + fmt.Print(conn.DescribeAllTrees()) } func describe(conn *client.Conn, args []string) { - if bytes, err := hex.DecodeString(args[1]); err != nil { - fmt.Println(err) - } else { - if result, err := conn.DescribeNode(bytes); err != nil { - fmt.Println(err) - } else { - fmt.Println(result.Describe()) - } - } + if bytes, err := hex.DecodeString(args[1]); err != nil { + fmt.Println(err) + } else { + if result, err := conn.DescribeNode(bytes); err != nil { + fmt.Println(err) + } else { + fmt.Println(result.Describe()) + } + } } func describeTree(conn *client.Conn, args []string) { - if bytes, err := hex.DecodeString(args[1]); err != nil { - fmt.Println(err) - } else { - if result, err := conn.DescribeTree(bytes); err != nil { - fmt.Println(err) - } else { - fmt.Println(result) - } - } + if bytes, err := hex.DecodeString(args[1]); err != nil { + fmt.Println(err) + } else { + if result, err := conn.DescribeTree(bytes); err != nil { + fmt.Println(err) + } else { + fmt.Println(result) + } + } } func get(conn *client.Conn, args []string) { - if value, existed := conn.Get([]byte(args[1])); existed { - fmt.Printf("%v\n", decode(value)) - } + if value, existed := conn.Get([]byte(args[1])); existed { + fmt.Printf("%v\n", decode(value)) + } } func subGet(conn *client.Conn, args []string) { - if value, existed := conn.SubGet([]byte(args[1]), []byte(args[2])); existed { - fmt.Printf("%v\n", decode(value)) - } + if value, existed := conn.SubGet([]byte(args[1]), []byte(args[2])); existed { + fmt.Printf("%v\n", decode(value)) + } } func clear(conn *client.Conn, args []string) { - conn.Clear() + conn.Clear() } func dump(conn *client.Conn, args []string) { - dump, wait := conn.Dump() - linedump(dump, wait) + dump, wait := conn.Dump() + linedump(dump, wait) } func subDump(conn *client.Conn, args []string) { - dump, wait := conn.SubDump([]byte(args[1])) - linedump(dump, wait) + dump, wait := conn.SubDump([]byte(args[1])) + linedump(dump, wait) } func linedump(dump chan [2][]byte, wait *sync.WaitGroup) { - defer func() { - close(dump) - wait.Wait() - }() - reader := bufio.NewReader(os.Stdin) - var pair []string - var line string - var err error - for line, err = reader.ReadString('\n'); err == nil; line, err = reader.ReadString('\n') { - pair = strings.Split(strings.TrimSpace(line), "=") - if len(pair) == 2 { - dump <- [2][]byte{[]byte(pair[0]), encode(pair[1])} - } else { - return - } - } - if err != io.EOF { - fmt.Println(err) - } + defer func() { + close(dump) + wait.Wait() + }() + reader := bufio.NewReader(os.Stdin) + var pair []string + var line string + var err error + for line, err = reader.ReadString('\n'); err == nil; line, err = reader.ReadString('\n') { + pair = strings.Split(strings.TrimSpace(line), "=") + if len(pair) == 2 { + dump <- [2][]byte{[]byte(pair[0]), encode(pair[1])} + } else { + return + } + } + if err != io.EOF { + fmt.Println(err) + } } func put(conn *client.Conn, args []string) { - conn.Put([]byte(args[1]), encode(args[2])) + conn.Put([]byte(args[1]), encode(args[2])) } func subPut(conn *client.Conn, args []string) { - conn.SubPut([]byte(args[1]), []byte(args[2]), encode(args[3])) + conn.SubPut([]byte(args[1]), []byte(args[2]), encode(args[3])) } func subClear(conn *client.Conn, args []string) { - conn.SubClear([]byte(args[1])) + conn.SubClear([]byte(args[1])) } func subDel(conn *client.Conn, args []string) { - conn.SubDel([]byte(args[1]), []byte(args[2])) + conn.SubDel([]byte(args[1]), []byte(args[2])) } func del(conn *client.Conn, args []string) { - conn.Del([]byte(args[1])) + conn.Del([]byte(args[1])) } func main() { - flag.Parse() - conn := client.MustConn(fmt.Sprintf("%v:%v", *ip, *port)) - if len(flag.Args()) == 0 { - show(conn) - } else { - for spec, fun := range actions { - if spec.cmd == flag.Args()[0] { - matchingParts := true - for index, reg := range spec.args { - if !reg.MatchString(flag.Args()[index+1]) { - matchingParts = false - break - } - } - if matchingParts { - fun(conn, flag.Args()) - return - } - } - } - fmt.Println("No command given?") - } + flag.Parse() + conn := client.MustConn(fmt.Sprintf("%v:%v", *ip, *port)) + if len(flag.Args()) == 0 { + show(conn) + } else { + for spec, fun := range actions { + if spec.cmd == flag.Args()[0] { + matchingParts := true + for index, reg := range spec.args { + if !reg.MatchString(flag.Args()[index+1]) { + matchingParts = false + break + } + } + if matchingParts { + fun(conn, flag.Args()) + return + } + } + } + fmt.Println("No command given?") + } } diff --git a/god_server/god_server.go b/god_server/god_server.go index a2c556d..b7ce8ce 100644 --- a/god_server/god_server.go +++ b/god_server/god_server.go @@ -1,19 +1,19 @@ package main import ( - "flag" - "fmt" - "github.com/zond/god/common" - "github.com/zond/god/dhash" - "runtime" - "time" + "flag" + "fmt" + "github.com/zond/god/common" + "github.com/zond/god/dhash" + "runtime" ) const ( - address = "address" + address = "address" ) -var ip = flag.String("ip", "127.0.0.1", "IP address to listen to.") +var listenIp = flag.String("listenIp", "127.0.0.1", "IP address to listen at.") +var broadcastIp = flag.String("broadcastIp", "127.0.0.1", "IP address to broadcast to the cluster.") var port = flag.Int("port", 9191, "Port to listen to for net/rpc connections. The next port will be used for the HTTP service.") var joinIp = flag.String("joinIp", "", "IP address to join.") var joinPort = flag.Int("joinPort", 9191, "Port to join.") @@ -21,36 +21,34 @@ var verbose = flag.Bool("verbose", false, "Whether the server should be log verb var dir = flag.String("dir", address, "Where to store logfiles and snapshots. Defaults to a directory named after the listening ip/port. The empty string will turn off persistence.") func main() { - runtime.GOMAXPROCS(runtime.NumCPU()) - flag.Parse() - if *dir == address { - *dir = fmt.Sprintf("%v:%v", *ip, *port) - } - s := dhash.NewNodeDir(fmt.Sprintf("%v:%v", *ip, *port), *dir) - if *verbose { - s.AddChangeListener(func(ring *common.Ring) bool { - fmt.Println(s.Describe()) - return true - }) - s.AddMigrateListener(func(dhash *dhash.Node, source, destination []byte) bool { - fmt.Printf("Migrated from %v to %v\n", common.HexEncode(source), common.HexEncode(destination)) - return true - }) - s.AddSyncListener(func(source, dest common.Remote, pulled, pushed int) bool { - fmt.Printf("%v pulled %v and pushed %v keys synchronizing with %v\n", source.Addr, pulled, pushed, dest.Addr) - return true - }) - s.AddCleanListener(func(source, dest common.Remote, cleaned, pushed int) bool { - fmt.Printf("%v cleaned %v and pushed %v keys to %v\n", source.Addr, cleaned, pushed, dest.Addr) - return true - }) - } - s.MustStart() - if *joinIp != "" { - s.MustJoin(fmt.Sprintf("%v:%v", *joinIp, *joinPort)) - } + runtime.GOMAXPROCS(runtime.NumCPU()) + flag.Parse() + if *dir == address { + *dir = fmt.Sprintf("%v_%v", *broadcastIp, *port) + } + s := dhash.NewNodeDir(fmt.Sprintf("%v:%v", *listenIp, *port), fmt.Sprintf("%v:%v", *broadcastIp, *port), *dir) + if *verbose { + s.AddChangeListener(func(ring *common.Ring) bool { + fmt.Println(s.Describe()) + return true + }) + s.AddMigrateListener(func(dhash *dhash.Node, source, destination []byte) bool { + fmt.Printf("Migrated from %v to %v\n", common.HexEncode(source), common.HexEncode(destination)) + return true + }) + s.AddSyncListener(func(source, dest common.Remote, pulled, pushed int) bool { + fmt.Printf("%v pulled %v and pushed %v keys synchronizing with %v\n", source.Addr, pulled, pushed, dest.Addr) + return true + }) + s.AddCleanListener(func(source, dest common.Remote, cleaned, pushed int) bool { + fmt.Printf("%v cleaned %v and pushed %v keys to %v\n", source.Addr, cleaned, pushed, dest.Addr) + return true + }) + } + s.MustStart() + if *joinIp != "" { + s.MustJoin(fmt.Sprintf("%v:%v", *joinIp, *joinPort)) + } - for { - time.Sleep(time.Second * 10) - } + select {} } diff --git a/murmur/README.md b/murmur/README.md index 9fe3221..57cdd15 100644 --- a/murmur/README.md +++ b/murmur/README.md @@ -1,4 +1,4 @@ murmur === -A thin wrapper around the 128 bit x64 version of http://code.google.com/p/smhasher/wiki/MurmurHash3, a fast, non cryptographically secure but well distributed hash function. +A thin wrapper around https://github.com/spaolacci/murmur3, a Go native and very fast murmur3 implementation. diff --git a/murmur/murmur.c b/murmur/murmur.c deleted file mode 100644 index 0b061b4..0000000 --- a/murmur/murmur.c +++ /dev/null @@ -1,115 +0,0 @@ - -#include "murmur.h" - -inline uint64_t rotl64 ( uint64_t x, int8_t r ) -{ - return (x << r) | (x >> (64 - r)); -} - -#define ROTL64(x,y) rotl64(x,y) - -#define BIG_CONSTANT(x) (x##LLU) - -//----------------------------------------------------------------------------- -// Block read - if your platform needs to do endian-swapping or can only -// handle aligned reads, do the conversion here - -uint64_t getblock ( const uint64_t * p, int i ) -{ - return p[i]; -} - -//----------------------------------------------------------------------------- -// Finalization mix - force all bits of a hash block to avalanche - -uint64_t fmix ( uint64_t k ) -{ - k ^= k >> 33; - k *= BIG_CONSTANT(0xff51afd7ed558ccd); - k ^= k >> 33; - k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); - k ^= k >> 33; - - return k; -} - -//----------------------------------------------------------------------------- -void MurmurHash3_x64_128 ( const void * key, const int len, - const uint32_t seed, void * out ) -{ - const uint8_t * data = (const uint8_t*)key; - const int nblocks = len / 16; - - uint64_t h1 = seed; - uint64_t h2 = seed; - - const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5); - const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f); - - //---------- - // body - - const uint64_t * blocks = (const uint64_t *)(data); - - int i; - for(i = 0; i < nblocks; i++) - { - uint64_t k1 = getblock(blocks,i*2+0); - uint64_t k2 = getblock(blocks,i*2+1); - - k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; - - h1 = ROTL64(h1,27); h1 += h2; h1 = h1*5+0x52dce729; - - k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; - - h2 = ROTL64(h2,31); h2 += h1; h2 = h2*5+0x38495ab5; - } - - //---------- - // tail - - const uint8_t * tail = (const uint8_t*)(data + nblocks*16); - - uint64_t k1 = 0; - uint64_t k2 = 0; - - switch(len & 15) - { - case 15: k2 ^= ((uint64_t) (tail[14])) << 48; - case 14: k2 ^= ((uint64_t) (tail[13])) << 40; - case 13: k2 ^= ((uint64_t) (tail[12])) << 32; - case 12: k2 ^= ((uint64_t) (tail[11])) << 24; - case 11: k2 ^= ((uint64_t) (tail[10])) << 16; - case 10: k2 ^= ((uint64_t) (tail[ 9])) << 8; - case 9: k2 ^= ((uint64_t) (tail[ 8])) << 0; - k2 *= c2; k2 = ROTL64(k2,33); k2 *= c1; h2 ^= k2; - - case 8: k1 ^= ((uint64_t) (tail[ 7])) << 56; - case 7: k1 ^= ((uint64_t) (tail[ 6])) << 48; - case 6: k1 ^= ((uint64_t) (tail[ 5])) << 40; - case 5: k1 ^= ((uint64_t) (tail[ 4])) << 32; - case 4: k1 ^= ((uint64_t) (tail[ 3])) << 24; - case 3: k1 ^= ((uint64_t) (tail[ 2])) << 16; - case 2: k1 ^= ((uint64_t) (tail[ 1])) << 8; - case 1: k1 ^= ((uint64_t) (tail[ 0])) << 0; - k1 *= c1; k1 = ROTL64(k1,31); k1 *= c2; h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; h2 ^= len; - - h1 += h2; - h2 += h1; - - h1 = fmix(h1); - h2 = fmix(h2); - - h1 += h2; - h2 += h1; - - ((uint64_t*)out)[0] = h1; - ((uint64_t*)out)[1] = h2; -} diff --git a/murmur/murmur.go b/murmur/murmur.go index 7d7b589..295e494 100644 --- a/murmur/murmur.go +++ b/murmur/murmur.go @@ -1,126 +1,98 @@ package murmur import ( - "bytes" - "encoding/binary" - "fmt" - "unsafe" + "bytes" + "encoding/binary" + "fmt" + "github.com/spaolacci/murmur3" ) -/* -#include "murmur.h" -*/ -import "C" - -func init() { - if unsafe.Sizeof(new(C.uint64_t)) != 8 { - panic("C.word64 is not 8 bytes long!") - } -} - const ( - BlockSize = 1 - Size = 16 - seed = 42 + BlockSize = 1 + Size = 16 + seed = 42 ) // HashString will return the hash for the provided string. func HashString(s string) []byte { - return NewBytes([]byte(s)).Get() + return HashBytes([]byte(s)) } // HashInt will return the hash for the provided int. func HashInt(i int) []byte { - b := new(bytes.Buffer) - if err := binary.Write(b, binary.BigEndian, i); err != nil { - panic(err) - } - return NewBytes(b.Bytes()).Get() + b := new(bytes.Buffer) + if err := binary.Write(b, binary.BigEndian, i); err != nil { + panic(err) + } + return HashBytes(b.Bytes()) } // HashInt64 will return the hash for the provided int64. func HashInt64(i int64) []byte { - b := new(bytes.Buffer) - if err := binary.Write(b, binary.BigEndian, i); err != nil { - panic(err) - } - return NewBytes(b.Bytes()).Get() + b := new(bytes.Buffer) + if err := binary.Write(b, binary.BigEndian, i); err != nil { + panic(err) + } + return HashBytes(b.Bytes()) } // HashBytes will return the hash for the provided byte slice. func HashBytes(b []byte) []byte { - return NewBytes(b).Get() + h1, h2 := murmur3.Sum128(b) + return []byte{ + byte(h1 >> 56), byte(h1 >> 48), byte(h1 >> 40), byte(h1 >> 32), + byte(h1 >> 24), byte(h1 >> 16), byte(h1 >> 8), byte(h1), + byte(h2 >> 56), byte(h2 >> 48), byte(h2 >> 40), byte(h2 >> 32), + byte(h2 >> 24), byte(h2 >> 16), byte(h2 >> 8), byte(h2), + } } -// Hash is a thin thin wrapper around the reference implementation of http://code.google.com/p/smhasher/wiki/MurmurHash3 modified slightly to compile with a C compiler. type Hash bytes.Buffer func New() *Hash { - return new(Hash) -} - -// NewString will return a Hash that has already consumed the provided string. -func NewString(s string) *Hash { - return (*Hash)(bytes.NewBufferString(s)) + return new(Hash) } -// NewBytes will return a Hash that has already consumed the provided byte slice. -func NewBytes(b []byte) *Hash { - return (*Hash)(bytes.NewBuffer(b)) +func (self *Hash) MustWrite(b []byte) { + n, err := (*bytes.Buffer)(self).Write(b) + if n != len(b) || err != nil { + panic(fmt.Errorf("Wanted to write %v bytes, but wrote %v and got %v", len(b), n, err)) + } } -// Get will return the hash for all consumed data. -func (self *Hash) Get() (result []byte) { - result = make([]byte, Size) - self.Extrude(&result) - return +func (self *Hash) Get() []byte { + return HashBytes((*bytes.Buffer)(self).Bytes()) } -// Extrude will fill the provided slice with the hash for all consumed data. -// Extrude is slightly less allocating than Get, if that kind of thing is of interest. -func (self *Hash) Extrude(result *[]byte) { - buf := (*bytes.Buffer)(self).Bytes() - C.MurmurHash3_x64_128( - *(*unsafe.Pointer)(unsafe.Pointer(&buf)), - C.int(len(buf)), - C.uint32_t(seed), - *(*unsafe.Pointer)(unsafe.Pointer(result))) - self.Reset() -} - -// Sum will consume the given bytes and return the hash for all consumed data. -func (self *Hash) Sum(p []byte) []byte { - (*bytes.Buffer)(self).Write(p) - return self.Get() -} - -func (self *Hash) MustWriteInt64(i int64) { - b := new(bytes.Buffer) - if err := binary.Write(b, binary.BigEndian, i); err != nil { - panic(err) - } - self.MustWrite(b.Bytes()) -} - -// MustWrite will consume the provided bytes. -func (self *Hash) MustWrite(p []byte) { - if i, err := (*bytes.Buffer)(self).Write(p); i != len(p) || err != nil { - panic(fmt.Errorf("When Writing %v to %v, got %v, %v", p, self, i, err)) - } -} - -// Write will consume the provided bytes, or return an error. -func (self *Hash) Write(p []byte) (n int, err error) { - return (*bytes.Buffer)(self).Write(p) +func NewBytes(b []byte) *Hash { + return (*Hash)(bytes.NewBuffer(b)) } -// Reset will forget all consumed data. -func (self *Hash) Reset() { - (*bytes.Buffer)(self).Truncate(0) -} -func (self *Hash) Size() int { - return 3 * 8 -} -func (self *Hash) BlockSize() int { - return 8 +func NewString(s string) *Hash { + return (*Hash)(bytes.NewBufferString(s)) +} + +func (self *Hash) Write(b []byte) (int, error) { + self.MustWrite(b) + return len(b), nil +} + +func (self *Hash) Extrude(result []byte) { + h1, h2 := murmur3.Sum128((*bytes.Buffer)(self).Bytes()) + result[0] = byte(h1 >> 56) + result[1] = byte(h1 >> 48) + result[2] = byte(h1 >> 40) + result[3] = byte(h1 >> 32) + result[4] = byte(h1 >> 24) + result[5] = byte(h1 >> 16) + result[6] = byte(h1 >> 8) + result[7] = byte(h1) + result[8] = byte(h2 >> 56) + result[9] = byte(h2 >> 48) + result[10] = byte(h2 >> 40) + result[11] = byte(h2 >> 32) + result[12] = byte(h2 >> 24) + result[13] = byte(h2 >> 16) + result[14] = byte(h2 >> 8) + result[15] = byte(h2) } diff --git a/murmur/murmur.h b/murmur/murmur.h deleted file mode 100644 index f50a3f5..0000000 --- a/murmur/murmur.h +++ /dev/null @@ -1,4 +0,0 @@ - -#include - -void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out ); diff --git a/murmur/murmur_test.go b/murmur/murmur_test.go index 9934bda..c0607e4 100644 --- a/murmur/murmur_test.go +++ b/murmur/murmur_test.go @@ -13,12 +13,11 @@ func init() { } func TestMurmur(t *testing.T) { - h := &Hash{} m := make(map[string]bool) for i := 0; i < 1000000; i++ { s := fmt.Sprint(rand.Int63()) - c1 := h.Sum([]byte(s)) - c2 := h.Sum([]byte(s)) + c1 := HashBytes([]byte(s)) + c2 := HashBytes([]byte(s)) if string(c1) != string(c2) { t.Errorf("%v should == %v", c1, c2) } @@ -32,13 +31,12 @@ func TestMurmur(t *testing.T) { func BenchmarkMurmur(b *testing.B) { b.StopTimer() var v [][]byte - t := &Hash{} for i := 0; i < b.N; i++ { v = append(v, []byte(fmt.Sprint(rand.Int63()))) } b.StartTimer() for _, n := range v { - t.Sum(n) + HashBytes(n) } } @@ -51,6 +49,7 @@ func BenchmarkSHA1(b *testing.B) { } b.StartTimer() for _, n := range v { - t.Sum(n) + t.Write(n) + t.Sum(nil) } } diff --git a/radix/node.go b/radix/node.go index 92d8e45..7bb65f1 100644 --- a/radix/node.go +++ b/radix/node.go @@ -1,21 +1,21 @@ package radix import ( - "bytes" - "encoding/hex" - "fmt" - "github.com/zond/god/murmur" - "strings" - "time" + "bytes" + "encoding/hex" + "fmt" + "github.com/zond/god/murmur" + "strings" + "time" ) const ( - byteValue = 1 << iota - treeValue + byteValue = 1 << iota + treeValue ) const ( - zombieLifetime = int64(time.Hour * 24) + zombieLifetime = int64(time.Hour * 24) ) type nodeIndexIterator func(key, byteValue []byte, treeValue *Tree, use int, timestamp int64, index int) (cont bool) @@ -31,39 +31,39 @@ type nodeIterator func(key, byteValue []byte, treeValue *Tree, use int, timestam // node.use != 0 && node.empty => node is invalid? // node.empty && node.timestamp == 0 => node is invalid? type node struct { - segment []Nibble // the bit of the key for this node that separates it from its parent - byteValue []byte - byteHash []byte // cached hash of the byteValue - treeValue *Tree - timestamp int64 // only used in regard to byteValues. treeValues ignore them (since they have their own timestamps inside them). a timestamp of 0 will be considered REALLY empty - hash []byte // cached hash of the entire node - children []*node - empty bool // this node only serves a structural purpose (ie remove it if it is no longer useful for that) - use int // the values in this node that are to be considered 'present'. even if this is a zero, do not remove the node if empty is false - it is still a tombstone. - treeSize int // size of the tree in this node and those of all of its children - byteSize int // number of byte values in this node and all of its children - realSize int // number of actual values, including tombstones + segment []Nibble // the bit of the key for this node that separates it from its parent + byteValue []byte + byteHash []byte // cached hash of the byteValue + treeValue *Tree + timestamp int64 // only used in regard to byteValues. treeValues ignore them (since they have their own timestamps inside them). a timestamp of 0 will be considered REALLY empty + hash []byte // cached hash of the entire node + children []*node + empty bool // this node only serves a structural purpose (ie remove it if it is no longer useful for that) + use int // the values in this node that are to be considered 'present'. even if this is a zero, do not remove the node if empty is false - it is still a tombstone. + treeSize int // size of the tree in this node and those of all of its children + byteSize int // number of byte values in this node and all of its children + realSize int // number of actual values, including tombstones } func newNode(segment []Nibble, byteValue []byte, treeValue *Tree, timestamp int64, empty bool, use int) *node { - return &node{ - segment: segment, - byteValue: byteValue, - byteHash: murmur.HashBytes(byteValue), - treeValue: treeValue, - timestamp: timestamp, - hash: make([]byte, murmur.Size), - children: make([]*node, 1<<(8/parts)), - empty: empty, - use: use, - } + return &node{ + segment: segment, + byteValue: byteValue, + byteHash: murmur.HashBytes(byteValue), + treeValue: treeValue, + timestamp: timestamp, + hash: make([]byte, murmur.Size), + children: make([]*node, 1<<(8/parts)), + empty: empty, + use: use, + } } // setSegment copies the given part to be our segment. func (self *node) setSegment(part []Nibble) { - new_segment := make([]Nibble, len(part)) - copy(new_segment, part) - self.segment = new_segment + new_segment := make([]Nibble, len(part)) + copy(new_segment, part) + self.segment = new_segment } // rehash will recount the size of this node by summing the sizes of its own data and @@ -74,346 +74,365 @@ func (self *node) setSegment(part []Nibble) { // // Finally it will remove any children that are timed out tombstones. func (self *node) rehash(key []Nibble, now int64) { - self.treeSize = 0 - self.byteSize = 0 - self.realSize = 0 - self.realSize += self.treeValue.RealSize() - if self.timestamp != 0 { - self.realSize++ - } - if self.use&treeValue != 0 { - self.treeSize = self.treeValue.Size() - } - if self.use&byteValue != 0 { - self.byteSize = 1 - } - h := murmur.NewBytes(toBytes(key)) - h.Write(self.byteHash) - h.Write(self.treeValue.Hash()) + self.treeSize = 0 + self.byteSize = 0 + self.realSize = 0 + self.realSize += self.treeValue.RealSize() + if self.timestamp != 0 { + self.realSize++ + } + if self.use&treeValue != 0 { + self.treeSize = self.treeValue.Size() + } + if self.use&byteValue != 0 { + self.byteSize = 1 + } + h := murmur.NewBytes(toBytes(key)) + h.Write(self.byteHash) + h.Write(self.treeValue.Hash()) - var child *node - for index := 0; index < len(self.children); index++ { - self.children[index] = self.children[index].gc(key, now) + var child *node + for index := 0; index < len(self.children); index++ { + self.children[index] = self.children[index].gc(key, now) - child = self.children[index] - if child != nil { - self.treeSize += child.treeSize - self.byteSize += child.byteSize - self.realSize += child.realSize - h.Write(child.hash) - } - } - h.Extrude(&self.hash) + child = self.children[index] + if child != nil { + self.treeSize += child.treeSize + self.byteSize += child.byteSize + self.realSize += child.realSize + h.Write(child.hash) + } + } + h.Extrude(self.hash) } + +// gc will garbage collect old tombstones. +// If this node is an old tombstone, a replacement child will be returned. +// If this node contains a tree which is empty and too old, it will be removed. func (self *node) gc(prefix []Nibble, now int64) (result *node) { - if self == nil { - return self - } - if !self.empty && self.use&treeValue == treeValue && self.treeValue.Size() == 0 && self.treeValue.dataTimestamp < now-zombieLifetime { - self.treeValue, self.use = nil, self.use&^treeValue - } - if !self.empty && self.use == 0 && self.timestamp < now-zombieLifetime { - result, _, _, _, _ = self.del(prefix, self.segment, 0, now) - } else { - result = self - } - return + if self == nil { + return self + } + if !self.empty && self.use&treeValue == treeValue && self.treeValue.Size() == 0 && self.treeValue.dataTimestamp < now-zombieLifetime { + self.treeValue, self.use = nil, self.use&^treeValue + } + if !self.empty && self.use == 0 && self.timestamp < now-zombieLifetime { + result, _, _, _, _ = self.del(prefix, self.segment, 0, now) + } else { + result = self + } + return } func (self *node) describe(indent int, buffer *bytes.Buffer) { - if self == nil { - return - } - indentation := &bytes.Buffer{} - for i := 0; i < indent; i++ { - fmt.Fprint(indentation, " ") - } - encodedSegment := stringEncode(toBytes(self.segment)) - keyHeader := fmt.Sprintf("%v%#v (%v/%v/%v, %v, %v, %v, %v) => ", string(indentation.Bytes()), encodedSegment, self.byteSize, self.treeSize, self.realSize, self.empty, self.use, self.timestamp, hex.EncodeToString(self.hash)) - if self.empty { - fmt.Fprintf(buffer, "%v\n", keyHeader) - } else { - fmt.Fprintf(buffer, "%v%v\n", keyHeader, strings.Trim(self.treeValue.describeIndented(0, len(keyHeader)), "\n")) - fmt.Fprintf(buffer, "%v%v\n", keyHeader, self.byteValue) - } - for _, child := range self.children { - child.describe(indent+len(encodedSegment), buffer) - } + if self == nil { + return + } + indentation := &bytes.Buffer{} + for i := 0; i < indent; i++ { + fmt.Fprint(indentation, " ") + } + encodedSegment := stringEncode(toBytes(self.segment)) + keyHeader := fmt.Sprintf("%v%#v (%v/%v/%v, %v, %v, %v, %v) => ", string(indentation.Bytes()), encodedSegment, self.byteSize, self.treeSize, self.realSize, self.empty, self.use, self.timestamp, hex.EncodeToString(self.hash)) + if self.empty { + fmt.Fprintf(buffer, "%v\n", keyHeader) + } else { + fmt.Fprintf(buffer, "%v%v\n", keyHeader, strings.Trim(self.treeValue.describeIndented(0, len(keyHeader)), "\n")) + fmt.Fprintf(buffer, "%v%v\n", keyHeader, self.byteValue) + } + for _, child := range self.children { + child.describe(indent+len(encodedSegment), buffer) + } } + +// finger will return a finger print of this node to use when comparing trees in Sync. func (self *node) finger(allocated *Print, segment []Nibble) (result *Print) { - result = allocated - if self == nil { - return - } - allocated.push(self) - beyond_self := false - beyond_segment := false - for i := 0; ; i++ { - beyond_self = i >= len(self.segment) - beyond_segment = i >= len(segment) - if beyond_self && beyond_segment { - allocated.set(self) - return - } else if beyond_segment { - return - } else if beyond_self { - return self.children[segment[i]].finger(allocated, segment[i:]) - } else if segment[i] != self.segment[i] { - return - } - } - panic("Shouldn't happen") + result = allocated + if self == nil { + return + } + allocated.push(self) + beyond_self := false + beyond_segment := false + for i := 0; ; i++ { + beyond_self = i >= len(self.segment) + beyond_segment = i >= len(segment) + if beyond_self && beyond_segment { + allocated.set(self) + return + } else if beyond_segment { + return + } else if beyond_self { + return self.children[segment[i]].finger(allocated, segment[i:]) + } else if segment[i] != self.segment[i] { + return + } + } + panic("Shouldn't happen") } + +// indexOf will return the index of the given segment, considering the data type defined by use (byteValue and/or treeValue). +// It will count from the start if up, else from the end. func (self *node) indexOf(count int, segment []Nibble, use int, up bool) (index int, existed int) { - beyond_self := false - beyond_segment := false - for i := 0; ; i++ { - beyond_self = i >= len(self.segment) - beyond_segment = i >= len(segment) - if beyond_self && beyond_segment { - index, existed = count, self.use - return - } else if beyond_segment { - return - } else if beyond_self { - if !self.empty { - if use == 0 || use&byteValue&self.use != 0 { - count++ - } - if use == 0 || use&treeValue&self.use != 0 { - count += self.treeValue.Size() - } - } - start, step, stop := 0, 1, len(self.children) - if !up { - start, step, stop = len(self.children)-1, -1, -1 - } - var child *node - for j := start; j != stop; j += step { - child = self.children[j] - if child != nil { - if (up && j < int(segment[i])) || (!up && j > int(segment[i])) { - if use == 0 { - count += child.realSize - } else { - if use&byteValue != 0 { - count += child.byteSize - } - if use&treeValue != 0 { - count += child.treeSize - } - } - } else { - index, existed = child.indexOf(count, segment[i:], use, up) - return - } - } - } - index, existed = count, 0 - return - } else if segment[i] != self.segment[i] { - if up { - if segment[i] < self.segment[i] { - index, existed = count, 0 - } else { - index, existed = count+1, 0 - } - } else { - if segment[i] > self.segment[i] { - index, existed = count, 0 - } else { - for _, child := range self.children { - if child != nil { - if use == 0 { - count += child.realSize - } else { - if use&byteValue != 0 { - count += child.byteSize - } - if use&treeValue != 0 { - count += child.treeSize - } - } - } - } - index, existed = count, 0 - } - } - return - } - } - panic("Shouldn't happen") + beyond_self := false + beyond_segment := false + for i := 0; ; i++ { + beyond_self = i >= len(self.segment) + beyond_segment = i >= len(segment) + if beyond_self && beyond_segment { + index, existed = count, self.use + return + } else if beyond_segment { + return + } else if beyond_self { + if !self.empty { + if use == 0 || use&byteValue&self.use != 0 { + count++ + } + if use == 0 || use&treeValue&self.use != 0 { + count += self.treeValue.Size() + } + } + start, step, stop := 0, 1, len(self.children) + if !up { + start, step, stop = len(self.children)-1, -1, -1 + } + var child *node + for j := start; j != stop; j += step { + child = self.children[j] + if child != nil { + if (up && j < int(segment[i])) || (!up && j > int(segment[i])) { + if use == 0 { + count += child.realSize + } else { + if use&byteValue != 0 { + count += child.byteSize + } + if use&treeValue != 0 { + count += child.treeSize + } + } + } else { + index, existed = child.indexOf(count, segment[i:], use, up) + return + } + } + } + index, existed = count, 0 + return + } else if segment[i] != self.segment[i] { + if up { + if segment[i] < self.segment[i] { + index, existed = count, 0 + } else { + index, existed = count+1, 0 + } + } else { + if segment[i] > self.segment[i] { + index, existed = count, 0 + } else { + for _, child := range self.children { + if child != nil { + if use == 0 { + count += child.realSize + } else { + if use&byteValue != 0 { + count += child.byteSize + } + if use&treeValue != 0 { + count += child.treeSize + } + } + } + } + index, existed = count, 0 + } + } + return + } + } + panic("Shouldn't happen") } + +// get will return values for the given key, if it exists func (self *node) get(segment []Nibble) (byteValue []byte, treeValue *Tree, timestamp int64, existed int) { - if self == nil { - return - } - beyond_self := false - beyond_segment := false - for i := 0; ; i++ { - beyond_self = i >= len(self.segment) - beyond_segment = i >= len(segment) - if beyond_self && beyond_segment { - byteValue, treeValue, timestamp, existed = self.byteValue, self.treeValue, self.timestamp, self.use - return - } else if beyond_segment { - return - } else if beyond_self { - byteValue, treeValue, timestamp, existed = self.children[segment[i]].get(segment[i:]) - return - } else if segment[i] != self.segment[i] { - return - } - } - panic("Shouldn't happen") + if self == nil { + return + } + beyond_self := false + beyond_segment := false + for i := 0; ; i++ { + beyond_self = i >= len(self.segment) + beyond_segment = i >= len(segment) + if beyond_self && beyond_segment { + byteValue, treeValue, timestamp, existed = self.byteValue, self.treeValue, self.timestamp, self.use + return + } else if beyond_segment { + return + } else if beyond_self { + byteValue, treeValue, timestamp, existed = self.children[segment[i]].get(segment[i:]) + return + } else if segment[i] != self.segment[i] { + return + } + } + panic("Shouldn't happen") } + +// del will return this node or a child replacement after removing the value type defined by use (byteValue and/or treeValue). func (self *node) del(prefix, segment []Nibble, use int, now int64) (result *node, oldBytes []byte, oldTree *Tree, timestamp int64, existed int) { - if self == nil { - return - } - beyond_segment := false - beyond_self := false - for i := 0; ; i++ { - beyond_segment = i >= len(segment) - beyond_self = i >= len(self.segment) - if beyond_segment && beyond_self { - if self.use&^use != 0 { - if self.use&use&byteValue != 0 { - oldBytes = self.byteValue - existed |= byteValue - self.byteValue, self.byteHash, self.use = nil, murmur.HashBytes(nil), self.use&^byteValue - } - if self.use&use&treeValue != 0 { - oldTree = self.treeValue - existed |= treeValue - self.treeValue, self.use = nil, self.use&^treeValue - } - result, timestamp = self, self.timestamp - self.rehash(append(prefix, segment...), now) - } else { - n_children := 0 - var a_child *node - for _, child := range self.children { - if child != nil { - n_children++ - a_child = child - } - } - if n_children > 1 || self.segment == nil { - result, oldBytes, oldTree, timestamp, existed = self, self.byteValue, self.treeValue, self.timestamp, self.use - self.byteValue, self.byteHash, self.treeValue, self.empty, self.use, self.timestamp = nil, murmur.HashBytes(nil), nil, true, 0, 0 - self.rehash(append(prefix, segment...), now) - } else if n_children == 1 { - a_child.setSegment(append(self.segment, a_child.segment...)) - result, oldBytes, oldTree, timestamp, existed = a_child, self.byteValue, self.treeValue, self.timestamp, self.use - } else { - result, oldBytes, oldTree, timestamp, existed = nil, self.byteValue, self.treeValue, self.timestamp, self.use - } - } - return - } else if beyond_segment { - result, oldBytes, oldTree, timestamp, existed = self, nil, nil, 0, 0 - return - } else if beyond_self { - prefix = append(prefix, self.segment...) - self.children[segment[i]], oldBytes, oldTree, timestamp, existed = self.children[segment[i]].del(prefix, segment[i:], use, now) - if self.empty && prefix != nil { - n_children := 0 - for _, child := range self.children { - if child != nil { - n_children++ - } - } - if n_children == 0 { - result = nil - } else { - result = self - self.rehash(prefix, now) - } - } else { - result = self - self.rehash(prefix, now) - } - return - } else if self.segment[i] != segment[i] { - result, oldBytes, oldTree, timestamp, existed = self, nil, nil, 0, 0 - return - } - } - panic("Shouldn't happen") + if self == nil { + return + } + beyond_segment := false + beyond_self := false + for i := 0; ; i++ { + beyond_segment = i >= len(segment) + beyond_self = i >= len(self.segment) + if beyond_segment && beyond_self { + if self.use&^use != 0 { + if self.use&use&byteValue != 0 { + oldBytes = self.byteValue + existed |= byteValue + self.byteValue, self.byteHash, self.use = nil, murmur.HashBytes(nil), self.use&^byteValue + } + if self.use&use&treeValue != 0 { + oldTree = self.treeValue + existed |= treeValue + self.treeValue, self.use = nil, self.use&^treeValue + } + result, timestamp = self, self.timestamp + self.rehash(append(prefix, segment...), now) + } else { + n_children := 0 + var a_child *node + for _, child := range self.children { + if child != nil { + n_children++ + a_child = child + } + } + if n_children > 1 || self.segment == nil { + result, oldBytes, oldTree, timestamp, existed = self, self.byteValue, self.treeValue, self.timestamp, self.use + self.byteValue, self.byteHash, self.treeValue, self.empty, self.use, self.timestamp = nil, murmur.HashBytes(nil), nil, true, 0, 0 + self.rehash(append(prefix, segment...), now) + } else if n_children == 1 { + a_child.setSegment(append(self.segment, a_child.segment...)) + result, oldBytes, oldTree, timestamp, existed = a_child, self.byteValue, self.treeValue, self.timestamp, self.use + } else { + result, oldBytes, oldTree, timestamp, existed = nil, self.byteValue, self.treeValue, self.timestamp, self.use + } + } + return + } else if beyond_segment { + result, oldBytes, oldTree, timestamp, existed = self, nil, nil, 0, 0 + return + } else if beyond_self { + prefix = append(prefix, self.segment...) + self.children[segment[i]], oldBytes, oldTree, timestamp, existed = self.children[segment[i]].del(prefix, segment[i:], use, now) + if self.empty && prefix != nil { + n_children := 0 + for _, child := range self.children { + if child != nil { + n_children++ + } + } + if n_children == 0 { + result = nil + } else { + result = self + self.rehash(prefix, now) + } + } else { + result = self + self.rehash(prefix, now) + } + return + } else if self.segment[i] != segment[i] { + result, oldBytes, oldTree, timestamp, existed = self, nil, nil, 0, 0 + return + } + } + panic("Shouldn't happen") } + +// fakeDel will replace the given key with a tombstone func (self *node) fakeDel(prefix, segment []Nibble, use int, timestamp, now int64) (result *node, oldBytes []byte, oldTree *Tree, oldTimestamp int64, existed int) { - return self.insertHelp(prefix, newNode(segment, nil, nil, timestamp, false, 0), use, now) + return self.insertHelp(prefix, newNode(segment, nil, nil, timestamp, false, 0), use, now) } + +// insert will insert the given node. func (self *node) insert(prefix []Nibble, n *node, now int64) (result *node, oldBytes []byte, oldTree *Tree, timestamp int64, existed int) { - return self.insertHelp(prefix, n, n.use, now) + return self.insertHelp(prefix, n, n.use, now) } + +// insertHelp will insert the given node, allowing the caller to define what values of any current node to replace by providing the use parameter. func (self *node) insertHelp(prefix []Nibble, n *node, use int, now int64) (result *node, oldBytes []byte, oldTree *Tree, timestamp int64, existed int) { - if self == nil { - n.rehash(append(prefix, n.segment...), now) - result = n - return - } - beyond_n := false - beyond_self := false - for i := 0; ; i++ { - beyond_n = i >= len(n.segment) - beyond_self = i >= len(self.segment) - if beyond_n && beyond_self { - result, oldBytes, oldTree, timestamp, existed = self, self.byteValue, self.treeValue, self.timestamp, self.use - if use&byteValue != 0 { - self.byteValue, self.byteHash = n.byteValue, n.byteHash - if n.use&byteValue == 0 { - self.use &^= byteValue - } else { - self.use |= byteValue - } - } - if use&treeValue != 0 { - self.treeValue = n.treeValue - if n.use&treeValue == 0 { - self.use &^= treeValue - } else { - self.use |= treeValue - } - } - self.empty, self.timestamp = n.empty, n.timestamp - self.rehash(append(prefix, self.segment...), now) - return - } else if beyond_n { - self.setSegment(self.segment[i:]) - n.children[self.segment[0]] = self - result, oldBytes, oldTree, timestamp, existed = n, nil, nil, 0, 0 - prefix = append(prefix, self.segment...) - self.rehash(prefix, now) - n.rehash(append(prefix, n.segment...), now) - return - } else if beyond_self { - n.setSegment(n.segment[i:]) - // k is pre-calculated here because n.segment may change when n is inserted - k := n.segment[0] - prefix = append(prefix, self.segment...) - self.children[k], oldBytes, oldTree, timestamp, existed = self.children[k].insertHelp(prefix, n, use, now) - self.rehash(prefix, now) - result = self - return - } else if n.segment[i] != self.segment[i] { - result, oldBytes, oldTree, timestamp, existed = newNode(nil, nil, nil, 0, true, 0), nil, nil, 0, 0 - result.setSegment(n.segment[:i]) + if self == nil { + n.rehash(append(prefix, n.segment...), now) + result = n + return + } + beyond_n := false + beyond_self := false + for i := 0; ; i++ { + beyond_n = i >= len(n.segment) + beyond_self = i >= len(self.segment) + if beyond_n && beyond_self { + result, oldBytes, oldTree, timestamp, existed = self, self.byteValue, self.treeValue, self.timestamp, self.use + if use&byteValue != 0 { + self.byteValue, self.byteHash = n.byteValue, n.byteHash + if n.use&byteValue == 0 { + self.use &^= byteValue + } else { + self.use |= byteValue + } + } + if use&treeValue != 0 { + self.treeValue = n.treeValue + if n.use&treeValue == 0 { + self.use &^= treeValue + } else { + self.use |= treeValue + } + } + self.empty, self.timestamp = n.empty, n.timestamp + self.rehash(append(prefix, self.segment...), now) + return + } else if beyond_n { + self.setSegment(self.segment[i:]) + n.children[self.segment[0]] = self + result, oldBytes, oldTree, timestamp, existed = n, nil, nil, 0, 0 + prefix = append(prefix, self.segment...) + self.rehash(prefix, now) + n.rehash(append(prefix, n.segment...), now) + return + } else if beyond_self { + n.setSegment(n.segment[i:]) + // k is pre-calculated here because n.segment may change when n is inserted + k := n.segment[0] + prefix = append(prefix, self.segment...) + self.children[k], oldBytes, oldTree, timestamp, existed = self.children[k].insertHelp(prefix, n, use, now) + self.rehash(prefix, now) + result = self + return + } else if n.segment[i] != self.segment[i] { + result, oldBytes, oldTree, timestamp, existed = newNode(nil, nil, nil, 0, true, 0), nil, nil, 0, 0 + result.setSegment(n.segment[:i]) - n.setSegment(n.segment[i:]) - result.children[n.segment[0]] = n + n.setSegment(n.segment[i:]) + result.children[n.segment[0]] = n - self.setSegment(self.segment[i:]) - result.children[self.segment[0]] = self + self.setSegment(self.segment[i:]) + result.children[self.segment[0]] = self - prefix = append(prefix, result.segment...) + prefix = append(prefix, result.segment...) - n.rehash(append(prefix, n.segment...), now) - self.rehash(append(prefix, self.segment...), now) - result.rehash(prefix, now) + n.rehash(append(prefix, n.segment...), now) + self.rehash(append(prefix, self.segment...), now) + result.rehash(prefix, now) - return - } - } - panic("Shouldn't happen") + return + } + } + panic("Shouldn't happen") } diff --git a/radix/node_iterators.go b/radix/node_iterators.go index 96cb1ed..1ca1b68 100644 --- a/radix/node_iterators.go +++ b/radix/node_iterators.go @@ -1,229 +1,241 @@ package radix +// each will iterate over the tree in order func (self *node) each(prefix []Nibble, use int, f nodeIterator) (cont bool) { - cont = true - if self != nil { - prefix = append(prefix, self.segment...) - if !self.empty && (use == 0 || self.use&use != 0) { - cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp) - } - if cont { - for _, child := range self.children { - cont = child.each(prefix, use, f) - if !cont { - break - } - } - } - } - return + cont = true + if self != nil { + prefix = append(prefix, self.segment...) + if !self.empty && (use == 0 || self.use&use != 0) { + cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp) + } + if cont { + for _, child := range self.children { + cont = child.each(prefix, use, f) + if !cont { + break + } + } + } + } + return } + +// reverseEach will iterate over the tree in reverse order func (self *node) reverseEach(prefix []Nibble, use int, f nodeIterator) (cont bool) { - cont = true - if self != nil { - prefix = append(prefix, self.segment...) - for i := len(self.children) - 1; i >= 0; i-- { - cont = self.children[i].reverseEach(prefix, use, f) - if !cont { - break - } - } - if cont { - if !self.empty && (use == 0 || self.use&use != 0) { - cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp) - } - } - } - return + cont = true + if self != nil { + prefix = append(prefix, self.segment...) + for i := len(self.children) - 1; i >= 0; i-- { + cont = self.children[i].reverseEach(prefix, use, f) + if !cont { + break + } + } + if cont { + if !self.empty && (use == 0 || self.use&use != 0) { + cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp) + } + } + } + return } + +// eachBetween will iterate between min and max, including each depending on mincmp and maxcmp, in order func (self *node) eachBetween(prefix, min, max []Nibble, mincmp, maxcmp, use int, f nodeIterator) (cont bool) { - cont = true - prefix = append(prefix, self.segment...) - if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || nComp(prefix, min) > mincmp) && (max == nil || nComp(prefix, max) < maxcmp) { - cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp) - } - if cont { - for _, child := range self.children { - if child != nil { - childKey := make([]Nibble, len(prefix)+len(child.segment)) - copy(childKey, prefix) - copy(childKey[len(prefix):], child.segment) - mmi := len(childKey) - if mmi > len(min) { - mmi = len(min) - } - mma := len(childKey) - if mma > len(max) { - mma = len(max) - } - if (min == nil || nComp(childKey[:mmi], min[:mmi]) > -1) && (max == nil || nComp(childKey[:mma], max[:mma]) < 1) { - cont = child.eachBetween(prefix, min, max, mincmp, maxcmp, use, f) - } - if !cont { - break - } - } - } - } - return + cont = true + prefix = append(prefix, self.segment...) + if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || nComp(prefix, min) > mincmp) && (max == nil || nComp(prefix, max) < maxcmp) { + cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp) + } + if cont { + for _, child := range self.children { + if child != nil { + childKey := make([]Nibble, len(prefix)+len(child.segment)) + copy(childKey, prefix) + copy(childKey[len(prefix):], child.segment) + mmi := len(childKey) + if mmi > len(min) { + mmi = len(min) + } + mma := len(childKey) + if mma > len(max) { + mma = len(max) + } + if (min == nil || nComp(childKey[:mmi], min[:mmi]) > -1) && (max == nil || nComp(childKey[:mma], max[:mma]) < 1) { + cont = child.eachBetween(prefix, min, max, mincmp, maxcmp, use, f) + } + if !cont { + break + } + } + } + } + return } + +// eachBetween will iterate between min and max, including each depending on mincmp and maxcmp, in reverse order func (self *node) reverseEachBetween(prefix, min, max []Nibble, mincmp, maxcmp, use int, f nodeIterator) (cont bool) { - cont = true - prefix = append(prefix, self.segment...) - var child *node - for i := len(self.children) - 1; i >= 0; i-- { - child = self.children[i] - if child != nil { - childKey := make([]Nibble, len(prefix)+len(child.segment)) - copy(childKey, prefix) - copy(childKey[len(prefix):], child.segment) - mmi := len(childKey) - if mmi > len(min) { - mmi = len(min) - } - mma := len(childKey) - if mma > len(max) { - mma = len(max) - } - if (min == nil || nComp(childKey[:mmi], min[:mmi]) > -1) && (max == nil || nComp(childKey[:mma], max[:mma]) < 1) { - cont = child.reverseEachBetween(prefix, min, max, mincmp, maxcmp, use, f) - } - if !cont { - break - } - } - } - if cont { - if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || nComp(prefix, min) > mincmp) && (max == nil || nComp(prefix, max) < maxcmp) { - cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp) - } - } - return + cont = true + prefix = append(prefix, self.segment...) + var child *node + for i := len(self.children) - 1; i >= 0; i-- { + child = self.children[i] + if child != nil { + childKey := make([]Nibble, len(prefix)+len(child.segment)) + copy(childKey, prefix) + copy(childKey[len(prefix):], child.segment) + mmi := len(childKey) + if mmi > len(min) { + mmi = len(min) + } + mma := len(childKey) + if mma > len(max) { + mma = len(max) + } + if (min == nil || nComp(childKey[:mmi], min[:mmi]) > -1) && (max == nil || nComp(childKey[:mma], max[:mma]) < 1) { + cont = child.reverseEachBetween(prefix, min, max, mincmp, maxcmp, use, f) + } + if !cont { + break + } + } + } + if cont { + if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || nComp(prefix, min) > mincmp) && (max == nil || nComp(prefix, max) < maxcmp) { + cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp) + } + } + return } +// sizeBetween will count values between min and max, including each depending on mincmp and maxcmp, counting values of types included in use (byteValue and/or treeValue) func (self *node) sizeBetween(prefix, min, max []Nibble, mincmp, maxcmp, use int) (result int) { - prefix = append(prefix, self.segment...) - if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || nComp(prefix, min) > mincmp) && (max == nil || nComp(prefix, max) < maxcmp) { - if use == 0 || self.use&use&byteValue != 0 { - result++ - } - if use == 0 || self.use&use&treeValue != 0 { - result += self.treeValue.Size() - } - } - for _, child := range self.children { - if child != nil { - childKey := make([]Nibble, len(prefix)+len(child.segment)) - copy(childKey, prefix) - copy(childKey[len(prefix):], child.segment) - mmi := len(childKey) - if mmi > len(min) { - mmi = len(min) - } - mma := len(childKey) - if mma > len(max) { - mma = len(max) - } - mires := nComp(childKey[:mmi], min[:mmi]) - mares := nComp(childKey[:mma], max[:mma]) - if (min == nil || mires > -1) && (max == nil || mares < 1) { - if (min == nil || mires > 0) && (max == nil || mares < 0) { - if use == 0 { - result += child.realSize - } else { - if use&byteValue != 0 { - result += child.byteSize - } - if use&treeValue != 0 { - result += child.treeSize - } - } - } else { - result += child.sizeBetween(prefix, min, max, mincmp, maxcmp, use) - } - } - } - } - return + prefix = append(prefix, self.segment...) + if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || nComp(prefix, min) > mincmp) && (max == nil || nComp(prefix, max) < maxcmp) { + if use == 0 || self.use&use&byteValue != 0 { + result++ + } + if use == 0 || self.use&use&treeValue != 0 { + result += self.treeValue.Size() + } + } + for _, child := range self.children { + if child != nil { + childKey := make([]Nibble, len(prefix)+len(child.segment)) + copy(childKey, prefix) + copy(childKey[len(prefix):], child.segment) + mmi := len(childKey) + if mmi > len(min) { + mmi = len(min) + } + mma := len(childKey) + if mma > len(max) { + mma = len(max) + } + mires := nComp(childKey[:mmi], min[:mmi]) + mares := nComp(childKey[:mma], max[:mma]) + if (min == nil || mires > -1) && (max == nil || mares < 1) { + if (min == nil || mires > 0) && (max == nil || mares < 0) { + if use == 0 { + result += child.realSize + } else { + if use&byteValue != 0 { + result += child.byteSize + } + if use&treeValue != 0 { + result += child.treeSize + } + } + } else { + result += child.sizeBetween(prefix, min, max, mincmp, maxcmp, use) + } + } + } + } + return } +// eachBetweenIndex will iterate over the tree between index min and max, inclusive. +// Missing min or max will mean 'from the start' or 'to the end' respectively. func (self *node) eachBetweenIndex(prefix []Nibble, count int, min, max *int, use int, f nodeIndexIterator) (cont bool) { - cont = true - prefix = append(prefix, self.segment...) - if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || count >= *min) && (max == nil || count <= *max) { - cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp, count) - if use == 0 || self.use&use&byteValue != 0 { - count++ - } - if use == 0 || self.use&use&treeValue != 0 { - count += self.treeValue.Size() - } - } - if cont { - relevantChildSize := 0 - for _, child := range self.children { - if child != nil { - relevantChildSize = 0 - if use == 0 { - relevantChildSize = child.realSize - } else { - if use&byteValue != 0 { - relevantChildSize += child.byteSize - } - if use&treeValue != 0 { - relevantChildSize += child.treeSize - } - } - if (min == nil || relevantChildSize+count > *min) && (max == nil || count <= *max) { - cont = child.eachBetweenIndex(prefix, count, min, max, use, f) - } - count += relevantChildSize - if !cont { - break - } - } - } - } - return + cont = true + prefix = append(prefix, self.segment...) + if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || count >= *min) && (max == nil || count <= *max) { + cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp, count) + if use == 0 || self.use&use&byteValue != 0 { + count++ + } + if use == 0 || self.use&use&treeValue != 0 { + count += self.treeValue.Size() + } + } + if cont { + relevantChildSize := 0 + for _, child := range self.children { + if child != nil { + relevantChildSize = 0 + if use == 0 { + relevantChildSize = child.realSize + } else { + if use&byteValue != 0 { + relevantChildSize += child.byteSize + } + if use&treeValue != 0 { + relevantChildSize += child.treeSize + } + } + if (min == nil || relevantChildSize+count > *min) && (max == nil || count <= *max) { + cont = child.eachBetweenIndex(prefix, count, min, max, use, f) + } + count += relevantChildSize + if !cont { + break + } + } + } + } + return } + +// reverseEachBetweenIndex is like eachBetweenIndex, but iterates in reverse. func (self *node) reverseEachBetweenIndex(prefix []Nibble, count int, min, max *int, use int, f nodeIndexIterator) (cont bool) { - cont = true - prefix = append(prefix, self.segment...) - var child *node - relevantChildSize := 0 - for i := len(self.children) - 1; i >= 0; i-- { - child = self.children[i] - if child != nil { - relevantChildSize = 0 - if use == 0 { - relevantChildSize = child.realSize - } else { - if use&byteValue != 0 { - relevantChildSize += child.byteSize - } - if use&treeValue != 0 { - relevantChildSize += child.treeSize - } - } - if (min == nil || relevantChildSize+count > *min) && (max == nil || count <= *max) { - cont = child.reverseEachBetweenIndex(prefix, count, min, max, use, f) - } - count += relevantChildSize - if !cont { - break - } - } - } - if cont { - if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || count >= *min) && (max == nil || count <= *max) { - cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp, count) - if use == 0 || self.use&use&byteValue != 0 { - count++ - } - if use == 0 || self.use&use&treeValue != 0 { - count += self.treeValue.Size() - } - } - } - return + cont = true + prefix = append(prefix, self.segment...) + var child *node + relevantChildSize := 0 + for i := len(self.children) - 1; i >= 0; i-- { + child = self.children[i] + if child != nil { + relevantChildSize = 0 + if use == 0 { + relevantChildSize = child.realSize + } else { + if use&byteValue != 0 { + relevantChildSize += child.byteSize + } + if use&treeValue != 0 { + relevantChildSize += child.treeSize + } + } + if (min == nil || relevantChildSize+count > *min) && (max == nil || count <= *max) { + cont = child.reverseEachBetweenIndex(prefix, count, min, max, use, f) + } + count += relevantChildSize + if !cont { + break + } + } + } + if cont { + if !self.empty && (use == 0 || self.use&use != 0) && (min == nil || count >= *min) && (max == nil || count <= *max) { + cont = f(Stitch(prefix), self.byteValue, self.treeValue, self.use, self.timestamp, count) + if use == 0 || self.use&use&byteValue != 0 { + count++ + } + if use == 0 || self.use&use&treeValue != 0 { + count += self.treeValue.Size() + } + } + } + return } diff --git a/radix/profile/profile.go b/radix/profile/profile.go index f6e2128..f9b22ce 100644 --- a/radix/profile/profile.go +++ b/radix/profile/profile.go @@ -1,36 +1,36 @@ package main import ( - "bytes" - "fmt" - . "github.com/zond/god/" - "github.com/zond/god/../murmur" - "os" - "runtime/pprof" + "bytes" + "fmt" + "github.com/zond/god/murmur" + "github.com/zond/god/radix" + "os" + "runtime/pprof" ) func main() { - f, err := os.Create("cpuprofile") - if err != nil { - panic(err.Error()) - } - f2, err := os.Create("memprofile") - if err != nil { - panic(err.Error()) - } + f, err := os.Create("cpuprofile") + if err != nil { + panic(err.Error()) + } + f2, err := os.Create("memprofile") + if err != nil { + panic(err.Error()) + } - pprof.StartCPUProfile(f) - defer pprof.StopCPUProfile() - defer pprof.WriteHeapProfile(f2) + pprof.StartCPUProfile(f) + defer pprof.StopCPUProfile() + defer pprof.WriteHeapProfile(f2) - m := NewTree() - var k []byte - for i := 0; i < 100000; i++ { - k = murmur.HashString(fmt.Sprint(i)) - m.Put(k, k, 1) - x, _, _ := m.Get(k) - if bytes.Compare(x, k) != 0 { - panic("humbug") - } - } + m := radix.NewTree() + var k []byte + for i := 0; i < 100000; i++ { + k = murmur.HashString(fmt.Sprint(i)) + m.Put(k, k, 1) + x, _, _ := m.Get(k) + if bytes.Compare(x, k) != 0 { + panic("humbug") + } + } } diff --git a/radix/radix.go b/radix/radix.go index c31ce8e..2bb3d25 100644 --- a/radix/radix.go +++ b/radix/radix.go @@ -1,9 +1,9 @@ package radix import ( - "bytes" - "fmt" - "unsafe" + "bytes" + "fmt" + "unsafe" ) var encodeChars = []string{"0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "a", "b", "c", "d", "e", "f"} @@ -15,117 +15,117 @@ type Nibble byte // Since the Trees remove tombstones lazily, and after a timeout, we need something to provide times. type Timer interface { - ContinuousTime() int64 + ContinuousTime() int64 } func toBytes(n []Nibble) []byte { - return *((*[]byte)(unsafe.Pointer(&n))) + return *((*[]byte)(unsafe.Pointer(&n))) } const ( - parts = 2 - mirrored = "mirrored" - yes = "yes" + parts = 2 + mirrored = "mirrored" + yes = "yes" ) func nComp(a, b []Nibble) int { - return bytes.Compare(toBytes(a), toBytes(b)) + return bytes.Compare(toBytes(a), toBytes(b)) } // Rip will explode a byte slice into a nibble slice. func Rip(b []byte) (result []Nibble) { - if b == nil { - return nil - } - result = make([]Nibble, parts*len(b)) - for i, char := range b { - for j := 0; j < parts; j++ { - result[(i*parts)+j] = Nibble((char << byte((8/parts)*j)) >> byte(8-(8/parts))) - } - } - return + if b == nil { + return nil + } + result = make([]Nibble, parts*len(b)) + for i, char := range b { + for j := 0; j < parts; j++ { + result[(i*parts)+j] = Nibble((char << byte((8/parts)*j)) >> byte(8-(8/parts))) + } + } + return } func stringEncode(b []byte) string { - buffer := new(bytes.Buffer) - for _, c := range b { - fmt.Fprint(buffer, encodeChars[c]) - } - return string(buffer.Bytes()) + buffer := new(bytes.Buffer) + for _, c := range b { + fmt.Fprint(buffer, encodeChars[c]) + } + return string(buffer.Bytes()) } // Stitch will implode a nibble slice into a byte slice. func Stitch(b []Nibble) (result []byte) { - if b == nil { - return nil - } - result = make([]byte, len(b)/parts) - for i, _ := range result { - for j := 0; j < parts; j++ { - result[i] += byte(b[(i*parts)+j] << byte((parts-j-1)*(8/parts))) - } - } - return + if b == nil { + return nil + } + result = make([]byte, len(b)/parts) + for i, _ := range result { + for j := 0; j < parts; j++ { + result[i] += byte(b[(i*parts)+j] << byte((parts-j-1)*(8/parts))) + } + } + return } // SubPrints are used to record hashes for child trees. type SubPrint struct { - Key []Nibble - Sum []byte - Exists bool + Key []Nibble + Sum []byte + Exists bool } func (self SubPrint) equals(other SubPrint) bool { - return bytes.Compare(other.Sum, self.Sum) == 0 + return bytes.Compare(other.Sum, self.Sum) == 0 } // Prints are used to record hashes for Nodes. type Print struct { - Exists bool - Key []Nibble - Empty bool - Timestamp int64 - SubTree bool - SubPrints []SubPrint - ByteHash []byte - TreeHash []byte - TreeDataTimestamp int64 - TreeSize int + Exists bool + Key []Nibble + Empty bool + Timestamp int64 + SubTree bool + SubPrints []SubPrint + ByteHash []byte + TreeHash []byte + TreeDataTimestamp int64 + TreeSize int } func (self *Print) coveredBy(other *Print) bool { - if self == nil { - return other == nil - } - return other != nil && (other.Timestamp > self.Timestamp || bytes.Compare(self.ByteHash, other.ByteHash) == 0) + if self == nil { + return other == nil + } + return other != nil && (other.Timestamp > self.Timestamp || bytes.Compare(self.ByteHash, other.ByteHash) == 0) } func (self *Print) push(n *node) { - self.Key = append(self.Key, n.segment...) + self.Key = append(self.Key, n.segment...) } func (self *Print) set(n *node) { - self.Exists = true - self.ByteHash = n.byteHash - self.TreeHash = n.treeValue.Hash() - if n.treeValue != nil { - self.TreeDataTimestamp = n.treeValue.DataTimestamp() - self.TreeSize = n.treeValue.Size() - } - self.Empty = n.empty - self.Timestamp = n.timestamp - self.SubPrints = make([]SubPrint, len(n.children)) - self.SubTree = n.treeValue != nil - for index, child := range n.children { - if child != nil { - self.SubPrints[index] = SubPrint{ - Exists: true, - Key: append(append([]Nibble{}, self.Key...), child.segment...), - Sum: child.hash, - } - } - } + self.Exists = true + self.ByteHash = n.byteHash + self.TreeHash = n.treeValue.Hash() + if n.treeValue != nil { + self.TreeDataTimestamp = n.treeValue.DataTimestamp() + self.TreeSize = n.treeValue.Size() + } + self.Empty = n.empty + self.Timestamp = n.timestamp + self.SubPrints = make([]SubPrint, len(n.children)) + self.SubTree = n.treeValue != nil + for index, child := range n.children { + if child != nil { + self.SubPrints[index] = SubPrint{ + Exists: true, + Key: append(append([]Nibble{}, self.Key...), child.segment...), + Sum: child.hash, + } + } + } } func (self *Print) timestamp() int64 { - if self == nil { - return 0 - } - return self.Timestamp + if self == nil { + return 0 + } + return self.Timestamp } diff --git a/radix/radix_test.go b/radix/radix_test.go index 095b2f8..9c28ebc 100644 --- a/radix/radix_test.go +++ b/radix/radix_test.go @@ -1,17 +1,17 @@ package radix import ( - "bytes" - "encoding/hex" - "fmt" - "github.com/zond/god/common" - "github.com/zond/god/murmur" - "math/big" - "math/rand" - "reflect" - "runtime" - "testing" - "time" + "bytes" + "encoding/hex" + "fmt" + "github.com/zond/god/common" + "github.com/zond/god/murmur" + "math/big" + "math/rand" + "reflect" + "runtime" + "testing" + "time" ) var benchmarkTestTree *Tree @@ -19,1167 +19,1167 @@ var benchmarkTestKeys [][]byte var benchmarkTestValues [][]byte func init() { - rand.Seed(time.Now().UnixNano()) - benchmarkTestTree = NewTree() - benchmarkTestTree.Log("benchmarklogs") - benchmarkTestTree.logger.Clear() + rand.Seed(time.Now().UnixNano()) + benchmarkTestTree = NewTree() + benchmarkTestTree.Log("benchmarklogs") + benchmarkTestTree.logger.Clear() } func TestSyncVersions(t *testing.T) { - tree1 := NewTree() - tree3 := NewTree() - n := 10 - var k []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte{byte(i)} - v = []byte(fmt.Sprint(i)) - tree1.Put(k, v, 1) - if i == 2 { - tree3.Put(k, []byte("other timestamp"), 2) - } else { - tree3.Put(k, v, 1) - } - } - tree2 := NewTree() - tree2.Put([]byte{2}, []byte("other timestamp"), 2) - s := NewSync(tree1, tree2) - s.Run() - if bytes.Compare(tree1.Hash(), tree2.Hash()) == 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should not be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if tree1.deepEqual(tree2) { - t.Errorf("%v and %v are equal", tree1, tree2) - } - if bytes.Compare(tree3.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) - } - if !tree3.deepEqual(tree2) { - t.Errorf("%v and %v are unequal", tree3, tree2) - } - tree1.Put([]byte{2}, []byte("yet another timestamp"), 3) - s.Run() - if bytes.Compare(tree3.Hash(), tree2.Hash()) == 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should not be equal!", tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) - } - if tree3.deepEqual(tree2) { - t.Errorf("%v and %v are equal", tree3, tree2) - } - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !tree1.deepEqual(tree2) { - t.Errorf("%v and %v are unequal", tree1, tree2) - } + tree1 := NewTree() + tree3 := NewTree() + n := 10 + var k []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte{byte(i)} + v = []byte(fmt.Sprint(i)) + tree1.Put(k, v, 1) + if i == 2 { + tree3.Put(k, []byte("other timestamp"), 2) + } else { + tree3.Put(k, v, 1) + } + } + tree2 := NewTree() + tree2.Put([]byte{2}, []byte("other timestamp"), 2) + s := NewSync(tree1, tree2) + s.Run() + if bytes.Compare(tree1.Hash(), tree2.Hash()) == 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should not be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if tree1.deepEqual(tree2) { + t.Errorf("%v and %v are equal", tree1, tree2) + } + if bytes.Compare(tree3.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) + } + if !tree3.deepEqual(tree2) { + t.Errorf("%v and %v are unequal", tree3, tree2) + } + tree1.Put([]byte{2}, []byte("yet another timestamp"), 3) + s.Run() + if bytes.Compare(tree3.Hash(), tree2.Hash()) == 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should not be equal!", tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) + } + if tree3.deepEqual(tree2) { + t.Errorf("%v and %v are equal", tree3, tree2) + } + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !tree1.deepEqual(tree2) { + t.Errorf("%v and %v are unequal", tree1, tree2) + } } func TestSyncLimits(t *testing.T) { - tree1 := NewTree() - tree3 := NewTree() - n := 10 - from := 3 - to := 7 - fromKey := []byte{byte(from)} - toKey := []byte{byte(to)} - var k []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte{byte(i)} - v = []byte(fmt.Sprint(i)) - tree1.Put(k, v, 1) - if i >= from && i < to { - tree3.Put(k, v, 1) - } - } - tree2 := NewTree() - s := NewSync(tree1, tree2).From(fromKey).To(toKey) - s.Run() - if bytes.Compare(tree3.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) - } - if !tree3.deepEqual(tree2) { - t.Errorf("%v and %v are unequal", tree3, tree2) - } + tree1 := NewTree() + tree3 := NewTree() + n := 10 + from := 3 + to := 7 + fromKey := []byte{byte(from)} + toKey := []byte{byte(to)} + var k []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte{byte(i)} + v = []byte(fmt.Sprint(i)) + tree1.Put(k, v, 1) + if i >= from && i < to { + tree3.Put(k, v, 1) + } + } + tree2 := NewTree() + s := NewSync(tree1, tree2).From(fromKey).To(toKey) + s.Run() + if bytes.Compare(tree3.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) + } + if !tree3.deepEqual(tree2) { + t.Errorf("%v and %v are unequal", tree3, tree2) + } } func TestripStitch(t *testing.T) { - var b []byte - for i := 0; i < 1000; i++ { - b = make([]byte, rand.Int()%30) - for j := 0; j < len(b); j++ { - b[j] = byte(rand.Int()) - } - if bytes.Compare(Stitch(Rip(b)), b) != 0 { - t.Errorf("%v != %v", Stitch(Rip(b)), b) - } - } + var b []byte + for i := 0; i < 1000; i++ { + b = make([]byte, rand.Int()%30) + for j := 0; j < len(b); j++ { + b[j] = byte(rand.Int()) + } + if bytes.Compare(Stitch(Rip(b)), b) != 0 { + t.Errorf("%v != %v", Stitch(Rip(b)), b) + } + } } func TestSyncSubTreeDestructive(t *testing.T) { - tree1 := NewTree() - tree3 := NewTree() - n := 10 - var k, sk []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte(murmur.HashString(fmt.Sprint(i))) - v = []byte(fmt.Sprint(i)) - if i%2 == 0 { - tree1.Put(k, v, 1) - tree3.Put(k, v, 1) - } else { - for j := 0; j < 10; j++ { - sk = []byte(fmt.Sprint(j)) - tree1.SubPut(k, sk, v, 1) - tree3.SubPut(k, sk, v, 1) - } - } - } - tree2 := NewTree() - s := NewSync(tree3, tree2).Destroy() - s.Run() - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !tree1.deepEqual(tree2) { - t.Errorf("\n%v and \n%v are unequal", tree1.Describe(), tree2.Describe()) - } - if tree3.Size() != 0 { - t.Errorf("%v should be empty", tree3.Describe()) - } - if !tree3.deepEqual(NewTree()) { - t.Errorf("%v and %v should be equal", tree3.Describe(), NewTree().Describe()) - } + tree1 := NewTree() + tree3 := NewTree() + n := 10 + var k, sk []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte(murmur.HashString(fmt.Sprint(i))) + v = []byte(fmt.Sprint(i)) + if i%2 == 0 { + tree1.Put(k, v, 1) + tree3.Put(k, v, 1) + } else { + for j := 0; j < 10; j++ { + sk = []byte(fmt.Sprint(j)) + tree1.SubPut(k, sk, v, 1) + tree3.SubPut(k, sk, v, 1) + } + } + } + tree2 := NewTree() + s := NewSync(tree3, tree2).Destroy() + s.Run() + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !tree1.deepEqual(tree2) { + t.Errorf("\n%v and \n%v are unequal", tree1.Describe(), tree2.Describe()) + } + if tree3.Size() != 0 { + t.Errorf("%v should be empty", tree3.Describe()) + } + if !tree3.deepEqual(NewTree()) { + t.Errorf("%v and %v should be equal", tree3.Describe(), NewTree().Describe()) + } } func TestTreeSizeBetween(t *testing.T) { - tree := NewTree() - for i := 11; i < 20; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - for i := 10; i < 21; i++ { - for j := i; j < 21; j++ { - expected := common.Max(0, common.Min(j+1, 20)-common.Max(11, i)) - val := tree.SizeBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, true) - if val != expected { - t.Errorf("%v.SizeBetween(%v, %v, true, true) should be %v but was %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), common.HexEncode([]byte(fmt.Sprint(j))), expected, val) - } - expected = common.Max(0, common.Min(j+1, 20)-common.Max(11, i+1)) - val = tree.SizeBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, true) - if val != expected { - t.Errorf("%v.SizeBetween(%v, %v, false, true) should be %v but was %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), common.HexEncode([]byte(fmt.Sprint(j))), expected, val) - } - expected = common.Max(0, common.Min(j, 20)-common.Max(11, i)) - val = tree.SizeBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, false) - if val != expected { - t.Errorf("%v.SizeBetween(%v, %v, true, false) should be %v but was %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), common.HexEncode([]byte(fmt.Sprint(j))), expected, val) - } - expected = common.Max(0, common.Min(j, 20)-common.Max(11, i+1)) - val = tree.SizeBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, false) - if val != expected { - t.Errorf("%v.SizeBetween(%v, %v, false, false) should be %v but was %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), common.HexEncode([]byte(fmt.Sprint(j))), expected, val) - } - } - } - for i := 0; i < 10; i++ { - tree.SubPut([]byte{50}, []byte{byte(i)}, []byte{byte(i)}, 1) - } - ary := []byte{50} - if s := tree.SizeBetween(ary, ary, true, true); s != 10 { - t.Errorf("wrong size calculated for %v\nbetween %v and %v\nwanted %v but got %v", tree.Describe(), common.HexEncode(ary), common.HexEncode(ary), 10, s) - } + tree := NewTree() + for i := 11; i < 20; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + for i := 10; i < 21; i++ { + for j := i; j < 21; j++ { + expected := common.Max(0, common.Min(j+1, 20)-common.Max(11, i)) + val := tree.SizeBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, true) + if val != expected { + t.Errorf("%v.SizeBetween(%v, %v, true, true) should be %v but was %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), common.HexEncode([]byte(fmt.Sprint(j))), expected, val) + } + expected = common.Max(0, common.Min(j+1, 20)-common.Max(11, i+1)) + val = tree.SizeBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, true) + if val != expected { + t.Errorf("%v.SizeBetween(%v, %v, false, true) should be %v but was %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), common.HexEncode([]byte(fmt.Sprint(j))), expected, val) + } + expected = common.Max(0, common.Min(j, 20)-common.Max(11, i)) + val = tree.SizeBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, false) + if val != expected { + t.Errorf("%v.SizeBetween(%v, %v, true, false) should be %v but was %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), common.HexEncode([]byte(fmt.Sprint(j))), expected, val) + } + expected = common.Max(0, common.Min(j, 20)-common.Max(11, i+1)) + val = tree.SizeBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, false) + if val != expected { + t.Errorf("%v.SizeBetween(%v, %v, false, false) should be %v but was %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), common.HexEncode([]byte(fmt.Sprint(j))), expected, val) + } + } + } + for i := 0; i < 10; i++ { + tree.SubPut([]byte{50}, []byte{byte(i)}, []byte{byte(i)}, 1) + } + ary := []byte{50} + if s := tree.SizeBetween(ary, ary, true, true); s != 10 { + t.Errorf("wrong size calculated for %v\nbetween %v and %v\nwanted %v but got %v", tree.Describe(), common.HexEncode(ary), common.HexEncode(ary), 10, s) + } } func TestSubTree(t *testing.T) { - tree := NewTree() - assertSize(t, tree, 0) - tree.Put([]byte("a"), []byte("a"), 1) - assertSize(t, tree, 1) - tree.SubPut([]byte("b"), []byte("c"), []byte("d"), 1) - assertSize(t, tree, 2) - tree.SubPut([]byte("b"), []byte("d"), []byte("e"), 2) - assertSize(t, tree, 3) - if v, ver, e := tree.SubGet([]byte("b"), []byte("d")); bytes.Compare(v, []byte("e")) != 0 || ver != 2 || !e { - t.Errorf("wrong result, wanted %v, %v, %v got %v, %v, %v", []byte("e"), 2, true, v, ver, e) - } + tree := NewTree() + assertSize(t, tree, 0) + tree.Put([]byte("a"), []byte("a"), 1) + assertSize(t, tree, 1) + tree.SubPut([]byte("b"), []byte("c"), []byte("d"), 1) + assertSize(t, tree, 2) + tree.SubPut([]byte("b"), []byte("d"), []byte("e"), 2) + assertSize(t, tree, 3) + if v, ver, e := tree.SubGet([]byte("b"), []byte("d")); bytes.Compare(v, []byte("e")) != 0 || ver != 2 || !e { + t.Errorf("wrong result, wanted %v, %v, %v got %v, %v, %v", []byte("e"), 2, true, v, ver, e) + } } func TestSyncSubTreeVersions(t *testing.T) { - tree1 := NewTree() - tree3 := NewTree() - n := 10 - var k, sk []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte(murmur.HashString(fmt.Sprint(i))) - v = []byte(fmt.Sprint(i)) - if i%2 == 0 { - tree3.Put(k, v, 1) - tree1.Put(k, v, 1) - } else { - for j := 0; j < 10; j++ { - sk = []byte(fmt.Sprint(j)) - tree1.SubPut(k, sk, v, 1) - if i == 1 && j == 3 { - tree3.SubPut(k, sk, []byte("another value"), 2) - } else { - tree3.SubPut(k, sk, v, 1) - } - } - } - } - tree2 := NewTree() - tree2.SubPut([]byte(murmur.HashString(fmt.Sprint(1))), []byte(fmt.Sprint(3)), []byte("another value"), 2) - s := NewSync(tree1, tree2) - s.Run() - if bytes.Compare(tree1.Hash(), tree2.Hash()) == 0 { - t.Errorf("should not be equal") - } - if tree1.deepEqual(tree2) { - t.Errorf("should not be equal") - } - if bytes.Compare(tree3.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) - } - if !tree3.deepEqual(tree2) { - t.Errorf("\n%v and \n%v are unequal", tree3.Describe(), tree2.Describe()) - } - tree1.SubPut([]byte(murmur.HashString(fmt.Sprint(1))), []byte(fmt.Sprint(3)), []byte("another value again"), 3) - s.Run() - if bytes.Compare(tree3.Hash(), tree2.Hash()) == 0 { - t.Errorf("should not be equal") - } - if tree3.deepEqual(tree2) { - t.Errorf("should not be equal") - } - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !tree1.deepEqual(tree2) { - t.Errorf("\n%v and \n%v are unequal", tree1.Describe(), tree2.Describe()) - } + tree1 := NewTree() + tree3 := NewTree() + n := 10 + var k, sk []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte(murmur.HashString(fmt.Sprint(i))) + v = []byte(fmt.Sprint(i)) + if i%2 == 0 { + tree3.Put(k, v, 1) + tree1.Put(k, v, 1) + } else { + for j := 0; j < 10; j++ { + sk = []byte(fmt.Sprint(j)) + tree1.SubPut(k, sk, v, 1) + if i == 1 && j == 3 { + tree3.SubPut(k, sk, []byte("another value"), 2) + } else { + tree3.SubPut(k, sk, v, 1) + } + } + } + } + tree2 := NewTree() + tree2.SubPut([]byte(murmur.HashString(fmt.Sprint(1))), []byte(fmt.Sprint(3)), []byte("another value"), 2) + s := NewSync(tree1, tree2) + s.Run() + if bytes.Compare(tree1.Hash(), tree2.Hash()) == 0 { + t.Errorf("should not be equal") + } + if tree1.deepEqual(tree2) { + t.Errorf("should not be equal") + } + if bytes.Compare(tree3.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) + } + if !tree3.deepEqual(tree2) { + t.Errorf("\n%v and \n%v are unequal", tree3.Describe(), tree2.Describe()) + } + tree1.SubPut([]byte(murmur.HashString(fmt.Sprint(1))), []byte(fmt.Sprint(3)), []byte("another value again"), 3) + s.Run() + if bytes.Compare(tree3.Hash(), tree2.Hash()) == 0 { + t.Errorf("should not be equal") + } + if tree3.deepEqual(tree2) { + t.Errorf("should not be equal") + } + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !tree1.deepEqual(tree2) { + t.Errorf("\n%v and \n%v are unequal", tree1.Describe(), tree2.Describe()) + } } func TestSyncSubTree(t *testing.T) { - tree1 := NewTree() - n := 10 - var k, sk []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte(murmur.HashString(fmt.Sprint(i))) - v = []byte(fmt.Sprint(i)) - if i%2 == 0 { - tree1.Put(k, v, 1) - } else { - for j := 0; j < 10; j++ { - sk = []byte(fmt.Sprint(j)) - tree1.SubPut(k, sk, v, 1) - } - } - } - tree2 := NewTree() - s := NewSync(tree1, tree2) - s.Run() - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !tree1.deepEqual(tree2) { - t.Errorf("\n%v and \n%v are unequal", tree1.Describe(), tree2.Describe()) - } + tree1 := NewTree() + n := 10 + var k, sk []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte(murmur.HashString(fmt.Sprint(i))) + v = []byte(fmt.Sprint(i)) + if i%2 == 0 { + tree1.Put(k, v, 1) + } else { + for j := 0; j < 10; j++ { + sk = []byte(fmt.Sprint(j)) + tree1.SubPut(k, sk, v, 1) + } + } + } + tree2 := NewTree() + s := NewSync(tree1, tree2) + s.Run() + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !tree1.deepEqual(tree2) { + t.Errorf("\n%v and \n%v are unequal", tree1.Describe(), tree2.Describe()) + } } func TestSyncDestructive(t *testing.T) { - tree1 := NewTree() - tree3 := NewTree() - n := 1000 - var k []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte(fmt.Sprint(i)) - v = []byte(fmt.Sprint(i)) - tree1.Put(k, v, 1) - tree3.Put(k, v, 1) - } - tree2 := NewTree() - s := NewSync(tree3, tree2).Destroy() - s.Run() - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !tree1.deepEqual(tree2) { - t.Errorf("%v and %v are unequal", tree1, tree2) - } - if tree3.Size() != 0 { - t.Errorf("%v should be size 0, is size %v", tree3, tree3.Size()) - } - if !tree3.deepEqual(NewTree()) { - t.Errorf("should be equal") - } + tree1 := NewTree() + tree3 := NewTree() + n := 1000 + var k []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte(fmt.Sprint(i)) + v = []byte(fmt.Sprint(i)) + tree1.Put(k, v, 1) + tree3.Put(k, v, 1) + } + tree2 := NewTree() + s := NewSync(tree3, tree2).Destroy() + s.Run() + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !tree1.deepEqual(tree2) { + t.Errorf("%v and %v are unequal", tree1, tree2) + } + if tree3.Size() != 0 { + t.Errorf("%v should be size 0, is size %v", tree3, tree3.Size()) + } + if !tree3.deepEqual(NewTree()) { + t.Errorf("should be equal") + } } func TestSyncDestructiveMatching(t *testing.T) { - tree1 := NewTree() - tree2 := NewTree() - tree3 := NewTree() - n := 1000 - var k []byte - var v []byte - for i := 0; i < n; i++ { - k = murmur.HashString(fmt.Sprint(i)) - v = []byte(fmt.Sprint(i)) - tree1.Put(k, v, 1) - tree2.Put(k, v, 1) - tree3.Put(k, v, 1) - } - NewSync(tree1, tree2).Destroy().Run() - if !tree2.deepEqual(tree3) { - t.Errorf("should be equal") - } - if tree1.Size() != 0 { - t.Errorf("should be empty!") - } - tree4 := NewTree() - if !tree1.deepEqual(tree4) { - t.Errorf("should be equal!") - } + tree1 := NewTree() + tree2 := NewTree() + tree3 := NewTree() + n := 1000 + var k []byte + var v []byte + for i := 0; i < n; i++ { + k = murmur.HashString(fmt.Sprint(i)) + v = []byte(fmt.Sprint(i)) + tree1.Put(k, v, 1) + tree2.Put(k, v, 1) + tree3.Put(k, v, 1) + } + NewSync(tree1, tree2).Destroy().Run() + if !tree2.deepEqual(tree3) { + t.Errorf("should be equal") + } + if tree1.Size() != 0 { + t.Errorf("should be empty!") + } + tree4 := NewTree() + if !tree1.deepEqual(tree4) { + t.Errorf("should be equal!") + } } func TestSyncComplete(t *testing.T) { - tree1 := NewTree() - n := 1000 - var k []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte(fmt.Sprint(i)) - v = []byte(fmt.Sprint(i)) - tree1.Put(k, v, 1) - } - tree2 := NewTree() - s := NewSync(tree1, tree2) - s.Run() - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !tree1.deepEqual(tree2) { - t.Errorf("%v and %v are unequal", tree1, tree2) - } + tree1 := NewTree() + n := 1000 + var k []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte(fmt.Sprint(i)) + v = []byte(fmt.Sprint(i)) + tree1.Put(k, v, 1) + } + tree2 := NewTree() + s := NewSync(tree1, tree2) + s.Run() + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !tree1.deepEqual(tree2) { + t.Errorf("%v and %v are unequal", tree1, tree2) + } } func TestSyncRandomLimits(t *testing.T) { - tree1 := NewTree() - n := 10 - var k []byte - var v []byte - for i := 0; i < n; i++ { - k = murmur.HashString(fmt.Sprint(i)) - v = []byte(fmt.Sprint(i)) - tree1.Put(k, v, 1) - } - var keys [][]byte - tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { - keys = append(keys, key) - return true - }) - var fromKey []byte - var toKey []byte - var tree2 *Tree - var tree3 *Tree - var s *Sync - for fromIndex, _ := range keys { - for toIndex, _ := range keys { - if fromIndex != toIndex { - fromKey = keys[fromIndex] - toKey = keys[toIndex] - if bytes.Compare(fromKey, toKey) < 0 { - tree2 = NewTree() - tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { - if common.BetweenIE(key, fromKey, toKey) { - tree2.Put(key, byteValue, 1) - } - return true - }) - tree3 = NewTree() - s = NewSync(tree1, tree3).From(fromKey).To(toKey) - s.Run() - if !tree3.deepEqual(tree2) { - t.Errorf("when syncing from %v to %v, %v and %v have hashes\n%v\n%v\nand they should be equal!", common.HexEncode(fromKey), common.HexEncode(toKey), tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) - } - } - } - } - } + tree1 := NewTree() + n := 10 + var k []byte + var v []byte + for i := 0; i < n; i++ { + k = murmur.HashString(fmt.Sprint(i)) + v = []byte(fmt.Sprint(i)) + tree1.Put(k, v, 1) + } + var keys [][]byte + tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { + keys = append(keys, key) + return true + }) + var fromKey []byte + var toKey []byte + var tree2 *Tree + var tree3 *Tree + var s *Sync + for fromIndex, _ := range keys { + for toIndex, _ := range keys { + if fromIndex != toIndex { + fromKey = keys[fromIndex] + toKey = keys[toIndex] + if bytes.Compare(fromKey, toKey) < 0 { + tree2 = NewTree() + tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { + if common.BetweenIE(key, fromKey, toKey) { + tree2.Put(key, byteValue, 1) + } + return true + }) + tree3 = NewTree() + s = NewSync(tree1, tree3).From(fromKey).To(toKey) + s.Run() + if !tree3.deepEqual(tree2) { + t.Errorf("when syncing from %v to %v, %v and %v have hashes\n%v\n%v\nand they should be equal!", common.HexEncode(fromKey), common.HexEncode(toKey), tree3.Describe(), tree2.Describe(), tree3.Hash(), tree2.Hash()) + } + } + } + } + } } func TestSyncPartial(t *testing.T) { - tree1 := NewTree() - tree2 := NewTree() - mod := 2 - n := 100 - var k []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte(fmt.Sprint(i)) - v = []byte(fmt.Sprint(i)) - tree1.Put(k, v, 1) - if i%mod != 0 { - tree2.Put(k, v, 1) - } - } - s := NewSync(tree1, tree2) - s.Run() - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !tree1.deepEqual(tree2) { - t.Errorf("%v and %v are unequal", tree1, tree2) - } + tree1 := NewTree() + tree2 := NewTree() + mod := 2 + n := 100 + var k []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte(fmt.Sprint(i)) + v = []byte(fmt.Sprint(i)) + tree1.Put(k, v, 1) + if i%mod != 0 { + tree2.Put(k, v, 1) + } + } + s := NewSync(tree1, tree2) + s.Run() + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !tree1.deepEqual(tree2) { + t.Errorf("%v and %v are unequal", tree1, tree2) + } } func TestSyncSubConf(t *testing.T) { - tree1 := NewTree() - tree2 := NewTree() - tree1.SubAddConfiguration([]byte("a"), 1, "blapp", "blepp") - s := NewSync(tree1, tree2) - s.Run() - c1, _ := tree1.SubConfiguration([]byte("a")) - c2, _ := tree2.SubConfiguration([]byte("a")) - if !reflect.DeepEqual(c1, c2) { - t.Errorf("%v and %v should be equal", c1, c2) - } + tree1 := NewTree() + tree2 := NewTree() + tree1.SubAddConfiguration([]byte("a"), 1, "blapp", "blepp") + s := NewSync(tree1, tree2) + s.Run() + c1, _ := tree1.SubConfiguration([]byte("a")) + c2, _ := tree2.SubConfiguration([]byte("a")) + if !reflect.DeepEqual(c1, c2) { + t.Errorf("%v and %v should be equal", c1, c2) + } } func TestSyncConf(t *testing.T) { - tree1 := NewTree() - tree2 := NewTree() - tree1.AddConfiguration(1, "blapp", "blepp") - s := NewSync(tree1, tree2) - s.Run() - c1, _ := tree1.Configuration() - c2, _ := tree2.Configuration() - if !reflect.DeepEqual(c1, c2) { - t.Errorf("%v and %v should be equal", c1, c2) - } + tree1 := NewTree() + tree2 := NewTree() + tree1.AddConfiguration(1, "blapp", "blepp") + s := NewSync(tree1, tree2) + s.Run() + c1, _ := tree1.Configuration() + c2, _ := tree2.Configuration() + if !reflect.DeepEqual(c1, c2) { + t.Errorf("%v and %v should be equal", c1, c2) + } } func TestTreeHash(t *testing.T) { - tree1 := NewTree() - var keys [][]byte - var vals [][]byte - n := 10 - var k []byte - var v []byte - for i := 0; i < n; i++ { - k = []byte(fmt.Sprint(rand.Int63())) - v = []byte(fmt.Sprint(rand.Int63())) - keys = append(keys, k) - vals = append(vals, v) - tree1.Put(k, v, 1) - } - keybackup := keys - tree2 := NewTree() - for i := 0; i < n; i++ { - index := rand.Int() % len(keys) - k = keys[index] - v = vals[index] - tree2.Put(k, v, 1) - keys = append(keys[:index], keys[index+1:]...) - vals = append(vals[:index], vals[index+1:]...) - } - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !reflect.DeepEqual(tree1.Finger(nil), tree2.Finger(nil)) { - t.Errorf("%v and %v have prints\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Finger(nil), tree2.Finger(nil)) - } - tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { - f1 := tree1.Finger(Rip(key)) - f2 := tree2.Finger(Rip(key)) - if f1 == nil || f2 == nil { - t.Errorf("should not be nil!") - } - if !reflect.DeepEqual(f1, f2) { - t.Errorf("should be equal!") - } - return true - }) - var deletes []int - for i := 0; i < n/10; i++ { - index := rand.Int() % len(keybackup) - deletes = append(deletes, index) - } - var successes []bool - for i := 0; i < n/10; i++ { - _, ok := tree1.Del(keybackup[deletes[i]]) - successes = append(successes, ok) - } - for i := 0; i < n/10; i++ { - if _, ok := tree2.Del(keybackup[deletes[i]]); ok != successes[i] { - t.Errorf("delete success should be %v", successes[i]) - } - } - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) - } - if !reflect.DeepEqual(tree1.Finger(nil), tree2.Finger(nil)) { - t.Errorf("%v and %v have prints\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Finger(nil), tree2.Finger(nil)) - } - tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { - f1 := tree1.Finger(Rip(key)) - f2 := tree2.Finger(Rip(key)) - if f1 == nil || f2 == nil { - t.Errorf("should not be nil!") - } - if !reflect.DeepEqual(f1, f2) { - t.Errorf("should be equal!") - } - return true - }) + tree1 := NewTree() + var keys [][]byte + var vals [][]byte + n := 10 + var k []byte + var v []byte + for i := 0; i < n; i++ { + k = []byte(fmt.Sprint(rand.Int63())) + v = []byte(fmt.Sprint(rand.Int63())) + keys = append(keys, k) + vals = append(vals, v) + tree1.Put(k, v, 1) + } + keybackup := keys + tree2 := NewTree() + for i := 0; i < n; i++ { + index := rand.Int() % len(keys) + k = keys[index] + v = vals[index] + tree2.Put(k, v, 1) + keys = append(keys[:index], keys[index+1:]...) + vals = append(vals[:index], vals[index+1:]...) + } + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !reflect.DeepEqual(tree1.Finger(nil), tree2.Finger(nil)) { + t.Errorf("%v and %v have prints\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Finger(nil), tree2.Finger(nil)) + } + tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { + f1 := tree1.Finger(Rip(key)) + f2 := tree2.Finger(Rip(key)) + if f1 == nil || f2 == nil { + t.Errorf("should not be nil!") + } + if !reflect.DeepEqual(f1, f2) { + t.Errorf("should be equal!") + } + return true + }) + var deletes []int + for i := 0; i < n/10; i++ { + index := rand.Int() % len(keybackup) + deletes = append(deletes, index) + } + var successes []bool + for i := 0; i < n/10; i++ { + _, ok := tree1.Del(keybackup[deletes[i]]) + successes = append(successes, ok) + } + for i := 0; i < n/10; i++ { + if _, ok := tree2.Del(keybackup[deletes[i]]); ok != successes[i] { + t.Errorf("delete success should be %v", successes[i]) + } + } + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + t.Errorf("%v and %v have hashes\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Hash(), tree2.Hash()) + } + if !reflect.DeepEqual(tree1.Finger(nil), tree2.Finger(nil)) { + t.Errorf("%v and %v have prints\n%v\n%v\nand they should be equal!", tree1.Describe(), tree2.Describe(), tree1.Finger(nil), tree2.Finger(nil)) + } + tree1.Each(func(key []byte, byteValue []byte, timestamp int64) bool { + f1 := tree1.Finger(Rip(key)) + f2 := tree2.Finger(Rip(key)) + if f1 == nil || f2 == nil { + t.Errorf("should not be nil!") + } + if !reflect.DeepEqual(f1, f2) { + t.Errorf("should be equal!") + } + return true + }) } func createKVArraysDown(from, to int) (keys [][]byte, values [][]byte) { - for i := to - 1; i >= from; i-- { - if i >= from { - keys = append(keys, []byte(fmt.Sprint(i))) - values = append(values, []byte(fmt.Sprint(i))) - } - } - return + for i := to - 1; i >= from; i-- { + if i >= from { + keys = append(keys, []byte(fmt.Sprint(i))) + values = append(values, []byte(fmt.Sprint(i))) + } + } + return } func createKVArraysUp(from, to int) (keys [][]byte, values [][]byte) { - for i := from; i < to; i++ { - if i < to { - keys = append(keys, []byte(fmt.Sprint(i))) - values = append(values, []byte(fmt.Sprint(i))) - } - } - return + for i := from; i < to; i++ { + if i < to { + keys = append(keys, []byte(fmt.Sprint(i))) + values = append(values, []byte(fmt.Sprint(i))) + } + } + return } func TestTreeReverseEach(t *testing.T) { - tree := NewTree() - for i := 100; i < 200; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - var foundKeys [][]byte - var foundValues [][]byte - tree.ReverseEach(func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues := createKVArraysDown(100, 200) - if !reflect.DeepEqual(cmpKeys, foundKeys) { - t.Errorf("%v should be %v", foundKeys, cmpKeys) - } - if !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v should be %v", foundValues, cmpValues) - } - foundKeys = nil - foundValues = nil - count := 10 - tree.ReverseEach(func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - count-- - return count > 0 - }) - cmpKeys, cmpValues = createKVArraysDown(190, 200) - if !reflect.DeepEqual(cmpKeys, foundKeys) { - t.Errorf("%v should be %v", foundKeys, cmpKeys) - } - if !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v should be %v", foundValues, cmpValues) - } + tree := NewTree() + for i := 100; i < 200; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + var foundKeys [][]byte + var foundValues [][]byte + tree.ReverseEach(func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues := createKVArraysDown(100, 200) + if !reflect.DeepEqual(cmpKeys, foundKeys) { + t.Errorf("%v should be %v", foundKeys, cmpKeys) + } + if !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v should be %v", foundValues, cmpValues) + } + foundKeys = nil + foundValues = nil + count := 10 + tree.ReverseEach(func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + count-- + return count > 0 + }) + cmpKeys, cmpValues = createKVArraysDown(190, 200) + if !reflect.DeepEqual(cmpKeys, foundKeys) { + t.Errorf("%v should be %v", foundKeys, cmpKeys) + } + if !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v should be %v", foundValues, cmpValues) + } } func TestTreeEach(t *testing.T) { - tree := NewTree() - for i := 100; i < 200; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - var foundKeys [][]byte - var foundValues [][]byte - tree.Each(func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues := createKVArraysUp(100, 200) - if !reflect.DeepEqual(cmpKeys, foundKeys) { - t.Errorf("%v should be %v", foundKeys, cmpKeys) - } - if !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v should be %v", foundValues, cmpValues) - } - foundKeys = nil - foundValues = nil - count := 10 - tree.Each(func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - count-- - return count > 0 - }) - cmpKeys, cmpValues = createKVArraysUp(100, 110) - if !reflect.DeepEqual(cmpKeys, foundKeys) { - t.Errorf("%v should be %v", foundKeys, cmpKeys) - } - if !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v should be %v", foundValues, cmpValues) - } + tree := NewTree() + for i := 100; i < 200; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + var foundKeys [][]byte + var foundValues [][]byte + tree.Each(func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues := createKVArraysUp(100, 200) + if !reflect.DeepEqual(cmpKeys, foundKeys) { + t.Errorf("%v should be %v", foundKeys, cmpKeys) + } + if !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v should be %v", foundValues, cmpValues) + } + foundKeys = nil + foundValues = nil + count := 10 + tree.Each(func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + count-- + return count > 0 + }) + cmpKeys, cmpValues = createKVArraysUp(100, 110) + if !reflect.DeepEqual(cmpKeys, foundKeys) { + t.Errorf("%v should be %v", foundKeys, cmpKeys) + } + if !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v should be %v", foundValues, cmpValues) + } } func TestTreeReverseEachBetween(t *testing.T) { - tree := NewTree() - for i := 11; i < 20; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - var foundKeys, cmpKeys [][]byte - var foundValues, cmpValues [][]byte - for i := 10; i < 21; i++ { - for j := i; j < 21; j++ { - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.ReverseEachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, true, func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues = createKVArraysDown(common.Max(11, i), common.Min(j+1, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.ReverseEachBetween(%v, %v, true, true) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.ReverseEachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, true, func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues = createKVArraysDown(common.Max(11, i+1), common.Min(j+1, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.ReverseEachBetween(%v, %v, false, true) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.ReverseEachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, false, func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues = createKVArraysDown(common.Max(11, i), common.Min(j, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.ReverseEachBetween(%v, %v, true, false) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.ReverseEachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, false, func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues = createKVArraysDown(common.Max(11, i+1), common.Min(j, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.ReverseEachBetween(%v, %v, false, false) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - } - } + tree := NewTree() + for i := 11; i < 20; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + var foundKeys, cmpKeys [][]byte + var foundValues, cmpValues [][]byte + for i := 10; i < 21; i++ { + for j := i; j < 21; j++ { + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.ReverseEachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, true, func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues = createKVArraysDown(common.Max(11, i), common.Min(j+1, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.ReverseEachBetween(%v, %v, true, true) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.ReverseEachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, true, func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues = createKVArraysDown(common.Max(11, i+1), common.Min(j+1, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.ReverseEachBetween(%v, %v, false, true) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.ReverseEachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, false, func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues = createKVArraysDown(common.Max(11, i), common.Min(j, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.ReverseEachBetween(%v, %v, true, false) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.ReverseEachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, false, func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues = createKVArraysDown(common.Max(11, i+1), common.Min(j, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.ReverseEachBetween(%v, %v, false, false) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + } + } } func TestTreeEachBetween(t *testing.T) { - tree := NewTree() - for i := 11; i < 20; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - var foundKeys, cmpKeys [][]byte - var foundValues, cmpValues [][]byte - for i := 10; i < 21; i++ { - for j := i; j < 21; j++ { - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.EachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, true, func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i), common.Min(j+1, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.EachBetween(%v, %v, true, true) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.EachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, true, func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i+1), common.Min(j+1, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.EachBetween(%v, %v, false, true) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.EachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, false, func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i), common.Min(j, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.EachBetween(%v, %v, true, false) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.EachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, false, func(key []byte, byteValue []byte, timestamp int64) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i+1), common.Min(j, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.EachBetween(%v, %v, false, false) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - } - } + tree := NewTree() + for i := 11; i < 20; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + var foundKeys, cmpKeys [][]byte + var foundValues, cmpValues [][]byte + for i := 10; i < 21; i++ { + for j := i; j < 21; j++ { + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.EachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, true, func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i), common.Min(j+1, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.EachBetween(%v, %v, true, true) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.EachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, true, func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i+1), common.Min(j+1, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.EachBetween(%v, %v, false, true) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.EachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), true, false, func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i), common.Min(j, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.EachBetween(%v, %v, true, false) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.EachBetween([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(j)), false, false, func(key []byte, byteValue []byte, timestamp int64) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i+1), common.Min(j, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.EachBetween(%v, %v, false, false) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + } + } } func TestTreeReverseIndexOf(t *testing.T) { - tree := NewTree() - for i := 100; i < 200; i += 2 { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - for i := 100; i < 200; i++ { - shouldExist := i%2 == 0 - wantedIndex := 49 - (i-100)/2 - if ind, e := tree.ReverseIndexOf([]byte(fmt.Sprint(i))); ind != wantedIndex || e != shouldExist { - t.Errorf("%v.ReverseIndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), i, ind, e, wantedIndex, shouldExist) - } - } - if ind, e := tree.ReverseIndexOf([]byte("1991")); ind != 0 || e { - t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), "1991", ind, e, 0, false) - } - if ind, e := tree.ReverseIndexOf([]byte("099")); ind != 50 || e { - t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), "099", ind, e, 50, false) - } + tree := NewTree() + for i := 100; i < 200; i += 2 { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + for i := 100; i < 200; i++ { + shouldExist := i%2 == 0 + wantedIndex := 49 - (i-100)/2 + if ind, e := tree.ReverseIndexOf([]byte(fmt.Sprint(i))); ind != wantedIndex || e != shouldExist { + t.Errorf("%v.ReverseIndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), i, ind, e, wantedIndex, shouldExist) + } + } + if ind, e := tree.ReverseIndexOf([]byte("1991")); ind != 0 || e { + t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), "1991", ind, e, 0, false) + } + if ind, e := tree.ReverseIndexOf([]byte("099")); ind != 50 || e { + t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), "099", ind, e, 50, false) + } } func TestTreeIndexOf(t *testing.T) { - tree := NewTree() - for i := 100; i < 200; i += 2 { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - for i := 100; i < 200; i++ { - shouldExist := i%2 == 0 - wantedIndex := (i - 99) / 2 - if ind, e := tree.IndexOf([]byte(fmt.Sprint(i))); ind != wantedIndex || e != shouldExist { - t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), ind, e, wantedIndex, shouldExist) - } - } - if ind, e := tree.IndexOf([]byte("1991")); ind != 50 || e { - t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), "1991", ind, e, 50, false) - } - if ind, e := tree.IndexOf([]byte("099")); ind != 0 || e { - t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), "099", ind, e, 0, false) - } + tree := NewTree() + for i := 100; i < 200; i += 2 { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + for i := 100; i < 200; i++ { + shouldExist := i%2 == 0 + wantedIndex := (i - 99) / 2 + if ind, e := tree.IndexOf([]byte(fmt.Sprint(i))); ind != wantedIndex || e != shouldExist { + t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), common.HexEncode([]byte(fmt.Sprint(i))), ind, e, wantedIndex, shouldExist) + } + } + if ind, e := tree.IndexOf([]byte("1991")); ind != 50 || e { + t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), "1991", ind, e, 50, false) + } + if ind, e := tree.IndexOf([]byte("099")); ind != 0 || e { + t.Errorf("%v.IndexOf(%v) => %v, %v should be %v, %v", tree.Describe(), "099", ind, e, 0, false) + } } func TestTreeReverseEachBetweenIndex(t *testing.T) { - tree := NewTree() - for i := 11; i < 20; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - var foundKeys, cmpKeys [][]byte - var foundValues, cmpValues [][]byte - for i := -1; i < 10; i++ { - for j := i; j < 10; j++ { - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.ReverseEachBetweenIndex(&i, &j, func(key []byte, byteValue []byte, timestamp int64, index int) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - - cmpKeys, cmpValues = createKVArraysDown(common.Max(11, 19-j), common.Min(20, 20-i)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.EachBetweenIndex(%v, %v) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - } - } + tree := NewTree() + for i := 11; i < 20; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + var foundKeys, cmpKeys [][]byte + var foundValues, cmpValues [][]byte + for i := -1; i < 10; i++ { + for j := i; j < 10; j++ { + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.ReverseEachBetweenIndex(&i, &j, func(key []byte, byteValue []byte, timestamp int64, index int) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + + cmpKeys, cmpValues = createKVArraysDown(common.Max(11, 19-j), common.Min(20, 20-i)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.EachBetweenIndex(%v, %v) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + } + } } func TestTreeEachBetweenIndex(t *testing.T) { - tree := NewTree() - for i := 11; i < 20; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - var foundKeys, cmpKeys [][]byte - var foundValues, cmpValues [][]byte - for i := -1; i < 10; i++ { - for j := i; j < 10; j++ { - foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil - tree.EachBetweenIndex(&i, &j, func(key []byte, byteValue []byte, timestamp int64, index int) bool { - foundKeys = append(foundKeys, key) - foundValues = append(foundValues, byteValue) - return true - }) - - cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i+11), common.Min(j+12, 20)) - if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { - t.Errorf("%v.EachBetweenIndex(%v, %v) => %v should be %v", tree, i, j, foundValues, cmpValues) - } - } - } + tree := NewTree() + for i := 11; i < 20; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + var foundKeys, cmpKeys [][]byte + var foundValues, cmpValues [][]byte + for i := -1; i < 10; i++ { + for j := i; j < 10; j++ { + foundKeys, cmpKeys, foundValues, cmpValues = nil, nil, nil, nil + tree.EachBetweenIndex(&i, &j, func(key []byte, byteValue []byte, timestamp int64, index int) bool { + foundKeys = append(foundKeys, key) + foundValues = append(foundValues, byteValue) + return true + }) + + cmpKeys, cmpValues = createKVArraysUp(common.Max(11, i+11), common.Min(j+12, 20)) + if !reflect.DeepEqual(cmpKeys, foundKeys) || !reflect.DeepEqual(cmpValues, foundValues) { + t.Errorf("%v.EachBetweenIndex(%v, %v) => %v should be %v", tree, i, j, foundValues, cmpValues) + } + } + } } func TestTreeNilKey(t *testing.T) { - tree := NewTree() - h := tree.Hash() - if value, _, existed := tree.Get(nil); value != nil || existed { - t.Errorf("should not exist") - } - if value, existed := tree.Put(nil, nil, 1); value != nil || existed { - t.Errorf("should not exist") - } - if value, _, existed := tree.Get(nil); value != nil || !existed { - t.Errorf("should exist") - } - if value, existed := tree.Del(nil); value != nil || !existed { - t.Errorf("should exist") - } - if value, _, existed := tree.Get(nil); value != nil || existed { - t.Errorf("nil should not exist in %v", tree.Describe()) - } - if bytes.Compare(h, tree.Hash()) != 0 { - t.Errorf("should be equal") - } + tree := NewTree() + h := tree.Hash() + if value, _, existed := tree.Get(nil); value != nil || existed { + t.Errorf("should not exist") + } + if value, existed := tree.Put(nil, nil, 1); value != nil || existed { + t.Errorf("should not exist") + } + if value, _, existed := tree.Get(nil); value != nil || !existed { + t.Errorf("should exist") + } + if value, existed := tree.Del(nil); value != nil || !existed { + t.Errorf("should exist") + } + if value, _, existed := tree.Get(nil); value != nil || existed { + t.Errorf("nil should not exist in %v", tree.Describe()) + } + if bytes.Compare(h, tree.Hash()) != 0 { + t.Errorf("should be equal") + } } func TestTreeFirstLast(t *testing.T) { - tree := NewTree() - for i := 10; i < 20; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - if key, value, timestamp, existed := tree.First(); !existed || bytes.Compare(key, []byte(fmt.Sprint(10))) != 0 || timestamp != 1 || bytes.Compare(value, []byte(fmt.Sprint(10))) != 0 { - t.Errorf("%v.First() should be %v, %v, %v, %v but was %v, %v, %v, %v", tree.Describe(), []byte(fmt.Sprint(10)), []byte(fmt.Sprint(10)), 1, true, key, value, timestamp, existed) - } - if key, value, timestamp, existed := tree.Last(); !existed || bytes.Compare(key, []byte(fmt.Sprint(19))) != 0 || timestamp != 1 || bytes.Compare(value, []byte(fmt.Sprint(19))) != 0 { - t.Errorf("%v.Last() should be %v, %v, %v, %v but was %v, %v, %v, %v", tree.Describe(), string([]byte(fmt.Sprint(19))), []byte(fmt.Sprint(19)), 1, true, string(key), string(value), timestamp, existed) - } + tree := NewTree() + for i := 10; i < 20; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + if key, value, timestamp, existed := tree.First(); !existed || bytes.Compare(key, []byte(fmt.Sprint(10))) != 0 || timestamp != 1 || bytes.Compare(value, []byte(fmt.Sprint(10))) != 0 { + t.Errorf("%v.First() should be %v, %v, %v, %v but was %v, %v, %v, %v", tree.Describe(), []byte(fmt.Sprint(10)), []byte(fmt.Sprint(10)), 1, true, key, value, timestamp, existed) + } + if key, value, timestamp, existed := tree.Last(); !existed || bytes.Compare(key, []byte(fmt.Sprint(19))) != 0 || timestamp != 1 || bytes.Compare(value, []byte(fmt.Sprint(19))) != 0 { + t.Errorf("%v.Last() should be %v, %v, %v, %v but was %v, %v, %v, %v", tree.Describe(), string([]byte(fmt.Sprint(19))), []byte(fmt.Sprint(19)), 1, true, string(key), string(value), timestamp, existed) + } } func TestTreeIndex(t *testing.T) { - tree := NewTree() - for i := 100; i < 200; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - for i := 0; i < 100; i++ { - if key, value, timestamp, existed := tree.Index(i); !existed || bytes.Compare(key, []byte(fmt.Sprint(i+100))) != 0 || timestamp != 1 || bytes.Compare(value, []byte(fmt.Sprint(i+100))) != 0 { - t.Errorf("%v.Index(%v) should be %v, %v, %v, %v but was %v, %v, %v, %v", tree.Describe(), i, []byte(fmt.Sprint(i+100)), []byte(fmt.Sprint(i+100)), 1, true, key, value, timestamp, existed) - } - } + tree := NewTree() + for i := 100; i < 200; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + for i := 0; i < 100; i++ { + if key, value, timestamp, existed := tree.Index(i); !existed || bytes.Compare(key, []byte(fmt.Sprint(i+100))) != 0 || timestamp != 1 || bytes.Compare(value, []byte(fmt.Sprint(i+100))) != 0 { + t.Errorf("%v.Index(%v) should be %v, %v, %v, %v but was %v, %v, %v, %v", tree.Describe(), i, []byte(fmt.Sprint(i+100)), []byte(fmt.Sprint(i+100)), 1, true, key, value, timestamp, existed) + } + } } func TestTreePrev(t *testing.T) { - tree := NewTree() - for i := 100; i < 200; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - for i := 101; i < 200; i++ { - if key, _, _, existed := tree.Prev([]byte(fmt.Sprint(i))); string(key) != fmt.Sprint(i-1) || !existed { - t.Errorf("%v, %v should be %v, %v", string(key), existed, fmt.Sprint(i-1), true) - } - } - if key, _, _, existed := tree.Prev([]byte("100")); existed { - t.Errorf("%v, %v should not exist!", key, existed) - } + tree := NewTree() + for i := 100; i < 200; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + for i := 101; i < 200; i++ { + if key, _, _, existed := tree.Prev([]byte(fmt.Sprint(i))); string(key) != fmt.Sprint(i-1) || !existed { + t.Errorf("%v, %v should be %v, %v", string(key), existed, fmt.Sprint(i-1), true) + } + } + if key, _, _, existed := tree.Prev([]byte("100")); existed { + t.Errorf("%v, %v should not exist!", key, existed) + } } func TestTreeNext(t *testing.T) { - tree := NewTree() - for i := 100; i < 200; i++ { - tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) - } - for i := 100; i < 199; i++ { - if key, _, _, existed := tree.Next([]byte(fmt.Sprint(i))); string(key) != fmt.Sprint(i+1) || !existed { - t.Errorf("%v, %v should be %v, %v", string(key), existed, fmt.Sprint(i+1), true) - } - } - if key, _, _, existed := tree.Next([]byte("199")); existed { - t.Errorf("%v, %v should not exist!", key, existed) - } + tree := NewTree() + for i := 100; i < 200; i++ { + tree.Put([]byte(fmt.Sprint(i)), []byte(fmt.Sprint(i)), 1) + } + for i := 100; i < 199; i++ { + if key, _, _, existed := tree.Next([]byte(fmt.Sprint(i))); string(key) != fmt.Sprint(i+1) || !existed { + t.Errorf("%v, %v should be %v, %v", string(key), existed, fmt.Sprint(i+1), true) + } + } + if key, _, _, existed := tree.Next([]byte("199")); existed { + t.Errorf("%v, %v should not exist!", key, existed) + } } func TestTreeBasicOps(t *testing.T) { - tree := NewTree() - assertSize(t, tree, 0) - assertNewPut(t, tree, "apple", "stonefruit") - assertSize(t, tree, 1) - assertOldPut(t, tree, "apple", "fruit", "stonefruit") - assertSize(t, tree, 1) - assertNewPut(t, tree, "crab", "critter") - assertSize(t, tree, 2) - assertOldPut(t, tree, "crab", "animal", "critter") - assertSize(t, tree, 2) - assertNewPut(t, tree, "crabapple", "poop") - assertSize(t, tree, 3) - assertOldPut(t, tree, "crabapple", "fruit", "poop") - assertSize(t, tree, 3) - assertNewPut(t, tree, "banana", "yellow") - assertSize(t, tree, 4) - assertOldPut(t, tree, "banana", "fruit", "yellow") - assertSize(t, tree, 4) - assertNewPut(t, tree, "guava", "fart") - assertSize(t, tree, 5) - assertOldPut(t, tree, "guava", "fruit", "fart") - assertSize(t, tree, 5) - assertNewPut(t, tree, "guanabana", "man") - assertSize(t, tree, 6) - assertOldPut(t, tree, "guanabana", "city", "man") - assertSize(t, tree, 6) - m := make(map[string][]byte) - tree.Each(func(key []byte, byteValue []byte, timestamp int64) bool { - m[hex.EncodeToString(key)] = byteValue - return true - }) - comp := map[string][]byte{ - hex.EncodeToString([]byte("apple")): []byte("fruit"), - hex.EncodeToString([]byte("crab")): []byte("animal"), - hex.EncodeToString([]byte("crabapple")): []byte("fruit"), - hex.EncodeToString([]byte("banana")): []byte("fruit"), - hex.EncodeToString([]byte("guava")): []byte("fruit"), - hex.EncodeToString([]byte("guanabana")): []byte("city"), - } - if !reflect.DeepEqual(m, comp) { - t.Errorf("%+v and %+v should be equal!", m, comp) - } - if !reflect.DeepEqual(tree.ToMap(), comp) { - t.Errorf("%v and %v should be equal!", tree.ToMap(), comp) - } - if old, existed := tree.Put(nil, []byte("nil"), 1); old != nil || existed { - t.Error("should not exist yet") - } - if old, existed := tree.Put([]byte("nil"), nil, 1); old != nil || existed { - t.Error("should not exist yet") - } - if value, _, existed := tree.Get(nil); !existed || bytes.Compare(value, []byte("nil")) != 0 { - t.Errorf("%v should contain %v => %v, got %v, %v", tree.Describe(), nil, "nil", value, existed) - } - if value, _, existed := tree.Get([]byte("nil")); !existed || value != nil { - t.Errorf("%v should contain %v => %v, got %v, %v", tree, "nil", nil, value, existed) - } - assertDelFailure(t, tree, "gua") - assertSize(t, tree, 8) - assertDelSuccess(t, tree, "apple", "fruit") - assertSize(t, tree, 7) - assertDelFailure(t, tree, "apple") - assertSize(t, tree, 7) - assertDelSuccess(t, tree, "crab", "animal") - assertSize(t, tree, 6) - assertDelFailure(t, tree, "crab") - assertSize(t, tree, 6) - assertDelSuccess(t, tree, "crabapple", "fruit") - assertSize(t, tree, 5) - assertDelFailure(t, tree, "crabapple") - assertSize(t, tree, 5) - assertDelSuccess(t, tree, "banana", "fruit") - assertSize(t, tree, 4) - assertDelFailure(t, tree, "banana") - assertSize(t, tree, 4) - assertDelSuccess(t, tree, "guava", "fruit") - assertSize(t, tree, 3) - assertDelFailure(t, tree, "guava") - assertSize(t, tree, 3) - assertDelSuccess(t, tree, "guanabana", "city") - assertSize(t, tree, 2) - assertDelFailure(t, tree, "guanabana") - assertSize(t, tree, 2) + tree := NewTree() + assertSize(t, tree, 0) + assertNewPut(t, tree, "apple", "stonefruit") + assertSize(t, tree, 1) + assertOldPut(t, tree, "apple", "fruit", "stonefruit") + assertSize(t, tree, 1) + assertNewPut(t, tree, "crab", "critter") + assertSize(t, tree, 2) + assertOldPut(t, tree, "crab", "animal", "critter") + assertSize(t, tree, 2) + assertNewPut(t, tree, "crabapple", "poop") + assertSize(t, tree, 3) + assertOldPut(t, tree, "crabapple", "fruit", "poop") + assertSize(t, tree, 3) + assertNewPut(t, tree, "banana", "yellow") + assertSize(t, tree, 4) + assertOldPut(t, tree, "banana", "fruit", "yellow") + assertSize(t, tree, 4) + assertNewPut(t, tree, "guava", "fart") + assertSize(t, tree, 5) + assertOldPut(t, tree, "guava", "fruit", "fart") + assertSize(t, tree, 5) + assertNewPut(t, tree, "guanabana", "man") + assertSize(t, tree, 6) + assertOldPut(t, tree, "guanabana", "city", "man") + assertSize(t, tree, 6) + m := make(map[string][]byte) + tree.Each(func(key []byte, byteValue []byte, timestamp int64) bool { + m[hex.EncodeToString(key)] = byteValue + return true + }) + comp := map[string][]byte{ + hex.EncodeToString([]byte("apple")): []byte("fruit"), + hex.EncodeToString([]byte("crab")): []byte("animal"), + hex.EncodeToString([]byte("crabapple")): []byte("fruit"), + hex.EncodeToString([]byte("banana")): []byte("fruit"), + hex.EncodeToString([]byte("guava")): []byte("fruit"), + hex.EncodeToString([]byte("guanabana")): []byte("city"), + } + if !reflect.DeepEqual(m, comp) { + t.Errorf("%+v and %+v should be equal!", m, comp) + } + if !reflect.DeepEqual(tree.ToMap(), comp) { + t.Errorf("%v and %v should be equal!", tree.ToMap(), comp) + } + if old, existed := tree.Put(nil, []byte("nil"), 1); old != nil || existed { + t.Error("should not exist yet") + } + if old, existed := tree.Put([]byte("nil"), nil, 1); old != nil || existed { + t.Error("should not exist yet") + } + if value, _, existed := tree.Get(nil); !existed || bytes.Compare(value, []byte("nil")) != 0 { + t.Errorf("%v should contain %v => %v, got %v, %v", tree.Describe(), nil, "nil", value, existed) + } + if value, _, existed := tree.Get([]byte("nil")); !existed || value != nil { + t.Errorf("%v should contain %v => %v, got %v, %v", tree, "nil", nil, value, existed) + } + assertDelFailure(t, tree, "gua") + assertSize(t, tree, 8) + assertDelSuccess(t, tree, "apple", "fruit") + assertSize(t, tree, 7) + assertDelFailure(t, tree, "apple") + assertSize(t, tree, 7) + assertDelSuccess(t, tree, "crab", "animal") + assertSize(t, tree, 6) + assertDelFailure(t, tree, "crab") + assertSize(t, tree, 6) + assertDelSuccess(t, tree, "crabapple", "fruit") + assertSize(t, tree, 5) + assertDelFailure(t, tree, "crabapple") + assertSize(t, tree, 5) + assertDelSuccess(t, tree, "banana", "fruit") + assertSize(t, tree, 4) + assertDelFailure(t, tree, "banana") + assertSize(t, tree, 4) + assertDelSuccess(t, tree, "guava", "fruit") + assertSize(t, tree, 3) + assertDelFailure(t, tree, "guava") + assertSize(t, tree, 3) + assertDelSuccess(t, tree, "guanabana", "city") + assertSize(t, tree, 2) + assertDelFailure(t, tree, "guanabana") + assertSize(t, tree, 2) } func benchTreeSync(b *testing.B, size, delta int) { - b.StopTimer() - tree1 := NewTree() - tree2 := NewTree() - var k []byte - var v []byte - for i := 0; i < size; i++ { - k = murmur.HashString(fmt.Sprint(i)) - v = []byte(fmt.Sprint(i)) - tree1.Put(k, v, 1) - tree2.Put(k, v, 1) - } - var s *Sync - for i := 0; i < b.N/delta; i++ { - for j := 0; j < delta; j++ { - tree2.Del(murmur.HashString(fmt.Sprint(j))) - } - b.StartTimer() - s = NewSync(tree1, tree2) - s.Run() - b.StopTimer() - if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { - b.Fatalf("%v != %v", tree1.Hash(), tree2.Hash()) - } - } + b.StopTimer() + tree1 := NewTree() + tree2 := NewTree() + var k []byte + var v []byte + for i := 0; i < size; i++ { + k = murmur.HashString(fmt.Sprint(i)) + v = []byte(fmt.Sprint(i)) + tree1.Put(k, v, 1) + tree2.Put(k, v, 1) + } + var s *Sync + for i := 0; i < b.N/delta; i++ { + for j := 0; j < delta; j++ { + tree2.Del(murmur.HashString(fmt.Sprint(j))) + } + b.StartTimer() + s = NewSync(tree1, tree2) + s.Run() + b.StopTimer() + if bytes.Compare(tree1.Hash(), tree2.Hash()) != 0 { + b.Fatalf("%v != %v", tree1.Hash(), tree2.Hash()) + } + } } func BenchmarkTreeSync10000_1(b *testing.B) { - benchTreeSync(b, 10000, 1) + benchTreeSync(b, 10000, 1) } func BenchmarkTreeSync10000_10(b *testing.B) { - benchTreeSync(b, 10000, 10) + benchTreeSync(b, 10000, 10) } func BenchmarkTreeSync10000_100(b *testing.B) { - benchTreeSync(b, 10000, 100) + benchTreeSync(b, 10000, 100) } func BenchmarkTreeSync10000_1000(b *testing.B) { - benchTreeSync(b, 10000, 1000) + benchTreeSync(b, 10000, 1000) } func BenchmarkTreeSync100000_1(b *testing.B) { - benchTreeSync(b, 100000, 1) + benchTreeSync(b, 100000, 1) } func BenchmarkTreeSync100000_10(b *testing.B) { - benchTreeSync(b, 100000, 10) + benchTreeSync(b, 100000, 10) } func BenchmarkTreeSync100000_100(b *testing.B) { - benchTreeSync(b, 100000, 100) + benchTreeSync(b, 100000, 100) } func BenchmarkTreeSync100000_1000(b *testing.B) { - benchTreeSync(b, 100000, 1000) + benchTreeSync(b, 100000, 1000) } func fillBenchTree(b *testing.B, n int) { - b.StopTimer() - for len(benchmarkTestKeys) < n { - benchmarkTestKeys = append(benchmarkTestKeys, murmur.HashString(fmt.Sprint(len(benchmarkTestKeys)))) - benchmarkTestValues = append(benchmarkTestValues, []byte(fmt.Sprint(len(benchmarkTestValues)))) - } - for benchmarkTestTree.Size() < n { - benchmarkTestTree.Put(benchmarkTestKeys[benchmarkTestTree.Size()], benchmarkTestValues[benchmarkTestTree.Size()], 1) - } - b.StartTimer() + b.StopTimer() + for len(benchmarkTestKeys) < n { + benchmarkTestKeys = append(benchmarkTestKeys, murmur.HashString(fmt.Sprint(len(benchmarkTestKeys)))) + benchmarkTestValues = append(benchmarkTestValues, []byte(fmt.Sprint(len(benchmarkTestValues)))) + } + for benchmarkTestTree.Size() < n { + benchmarkTestTree.Put(benchmarkTestKeys[benchmarkTestTree.Size()], benchmarkTestValues[benchmarkTestTree.Size()], 1) + } + b.StartTimer() } func benchTree(b *testing.B, n int, put, get bool) { - fillBenchTree(b, n) - b.StopTimer() - oldprocs := runtime.GOMAXPROCS(runtime.NumCPU()) - defer runtime.GOMAXPROCS(oldprocs) - var keys [][]byte - var vals [][]byte - for i := 0; i < b.N; i++ { - keys = append(keys, murmur.HashString(fmt.Sprint(rand.Int63()))) - vals = append(vals, []byte(fmt.Sprint(rand.Int63()))) - } - var k []byte - var v []byte - b.StartTimer() - for i := 0; i < b.N; i++ { - k = benchmarkTestKeys[i%len(benchmarkTestKeys)] - v = benchmarkTestValues[i%len(benchmarkTestValues)] - if put { - benchmarkTestTree.Put(k, v, 1) - } - if get { - j, _, existed := benchmarkTestTree.Get(k) - if bytes.Compare(j, v) != 0 { - b.Fatalf("%v should contain %v, but got %v, %v", benchmarkTestTree.Describe(), v, j, existed) - } - } - } + fillBenchTree(b, n) + b.StopTimer() + oldprocs := runtime.GOMAXPROCS(runtime.NumCPU()) + defer runtime.GOMAXPROCS(oldprocs) + var keys [][]byte + var vals [][]byte + for i := 0; i < b.N; i++ { + keys = append(keys, murmur.HashString(fmt.Sprint(rand.Int63()))) + vals = append(vals, []byte(fmt.Sprint(rand.Int63()))) + } + var k []byte + var v []byte + b.StartTimer() + for i := 0; i < b.N; i++ { + k = benchmarkTestKeys[i%len(benchmarkTestKeys)] + v = benchmarkTestValues[i%len(benchmarkTestValues)] + if put { + benchmarkTestTree.Put(k, v, 1) + } + if get { + j, _, existed := benchmarkTestTree.Get(k) + if bytes.Compare(j, v) != 0 { + b.Fatalf("%v should contain %v, but got %v, %v", benchmarkTestTree.Describe(), v, j, existed) + } + } + } } func BenchmarkTreePut10(b *testing.B) { - benchTree(b, 10, true, false) + benchTree(b, 10, true, false) } func BenchmarkTreeGet10(b *testing.B) { - benchTree(b, 10, false, true) + benchTree(b, 10, false, true) } func BenchmarkTreePut100(b *testing.B) { - benchTree(b, 100, true, false) + benchTree(b, 100, true, false) } func BenchmarkTreeGet100(b *testing.B) { - benchTree(b, 100, false, true) + benchTree(b, 100, false, true) } func BenchmarkTreePut1000(b *testing.B) { - benchTree(b, 1000, true, false) + benchTree(b, 1000, true, false) } func BenchmarkTreeGet1000(b *testing.B) { - benchTree(b, 1000, false, true) + benchTree(b, 1000, false, true) } func BenchmarkTreePut10000(b *testing.B) { - benchTree(b, 10000, true, false) + benchTree(b, 10000, true, false) } func BenchmarkTreeGet10000(b *testing.B) { - benchTree(b, 10000, false, true) + benchTree(b, 10000, false, true) } func BenchmarkTreePut100000(b *testing.B) { - benchTree(b, 100000, true, false) + benchTree(b, 100000, true, false) } func BenchmarkTreeGet100000(b *testing.B) { - benchTree(b, 100000, false, true) + benchTree(b, 100000, false, true) } func BenchmarkTreePut1000000(b *testing.B) { - benchTree(b, 1000000, true, false) + benchTree(b, 1000000, true, false) } func BenchmarkTreeGet1000000(b *testing.B) { - benchTree(b, 1000000, false, true) + benchTree(b, 1000000, false, true) } func BenchmarkTreeRealSizeBetween0_8_100000(b *testing.B) { - fillBenchTree(b, 100000) - max := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), murmur.Size*8), big.NewInt(2)) - for i := 0; i < b.N; i++ { - benchmarkTestTree.RealSizeBetween(nil, max.Bytes(), true, false) - } + fillBenchTree(b, 100000) + max := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), murmur.Size*8), big.NewInt(2)) + for i := 0; i < b.N; i++ { + benchmarkTestTree.RealSizeBetween(nil, max.Bytes(), true, false) + } } func BenchmarkTreeRealSizeBetween8_0_100000(b *testing.B) { - fillBenchTree(b, 100000) - max := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), murmur.Size*8), big.NewInt(2)) - for i := 0; i < b.N; i++ { - benchmarkTestTree.RealSizeBetween(max.Bytes(), nil, true, false) - } + fillBenchTree(b, 100000) + max := new(big.Int).Div(new(big.Int).Lsh(big.NewInt(1), murmur.Size*8), big.NewInt(2)) + for i := 0; i < b.N; i++ { + benchmarkTestTree.RealSizeBetween(max.Bytes(), nil, true, false) + } } func BenchmarkTreeNextMarkerIndex1000000(b *testing.B) { - fillBenchTree(b, 100000) - s := benchmarkTestTree.RealSize() - for i := 0; i < b.N; i++ { - benchmarkTestTree.NextMarkerIndex(int(rand.Int31n(int32(s)))) - } + fillBenchTree(b, 100000) + s := benchmarkTestTree.RealSize() + for i := 0; i < b.N; i++ { + benchmarkTestTree.NextMarkerIndex(int(rand.Int31n(int32(s)))) + } } func BenchmarkTreeMirrorPut10(b *testing.B) { - benchmarkTestTree = NewTree() - benchmarkTestTree.AddConfiguration(1, mirrored, yes) - benchTree(b, 10, true, false) + benchmarkTestTree = NewTree() + benchmarkTestTree.AddConfiguration(1, mirrored, yes) + benchTree(b, 10, true, false) } func BenchmarkTreeMirrorPut100(b *testing.B) { - benchTree(b, 100, true, false) + benchTree(b, 100, true, false) } func BenchmarkTreeMirrorPut1000(b *testing.B) { - benchTree(b, 1000, true, false) + benchTree(b, 1000, true, false) } func BenchmarkTreeMirrorPut10000(b *testing.B) { - benchTree(b, 10000, true, false) + benchTree(b, 10000, true, false) } func BenchmarkTreeMirrorPut100000(b *testing.B) { - benchTree(b, 100000, true, false) + benchTree(b, 100000, true, false) } func BenchmarkTreeMirrorPut1000000(b *testing.B) { - benchTree(b, 1000000, true, false) + benchTree(b, 1000000, true, false) } diff --git a/radix/subtree_wrapper.go b/radix/subtree_wrapper.go index dbf348a..b0db64e 100644 --- a/radix/subtree_wrapper.go +++ b/radix/subtree_wrapper.go @@ -1,55 +1,55 @@ package radix type subTreeWrapper struct { - parentTree HashTree - key []Nibble + parentTree HashTree + key []Nibble } func (self *subTreeWrapper) Configuration() (map[string]string, int64) { - return self.parentTree.SubConfiguration(Stitch(self.key)) + return self.parentTree.SubConfiguration(Stitch(self.key)) } func (self *subTreeWrapper) Configure(conf map[string]string, ts int64) { - self.parentTree.SubConfigure(Stitch(self.key), conf, ts) + self.parentTree.SubConfigure(Stitch(self.key), conf, ts) } func (self *subTreeWrapper) Hash() (hash []byte) { - if p := self.parentTree.Finger(self.key); p != nil { - hash = p.TreeHash - } - return + if p := self.parentTree.Finger(self.key); p != nil { + hash = p.TreeHash + } + return } func (self *subTreeWrapper) Finger(subKey []Nibble) *Print { - return self.parentTree.SubFinger(self.key, subKey) + return self.parentTree.SubFinger(self.key, subKey) } func (self *subTreeWrapper) GetTimestamp(subKey []Nibble) (byteValue []byte, version int64, present bool) { - return self.parentTree.SubGetTimestamp(self.key, subKey) + return self.parentTree.SubGetTimestamp(self.key, subKey) } func (self *subTreeWrapper) PutTimestamp(subKey []Nibble, byteValue []byte, present bool, expected, version int64) bool { - return self.parentTree.SubPutTimestamp(self.key, subKey, byteValue, present, expected, version) + return self.parentTree.SubPutTimestamp(self.key, subKey, byteValue, present, expected, version) } func (self *subTreeWrapper) DelTimestamp(subKey []Nibble, expected int64) bool { - return self.parentTree.SubDelTimestamp(self.key, subKey, expected) + return self.parentTree.SubDelTimestamp(self.key, subKey, expected) } func (self *subTreeWrapper) SubConfiguration(key []byte) (map[string]string, int64) { - panic(subTreeError) + panic(subTreeError) } func (self *subTreeWrapper) SubConfigure(key []byte, conf map[string]string, ts int64) { - panic(subTreeError) + panic(subTreeError) } func (self *subTreeWrapper) SubFinger(key, subKey []Nibble) (result *Print) { - panic(subTreeError) + panic(subTreeError) } func (self *subTreeWrapper) SubGetTimestamp(key, subKey []Nibble) (byteValue []byte, version int64, present bool) { - panic(subTreeError) + panic(subTreeError) } func (self *subTreeWrapper) SubPutTimestamp(key, subKey []Nibble, byteValue []byte, present bool, subExpected, subTimestamp int64) bool { - panic(subTreeError) + panic(subTreeError) } func (self *subTreeWrapper) SubDelTimestamp(key, subKey []Nibble, subExpected int64) bool { - panic(subTreeError) + panic(subTreeError) } func (self *subTreeWrapper) SubClearTimestamp(key []Nibble, expected, timestamp int64) int { - panic(subTreeError) + panic(subTreeError) } func (self *subTreeWrapper) SubKillTimestamp(key []Nibble, expected int64) int { - panic(subTreeError) + panic(subTreeError) } diff --git a/radix/sync.go b/radix/sync.go index 2d02eab..6e5280c 100644 --- a/radix/sync.go +++ b/radix/sync.go @@ -1,170 +1,195 @@ package radix import ( - "bytes" - "github.com/zond/god/common" + "bytes" + "github.com/zond/god/common" ) const ( - subTreeError = "Illegal, only one level of sub trees supported" + subTreeError = "Illegal, only one level of sub trees supported" ) // HashTree is something that can be synchronized using Sync. type HashTree interface { - Hash() []byte + Hash() []byte - Configuration() (conf map[string]string, timestamp int64) - Configure(conf map[string]string, timestamp int64) + Configuration() (conf map[string]string, timestamp int64) + Configure(conf map[string]string, timestamp int64) - Finger(key []Nibble) *Print - GetTimestamp(key []Nibble) (byteValue []byte, timestamp int64, present bool) - PutTimestamp(key []Nibble, byteValue []byte, present bool, expected, timestamp int64) bool - DelTimestamp(key []Nibble, expected int64) bool + Finger(key []Nibble) *Print + GetTimestamp(key []Nibble) (byteValue []byte, timestamp int64, present bool) + PutTimestamp(key []Nibble, byteValue []byte, present bool, expected, timestamp int64) bool + DelTimestamp(key []Nibble, expected int64) bool - SubConfiguration(key []byte) (conf map[string]string, timestamp int64) - SubConfigure(key []byte, conf map[string]string, timestamp int64) + SubConfiguration(key []byte) (conf map[string]string, timestamp int64) + SubConfigure(key []byte, conf map[string]string, timestamp int64) - SubFinger(key, subKey []Nibble) (result *Print) - SubGetTimestamp(key, subKey []Nibble) (byteValue []byte, timestamp int64, present bool) - SubPutTimestamp(key, subKey []Nibble, byteValue []byte, present bool, subExpected, subTimestamp int64) bool - SubDelTimestamp(key, subKey []Nibble, subExpected int64) bool - SubClearTimestamp(key []Nibble, expected, timestamp int64) (deleted int) - SubKillTimestamp(key []Nibble, expected int64) (deleted int) + SubFinger(key, subKey []Nibble) (result *Print) + SubGetTimestamp(key, subKey []Nibble) (byteValue []byte, timestamp int64, present bool) + SubPutTimestamp(key, subKey []Nibble, byteValue []byte, present bool, subExpected, subTimestamp int64) bool + SubDelTimestamp(key, subKey []Nibble, subExpected int64) bool + SubClearTimestamp(key []Nibble, expected, timestamp int64) (deleted int) + SubKillTimestamp(key []Nibble, expected int64) (deleted int) } // Sync synchronizes HashTrees using their fingerprints and mutators. type Sync struct { - source HashTree - destination HashTree - from []Nibble - to []Nibble - destructive bool - putCount int - delCount int + source HashTree + destination HashTree + from []Nibble + to []Nibble + destructive bool + putCount int + delCount int } func NewSync(source, destination HashTree) *Sync { - return &Sync{ - source: source, - destination: destination, - } + return &Sync{ + source: source, + destination: destination, + } } // From defines from what key, inclusive, that this Sync will synchronize. func (self *Sync) From(from []byte) *Sync { - self.from = Rip(from) - return self + self.from = Rip(from) + return self } // To defines from what key, exclusive, that this Sync will synchronize. func (self *Sync) To(to []byte) *Sync { - self.to = Rip(to) - return self + self.to = Rip(to) + return self } // Destroy defines that this Sync will delete whatever it copies from the source Tree. func (self *Sync) Destroy() *Sync { - self.destructive = true - return self + self.destructive = true + return self } // PutCount returns the number of entries this Sync has inserted into the destination Tree. func (self *Sync) PutCount() int { - return self.putCount + return self.putCount } // DelCount returns the number of entries this Sync has deleted from the source Tree. func (self *Sync) DelCount() int { - return self.delCount + return self.delCount } // Run will start this Sync and return when it is finished. func (self *Sync) Run() *Sync { - // If we have from and to, and they are equal, that means this sync is over an empty set... just ignore it - if self.from != nil && self.to != nil && nComp(self.from, self.to) == 0 { - return self - } - if self.destructive || bytes.Compare(self.source.Hash(), self.destination.Hash()) != 0 { - sourceConf, sourceTs := self.source.Configuration() - _, destTs := self.destination.Configuration() - if sourceTs > destTs { - self.destination.Configure(sourceConf, sourceTs) - } - self.synchronize(self.source.Finger(nil), self.destination.Finger(nil)) - } - return self + // If we have from and to, and they are equal, that means this sync is over an empty set... just ignore it + if self.from != nil && self.to != nil && nComp(self.from, self.to) == 0 { + return self + } + if self.destructive || bytes.Compare(self.source.Hash(), self.destination.Hash()) != 0 { + sourceConf, sourceTs := self.source.Configuration() + _, destTs := self.destination.Configuration() + if sourceTs > destTs { + self.destination.Configure(sourceConf, sourceTs) + } + self.synchronize(self.source.Finger(nil), self.destination.Finger(nil)) + } + return self } + +// potentiallyWithinLimits will check if the given key can contain children between the from and to Nibbles +// for this Sync when considering the namespace circular. func (self *Sync) potentiallyWithinLimits(key []Nibble) bool { - if self.from == nil || self.to == nil { - return true - } - cmpKey := toBytes(key) - cmpFrom := toBytes(self.from) - cmpTo := toBytes(self.to) - m := len(cmpKey) - if m > len(cmpFrom) { - m = len(cmpFrom) - } - if m > len(cmpTo) { - m = len(cmpTo) - } - return common.BetweenII(cmpKey[:m], cmpFrom[:m], cmpTo[:m]) + if self.from == nil || self.to == nil { + return true + } + cmpKey := toBytes(key) + cmpFrom := toBytes(self.from) + cmpTo := toBytes(self.to) + m := len(cmpKey) + if m > len(cmpFrom) { + m = len(cmpFrom) + } + if m > len(cmpTo) { + m = len(cmpTo) + } + return common.BetweenII(cmpKey[:m], cmpFrom[:m], cmpTo[:m]) } + +// withinLimits will check i the given key is actually between the from and to Nibbles for this Sync. func (self *Sync) withinLimits(key []Nibble) bool { - if self.from == nil || self.to == nil { - return true - } - return common.BetweenIE(toBytes(key), toBytes(self.from), toBytes(self.to)) + if self.from == nil || self.to == nil { + return true + } + return common.BetweenIE(toBytes(key), toBytes(self.from), toBytes(self.to)) } + +// synchronize will recursively run the actual synchronization. func (self *Sync) synchronize(sourcePrint, destinationPrint *Print) { - if sourcePrint.Exists { - if !sourcePrint.Empty && self.withinLimits(sourcePrint.Key) { - if sourcePrint.SubTree { - if bytes.Compare(sourcePrint.TreeHash, destinationPrint.TreeHash) != 0 { - if sourcePrint.TreeSize == 0 && destinationPrint.TreeSize > 0 && sourcePrint.TreeDataTimestamp > destinationPrint.TreeDataTimestamp { - self.putCount += self.destination.SubClearTimestamp(sourcePrint.Key, destinationPrint.TreeDataTimestamp, sourcePrint.TreeDataTimestamp) - } - subSync := NewSync(&subTreeWrapper{ - self.source, - sourcePrint.Key, - }, &subTreeWrapper{ - self.destination, - sourcePrint.Key, - }) - if self.destructive { - subSync.Destroy() - } - subSync.Run() - self.putCount += subSync.PutCount() - self.delCount += subSync.DelCount() - } else if self.destructive { - self.delCount += self.source.SubKillTimestamp(sourcePrint.Key, sourcePrint.TreeDataTimestamp) - } - } - if sourcePrint.Timestamp > 0 { - if !sourcePrint.coveredBy(destinationPrint) { - if value, timestamp, present := self.source.GetTimestamp(sourcePrint.Key); timestamp == sourcePrint.timestamp() { - if self.destination.PutTimestamp(sourcePrint.Key, value, present, destinationPrint.timestamp(), sourcePrint.timestamp()) { - self.putCount++ - } - } - } - if self.destructive && !sourcePrint.Empty { - if self.source.DelTimestamp(sourcePrint.Key, sourcePrint.timestamp()) { - self.delCount++ - } - } - } - } - for index, subPrint := range sourcePrint.SubPrints { - if subPrint.Exists && self.potentiallyWithinLimits(subPrint.Key) { - if self.destructive || (!destinationPrint.Exists || !subPrint.equals(destinationPrint.SubPrints[index])) { - self.synchronize( - self.source.Finger(subPrint.Key), - self.destination.Finger(subPrint.Key), - ) - } - } - } - } + // If there is a source key + if sourcePrint.Exists { + // If it represents a node containing synchronizable data, and it is within our limits + if !sourcePrint.Empty && self.withinLimits(sourcePrint.Key) { + // If it contains a sub tree + if sourcePrint.SubTree { + // If the sub tree in the destination is not equal to the sub tree in the source + if bytes.Compare(sourcePrint.TreeHash, destinationPrint.TreeHash) != 0 { + // If the source is empty, but not the destination, and the source is newer than the destination + if sourcePrint.TreeSize == 0 && destinationPrint.TreeSize > 0 && sourcePrint.TreeDataTimestamp > destinationPrint.TreeDataTimestamp { + // Clear the destination and count the number of removed keys. + self.putCount += self.destination.SubClearTimestamp(sourcePrint.Key, destinationPrint.TreeDataTimestamp, sourcePrint.TreeDataTimestamp) + } + // Synchronize the sub trees. If the destination is previously cleared, this will copy the configuration. + subSync := NewSync(&subTreeWrapper{ + self.source, + sourcePrint.Key, + }, &subTreeWrapper{ + self.destination, + sourcePrint.Key, + }) + if self.destructive { + subSync.Destroy() + } + subSync.Run() + self.putCount += subSync.PutCount() + self.delCount += subSync.DelCount() + } else if self.destructive { + // If the trees are equal, but this Sync is destructive, just remove the source sub tree. + self.delCount += self.source.SubKillTimestamp(sourcePrint.Key, sourcePrint.TreeDataTimestamp) + } + } + // If the source has a byte value. + if sourcePrint.Timestamp > 0 { + // If the destination print is not covered by the source print (it is not equal and it is older) + if !sourcePrint.coveredBy(destinationPrint) { + // If the source still contains the same timestamp + if value, timestamp, present := self.source.GetTimestamp(sourcePrint.Key); timestamp == sourcePrint.timestamp() { + // Put the found data in the destination + if self.destination.PutTimestamp(sourcePrint.Key, value, present, destinationPrint.timestamp(), sourcePrint.timestamp()) { + self.putCount++ + } + } + } + // If we are destructive and contain something + if self.destructive && !sourcePrint.Empty { + // Remove the byte value in the source. + if self.source.DelTimestamp(sourcePrint.Key, sourcePrint.timestamp()) { + self.delCount++ + } + } + } + } + // For each child of the source print + for index, subPrint := range sourcePrint.SubPrints { + // If there is a child node there, and it might contain matching keys + if subPrint.Exists && self.potentiallyWithinLimits(subPrint.Key) { + // If we are destructive, or if the prints are dissimilar + if self.destructive || (!destinationPrint.Exists || !subPrint.equals(destinationPrint.SubPrints[index])) { + // Synchronize the children + self.synchronize( + self.source.Finger(subPrint.Key), + self.destination.Finger(subPrint.Key), + ) + } + } + } + } } diff --git a/radix/tree.go b/radix/tree.go index 9a2b97c..6260d22 100644 --- a/radix/tree.go +++ b/radix/tree.go @@ -1,14 +1,14 @@ package radix import ( - "bytes" - "encoding/hex" - "fmt" - "github.com/zond/god/common" - "github.com/zond/god/murmur" - "github.com/zond/god/persistence" - "math/big" - "sync/atomic" + "bytes" + "encoding/hex" + "fmt" + "github.com/zond/god/common" + "github.com/zond/god/murmur" + "github.com/zond/god/persistence" + "math/big" + "sync/atomic" ) // NaiveTimer is a Timer that just provides the current system time. @@ -17,7 +17,7 @@ type NaiveTimer struct{} var faketime int64 func (self NaiveTimer) ContinuousTime() int64 { - return atomic.AddInt64(&faketime, 1) + return atomic.AddInt64(&faketime, 1) } // TreeIterators iterate over trees, and see the key, value and timestamp of what they iterate over. @@ -29,65 +29,65 @@ type TreeIterator func(key, value []byte, timestamp int64) (cont bool) type TreeIndexIterator func(key, value []byte, timestamp int64, index int) (cont bool) func cmps(mininc, maxinc bool) (mincmp, maxcmp int) { - if mininc { - mincmp = -1 - } - if maxinc { - maxcmp = 1 - } - return + if mininc { + mincmp = -1 + } + if maxinc { + maxcmp = 1 + } + return } func escapeBytes(b []byte) (result []byte) { - result = make([]byte, 0, len(b)) - for _, c := range b { - if c == 0 { - result = append(result, 0, 0) - } else { - result = append(result, c) - } - } - return + result = make([]byte, 0, len(b)) + for _, c := range b { + if c == 0 { + result = append(result, 0, 0) + } else { + result = append(result, c) + } + } + return } func incrementBytes(b []byte) []byte { - return new(big.Int).Add(new(big.Int).SetBytes(b), big.NewInt(1)).Bytes() + return new(big.Int).Add(new(big.Int).SetBytes(b), big.NewInt(1)).Bytes() } func newMirrorIterator(min, max []byte, mininc, maxinc bool, f TreeIterator) TreeIterator { - return func(key, value []byte, timestamp int64) bool { - gt := 0 - if mininc { - gt = -1 - } - lt := 0 - if maxinc { - lt = 1 - } - k := key[:len(key)-len(escapeBytes(value))-1] - if (min == nil || bytes.Compare(k, min) > gt) && (max == nil || bytes.Compare(k, max) < lt) { - return f(k, value, timestamp) - } - return true - } + return func(key, value []byte, timestamp int64) bool { + gt := 0 + if mininc { + gt = -1 + } + lt := 0 + if maxinc { + lt = 1 + } + k := key[:len(key)-len(escapeBytes(value))-1] + if (min == nil || bytes.Compare(k, min) > gt) && (max == nil || bytes.Compare(k, max) < lt) { + return f(k, value, timestamp) + } + return true + } } func newMirrorIndexIterator(f TreeIndexIterator) TreeIndexIterator { - return func(key, value []byte, timestamp int64, index int) bool { - return f(key[:len(key)-len(escapeBytes(value))-1], value, timestamp, index) - } + return func(key, value []byte, timestamp int64, index int) bool { + return f(key[:len(key)-len(escapeBytes(value))-1], value, timestamp, index) + } } func newNodeIterator(f TreeIterator) nodeIterator { - return func(key, bValue []byte, tValue *Tree, use int, timestamp int64) (cont bool) { - return f(key, bValue, timestamp) - } + return func(key, bValue []byte, tValue *Tree, use int, timestamp int64) (cont bool) { + return f(key, bValue, timestamp) + } } func newNodeIndexIterator(f TreeIndexIterator) nodeIndexIterator { - return func(key, bValue []byte, tValue *Tree, use int, timestamp int64, index int) (cont bool) { - return f(key, bValue, timestamp, index) - } + return func(key, bValue []byte, tValue *Tree, use int, timestamp int64, index int) (cont bool) { + return f(key, bValue, timestamp, index) + } } // Tree is a merkle tree inside a radix tree, where each node can contain a separate sub tree. @@ -98,1266 +98,1272 @@ func newNodeIndexIterator(f TreeIndexIterator) nodeIndexIterator { // // A Tree is configured to be mirrored or not by using AddConfiguration or SubAddConfiguration (for a sub tree) setting 'mirrored' to 'yes'. type Tree struct { - lock *common.TimeLock - timer Timer - logger *persistence.Logger - root *node - mirror *Tree - configuration map[string]string - configurationTimestamp int64 - dataTimestamp int64 + lock *common.TimeLock + timer Timer + logger *persistence.Logger + root *node + mirror *Tree + configuration map[string]string + configurationTimestamp int64 + dataTimestamp int64 } func NewTree() *Tree { - return NewTreeTimer(NaiveTimer{}) + return NewTreeTimer(NaiveTimer{}) } func NewTreeTimer(timer Timer) (result *Tree) { - result = &Tree{ - lock: common.NewTimeLock(), - timer: timer, - configuration: make(map[string]string), - } - result.root, _, _, _, _ = result.root.insert(nil, newNode(nil, nil, nil, 0, true, 0), result.timer.ContinuousTime()) - result.dataTimestamp = timer.ContinuousTime() - return + result = &Tree{ + lock: common.NewTimeLock(), + timer: timer, + configuration: make(map[string]string), + } + result.root, _, _, _, _ = result.root.insert(nil, newNode(nil, nil, nil, 0, true, 0), result.timer.ContinuousTime()) + result.dataTimestamp = timer.ContinuousTime() + return } func (self *Tree) Load() float64 { - return self.lock.Load() + return self.lock.Load() } func (self *Tree) deepEqual(o *Tree) bool { - return self.Describe() == o.Describe() + return self.Describe() == o.Describe() } func (self *Tree) conf() (result map[string]string, ts int64) { - result = make(map[string]string) - for k, v := range self.configuration { - result[k] = v - } - return result, self.configurationTimestamp + result = make(map[string]string) + for k, v := range self.configuration { + result[k] = v + } + return result, self.configurationTimestamp } // Configuration returns the current configuration and its timestamp. func (self *Tree) Configuration() (map[string]string, int64) { - self.lock.RLock() - defer self.lock.RUnlock() - return self.conf() + self.lock.RLock() + defer self.lock.RUnlock() + return self.conf() } func (self *Tree) mirrorClear(timestamp int64) { - if self.mirror != nil { - self.mirror.Clear(timestamp) - } + if self.mirror != nil { + self.mirror.Clear(timestamp) + } } func (self *Tree) mirrorPut(key, value []byte, timestamp int64) { - if self.mirror != nil { - escapedKey := escapeBytes(key) - newKey := make([]byte, len(escapedKey)+len(value)+1) - copy(newKey, value) - copy(newKey[len(value)+1:], escapedKey) - self.mirror.Put(newKey, key, timestamp) - } + if self.mirror != nil { + escapedKey := escapeBytes(key) + newKey := make([]byte, len(escapedKey)+len(value)+1) + copy(newKey, value) + copy(newKey[len(value)+1:], escapedKey) + self.mirror.Put(newKey, key, timestamp) + } } func (self *Tree) mirrorFakeDel(key, value []byte, timestamp int64) { - if self.mirror != nil { - escapedKey := escapeBytes(key) - newKey := make([]byte, len(escapedKey)+len(value)+1) - copy(newKey, value) - copy(newKey[len(value)+1:], escapedKey) - self.mirror.FakeDel(newKey, timestamp) - } + if self.mirror != nil { + escapedKey := escapeBytes(key) + newKey := make([]byte, len(escapedKey)+len(value)+1) + copy(newKey, value) + copy(newKey[len(value)+1:], escapedKey) + self.mirror.FakeDel(newKey, timestamp) + } } func (self *Tree) mirrorDel(key, value []byte) { - if self.mirror != nil { - escapedKey := escapeBytes(key) - newKey := make([]byte, len(escapedKey)+len(value)+1) - copy(newKey, value) - copy(newKey[len(value)+1:], escapedKey) - self.mirror.Del(newKey) - } + if self.mirror != nil { + escapedKey := escapeBytes(key) + newKey := make([]byte, len(escapedKey)+len(value)+1) + copy(newKey, value) + copy(newKey[len(value)+1:], escapedKey) + self.mirror.Del(newKey) + } } func (self *Tree) startMirroring() { - self.mirror = NewTreeTimer(self.timer) - self.root.each(nil, byteValue, func(key, byteValue []byte, treeValue *Tree, use int, timestamp int64) bool { - self.mirrorPut(key, byteValue, timestamp) - return true - }) + self.mirror = NewTreeTimer(self.timer) + self.root.each(nil, byteValue, func(key, byteValue []byte, treeValue *Tree, use int, timestamp int64) bool { + self.mirrorPut(key, byteValue, timestamp) + return true + }) } func (self *Tree) configure(conf map[string]string, ts int64) { - if conf[mirrored] == yes && self.configuration[mirrored] != yes { - self.startMirroring() - } else if conf[mirrored] != yes && self.configuration[mirrored] == yes { - self.mirror = nil - } - self.configuration = conf - self.configurationTimestamp = ts - self.log(persistence.Op{ - Configuration: conf, - Timestamp: ts, - }) + if conf[mirrored] == yes && self.configuration[mirrored] != yes { + self.startMirroring() + } else if conf[mirrored] != yes && self.configuration[mirrored] == yes { + self.mirror = nil + } + self.configuration = conf + self.configurationTimestamp = ts + self.log(persistence.Op{ + Configuration: conf, + Timestamp: ts, + }) } // Configure will set a new configuration and timestamp to this tree. // If the configuration has mirrored=yes this tree will start mirroring all its keys and values in a mirror Tree. func (self *Tree) Configure(conf map[string]string, ts int64) { - self.lock.Lock() - defer self.lock.Unlock() - self.configure(conf, ts) + self.lock.Lock() + defer self.lock.Unlock() + self.configure(conf, ts) } // AddConfiguration will set the key and value in the configuration of this tree, and set the provided timestamp as the // new configuration timestamp. func (self *Tree) AddConfiguration(ts int64, key, value string) bool { - self.lock.Lock() - defer self.lock.Unlock() - oldConf, _ := self.conf() - if oldConf[key] != value { - oldConf[key] = value - self.configure(oldConf, ts) - return true - } - return false + self.lock.Lock() + defer self.lock.Unlock() + oldConf, _ := self.conf() + if oldConf[key] != value { + oldConf[key] = value + self.configure(oldConf, ts) + return true + } + return false } // Log will make this Tree start logging using a new persistence.Logger. func (self *Tree) Log(dir string) *Tree { - self.logger = persistence.NewLogger(dir) - <-self.logger.Record() - return self + self.logger = persistence.NewLogger(dir) + <-self.logger.Record() + return self } // Restore will temporarily stop the Logger of this Tree, make it replay all operations // to allow us to restore the state logged in that directory, and then start recording again. func (self *Tree) Restore() *Tree { - self.logger.Stop() - self.logger.Play(func(op persistence.Op) { - if op.Configuration != nil { - if op.Key == nil { - self.Configure(op.Configuration, op.Timestamp) - } else { - self.SubConfigure(op.Key, op.Configuration, op.Timestamp) - } - } else if op.Put { - if op.SubKey == nil { - self.Put(op.Key, op.Value, op.Timestamp) - } else { - self.SubPut(op.Key, op.SubKey, op.Value, op.Timestamp) - } - } else { - if op.SubKey == nil { - if op.Clear { - if op.Timestamp > 0 { - self.SubClear(op.Key, op.Timestamp) - } else { - self.SubKill(op.Key) - } - } else { - self.Del(op.Key) - } - } else { - self.SubDel(op.Key, op.SubKey) - } - } - }) - <-self.logger.Record() - return self + self.logger.Stop() + self.logger.Play(func(op persistence.Op) { + if op.Configuration != nil { + if op.Key == nil { + self.Configure(op.Configuration, op.Timestamp) + } else { + self.SubConfigure(op.Key, op.Configuration, op.Timestamp) + } + } else if op.Put { + if op.SubKey == nil { + self.Put(op.Key, op.Value, op.Timestamp) + } else { + self.SubPut(op.Key, op.SubKey, op.Value, op.Timestamp) + } + } else { + if op.SubKey == nil { + if op.Clear { + if op.Timestamp > 0 { + self.SubClear(op.Key, op.Timestamp) + } else { + self.SubKill(op.Key) + } + } else { + self.Del(op.Key) + } + } else { + self.SubDel(op.Key, op.SubKey) + } + } + }) + <-self.logger.Record() + return self } func (self *Tree) log(op persistence.Op) { - if self.logger != nil && self.logger.Recording() { - self.logger.Dump(op) - } + if self.logger != nil && self.logger.Recording() { + self.logger.Dump(op) + } } func (self *Tree) newTreeWith(key []Nibble, byteValue []byte, timestamp int64) (result *Tree) { - result = NewTreeTimer(self.timer) - result.PutTimestamp(key, byteValue, true, 0, timestamp) - return + result = NewTreeTimer(self.timer) + result.PutTimestamp(key, byteValue, true, 0, timestamp) + return } // Each will iterate over the entire tree using f. func (self *Tree) Each(f TreeIterator) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - self.root.each(nil, byteValue, newNodeIterator(f)) + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + self.root.each(nil, byteValue, newNodeIterator(f)) } // ReverseEach will iterate over the entire tree in reverse order using f. func (self *Tree) ReverseEach(f TreeIterator) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - self.root.reverseEach(nil, byteValue, newNodeIterator(f)) + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + self.root.reverseEach(nil, byteValue, newNodeIterator(f)) } // MirrorEachBetween will iterate between min and max in the mirror Tree using f. func (self *Tree) MirrorEachBetween(min, max []byte, mininc, maxinc bool, f TreeIterator) { - if self == nil || self.mirror == nil { - return - } - if maxinc && max != nil { - maxinc = false - max = incrementBytes(max) - } - self.mirror.EachBetween(min, max, mininc, maxinc, newMirrorIterator(min, max, mininc, maxinc, f)) + if self == nil || self.mirror == nil { + return + } + if maxinc && max != nil { + maxinc = false + max = incrementBytes(max) + } + self.mirror.EachBetween(min, max, mininc, maxinc, newMirrorIterator(min, max, mininc, maxinc, f)) } // EachBetween will iterate between min and max using f. func (self *Tree) EachBetween(min, max []byte, mininc, maxinc bool, f TreeIterator) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - mincmp, maxcmp := cmps(mininc, maxinc) - self.root.eachBetween(nil, Rip(min), Rip(max), mincmp, maxcmp, byteValue, newNodeIterator(f)) + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + mincmp, maxcmp := cmps(mininc, maxinc) + self.root.eachBetween(nil, Rip(min), Rip(max), mincmp, maxcmp, byteValue, newNodeIterator(f)) } // MirrorReverseEachBetween will iterate between min and max in the mirror Tree, in reverse order, using f. func (self *Tree) MirrorReverseEachBetween(min, max []byte, mininc, maxinc bool, f TreeIterator) { - if self == nil || self.mirror == nil { - return - } - if maxinc && max != nil { - maxinc = false - max = incrementBytes(max) - } - self.mirror.ReverseEachBetween(min, max, mininc, maxinc, newMirrorIterator(min, max, mininc, maxinc, f)) + if self == nil || self.mirror == nil { + return + } + if maxinc && max != nil { + maxinc = false + max = incrementBytes(max) + } + self.mirror.ReverseEachBetween(min, max, mininc, maxinc, newMirrorIterator(min, max, mininc, maxinc, f)) } // ReverseEachBetween will iterate between min and max in reverse order using f. func (self *Tree) ReverseEachBetween(min, max []byte, mininc, maxinc bool, f TreeIterator) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - mincmp, maxcmp := cmps(mininc, maxinc) - self.root.reverseEachBetween(nil, Rip(min), Rip(max), mincmp, maxcmp, byteValue, newNodeIterator(f)) + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + mincmp, maxcmp := cmps(mininc, maxinc) + self.root.reverseEachBetween(nil, Rip(min), Rip(max), mincmp, maxcmp, byteValue, newNodeIterator(f)) } // MirrorIndexOf will return the index of (or the index it would have if it existed) key in the mirror Tree. func (self *Tree) MirrorIndexOf(key []byte) (index int, existed bool) { - if self == nil || self.mirror == nil { - return - } - var value []byte - self.MirrorEachBetween(key, nil, true, false, func(k, v []byte, ts int64) bool { - value, existed = v, bytes.Compare(key, k[:len(key)]) == 0 - return false - }) - newKey := key - if existed { - escapedValue := escapeBytes(value) - newKey = make([]byte, len(escapedValue)+len(key)+1) - copy(newKey, key) - copy(newKey[len(key)+1:], escapedValue) - } - index, _ = self.mirror.IndexOf(newKey) - return + if self == nil || self.mirror == nil { + return + } + var value []byte + self.MirrorEachBetween(key, nil, true, false, func(k, v []byte, ts int64) bool { + value, existed = v, bytes.Compare(key, k[:len(key)]) == 0 + return false + }) + newKey := key + if existed { + escapedValue := escapeBytes(value) + newKey = make([]byte, len(escapedValue)+len(key)+1) + copy(newKey, key) + copy(newKey[len(key)+1:], escapedValue) + } + index, _ = self.mirror.IndexOf(newKey) + return } // IndexOf will return the index of (or the index it would have if it existed) key. func (self *Tree) IndexOf(key []byte) (index int, existed bool) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - index, ex := self.root.indexOf(0, Rip(key), byteValue, true) - existed = ex&byteValue != 0 - return + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + index, ex := self.root.indexOf(0, Rip(key), byteValue, true) + existed = ex&byteValue != 0 + return } // MirrorReverseIndexOf will return the index from the end (or the index it would have if it existed) key in the mirror Tree. func (self *Tree) MirrorReverseIndexOf(key []byte) (index int, existed bool) { - if self == nil || self.mirror == nil { - return - } - var value []byte - self.MirrorEachBetween(key, nil, true, false, func(k, v []byte, ts int64) bool { - value, existed = v, bytes.Compare(key, k[:len(key)]) == 0 - return false - }) - newKey := key - if existed { - escapedValue := escapeBytes(value) - newKey = make([]byte, len(escapedValue)+len(key)+1) - copy(newKey, key) - copy(newKey[len(key)+1:], escapedValue) - } - index, _ = self.mirror.ReverseIndexOf(newKey) - return -} - -// MirrorReverseIndexOf will return the index from the end (or the index it would have if it existed) key. + if self == nil || self.mirror == nil { + return + } + var value []byte + self.MirrorEachBetween(key, nil, true, false, func(k, v []byte, ts int64) bool { + value, existed = v, bytes.Compare(key, k[:len(key)]) == 0 + return false + }) + newKey := key + if existed { + escapedValue := escapeBytes(value) + newKey = make([]byte, len(escapedValue)+len(key)+1) + copy(newKey, key) + copy(newKey[len(key)+1:], escapedValue) + } + index, _ = self.mirror.ReverseIndexOf(newKey) + return +} + +// ReverseIndexOf will return the index from the end (or the index it would have if it existed) key. func (self *Tree) ReverseIndexOf(key []byte) (index int, existed bool) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - index, ex := self.root.indexOf(0, Rip(key), byteValue, false) - existed = ex&byteValue != 0 - return + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + index, ex := self.root.indexOf(0, Rip(key), byteValue, false) + existed = ex&byteValue != 0 + return } // MirrorEachBetweenIndex will iterate between the min'th and the max'th entry in the mirror Tree using f. func (self *Tree) MirrorEachBetweenIndex(min, max *int, f TreeIndexIterator) { - if self == nil || self.mirror == nil { - return - } - self.mirror.EachBetweenIndex(min, max, newMirrorIndexIterator(f)) + if self == nil || self.mirror == nil { + return + } + self.mirror.EachBetweenIndex(min, max, newMirrorIndexIterator(f)) } // EachBetweenIndex will iterate between the min'th and the max'th entry using f. func (self *Tree) EachBetweenIndex(min, max *int, f TreeIndexIterator) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - self.root.eachBetweenIndex(nil, 0, min, max, byteValue, newNodeIndexIterator(f)) + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + self.root.eachBetweenIndex(nil, 0, min, max, byteValue, newNodeIndexIterator(f)) } // MirrorReverseEachBetweenIndex will iterate between the min'th and the max'th entry of the mirror Tree, in reverse order, using f. func (self *Tree) MirrorReverseEachBetweenIndex(min, max *int, f TreeIndexIterator) { - if self == nil || self.mirror == nil { - return - } - self.mirror.ReverseEachBetweenIndex(min, max, newMirrorIndexIterator(f)) + if self == nil || self.mirror == nil { + return + } + self.mirror.ReverseEachBetweenIndex(min, max, newMirrorIndexIterator(f)) } // ReverseEachBetweenIndex will iterate between the min'th and the max'th entry in reverse order using f. func (self *Tree) ReverseEachBetweenIndex(min, max *int, f TreeIndexIterator) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - self.root.reverseEachBetweenIndex(nil, 0, min, max, byteValue, newNodeIndexIterator(f)) + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + self.root.reverseEachBetweenIndex(nil, 0, min, max, byteValue, newNodeIndexIterator(f)) } func (self *Tree) DataTimestamp() int64 { - if self == nil { - return 0 - } - self.lock.RLock() - defer self.lock.RUnlock() - return self.dataTimestamp + if self == nil { + return 0 + } + self.lock.RLock() + defer self.lock.RUnlock() + return self.dataTimestamp } // Hash returns the merkle hash of this Tree. func (self *Tree) Hash() []byte { - if self == nil { - return nil - } - self.lock.RLock() - defer self.lock.RUnlock() - hash := murmur.NewString(fmt.Sprint(self.configuration)) - return hash.Sum(self.root.hash) + if self == nil { + return nil + } + self.lock.RLock() + defer self.lock.RUnlock() + hash := murmur.NewString(fmt.Sprint(self.configuration)) + hash.MustWrite(self.root.hash) + return hash.Get() } // ToMap will return a dubious map representation of this Tree, where each byte slice key is converted to a string. func (self *Tree) ToMap() (result map[string][]byte) { - if self == nil { - return - } - result = make(map[string][]byte) - self.Each(func(key []byte, value []byte, timestamp int64) bool { - result[hex.EncodeToString(key)] = value - return true - }) - return + if self == nil { + return + } + result = make(map[string][]byte) + self.Each(func(key []byte, value []byte, timestamp int64) bool { + result[hex.EncodeToString(key)] = value + return true + }) + return } // String returns a humanly readable string representation of this Tree. func (self *Tree) String() string { - if self == nil { - return "" - } - return fmt.Sprint(self.ToMap()) + if self == nil { + return "" + } + return fmt.Sprint(self.ToMap()) } func (self *Tree) sizeBetween(min, max []byte, mininc, maxinc bool, use int) int { - if self == nil { - return 0 - } - self.lock.RLock() - defer self.lock.RUnlock() - mincmp, maxcmp := cmps(mininc, maxinc) - return self.root.sizeBetween(nil, Rip(min), Rip(max), mincmp, maxcmp, use) + if self == nil { + return 0 + } + self.lock.RLock() + defer self.lock.RUnlock() + mincmp, maxcmp := cmps(mininc, maxinc) + return self.root.sizeBetween(nil, Rip(min), Rip(max), mincmp, maxcmp, use) } // RealSizeBetween returns the real, as in 'including tombstones and sub trees', size of this Tree between min anx max. func (self *Tree) RealSizeBetween(min, max []byte, mininc, maxinc bool) int { - return self.sizeBetween(min, max, mininc, maxinc, 0) + return self.sizeBetween(min, max, mininc, maxinc, 0) } // MirrorSizeBetween returns the virtual, as in 'not including tombstones and sub trees', size of the mirror Tree between min and max. func (self *Tree) MirrorSizeBetween(min, max []byte, mininc, maxinc bool) (i int) { - if self == nil || self.mirror == nil { - return - } - if !mininc && min != nil { - mininc = true - min = incrementBytes(min) - } - if maxinc && max != nil { - maxinc = false - max = incrementBytes(max) - } - return self.mirror.SizeBetween(min, max, mininc, maxinc) + if self == nil || self.mirror == nil { + return + } + if !mininc && min != nil { + mininc = true + min = incrementBytes(min) + } + if maxinc && max != nil { + maxinc = false + max = incrementBytes(max) + } + return self.mirror.SizeBetween(min, max, mininc, maxinc) } // SizeBetween returns the virtual, as in 'not including tombstones and sub trees', size of this Tree between min and max. func (self *Tree) SizeBetween(min, max []byte, mininc, maxinc bool) int { - return self.sizeBetween(min, max, mininc, maxinc, byteValue|treeValue) + return self.sizeBetween(min, max, mininc, maxinc, byteValue|treeValue) } // RealSize returns the real, as in 'including tombstones and sub trees', size of this Tree. func (self *Tree) RealSize() int { - if self == nil { - return 0 - } - self.lock.RLock() - defer self.lock.RUnlock() - return self.root.realSize + if self == nil { + return 0 + } + self.lock.RLock() + defer self.lock.RUnlock() + return self.root.realSize } // Size returns the virtual, as in 'not including tombstones and sub trees', size of this Tree. func (self *Tree) Size() int { - if self == nil { - return 0 - } - self.lock.RLock() - defer self.lock.RUnlock() - return self.root.byteSize + self.root.treeSize + if self == nil { + return 0 + } + self.lock.RLock() + defer self.lock.RUnlock() + return self.root.byteSize + self.root.treeSize } func (self *Tree) describeIndented(first, indent int) string { - if self == nil { - return "" - } - indentation := &bytes.Buffer{} - for i := 0; i < first; i++ { - fmt.Fprint(indentation, " ") - } - buffer := bytes.NewBufferString(fmt.Sprintf("%v\n", indentation, self.Size(), hex.EncodeToString(self.Hash()))) - self.root.describe(indent+2, buffer) - if self.mirror != nil { - for i := 0; i < indent+first; i++ { - fmt.Fprint(buffer, " ") - } - fmt.Fprint(buffer, "\n") - self.mirror.root.describe(indent+2, buffer) - } - return string(buffer.Bytes()) + if self == nil { + return "" + } + indentation := &bytes.Buffer{} + for i := 0; i < first; i++ { + fmt.Fprint(indentation, " ") + } + buffer := bytes.NewBufferString(fmt.Sprintf("%v\n", indentation, self.Size(), hex.EncodeToString(self.Hash()))) + self.root.describe(indent+2, buffer) + if self.mirror != nil { + for i := 0; i < indent+first; i++ { + fmt.Fprint(buffer, " ") + } + fmt.Fprint(buffer, "\n") + self.mirror.root.describe(indent+2, buffer) + } + return string(buffer.Bytes()) } // Describe will return a complete and humanly readable (albeit slightly convoluted) description of this Tree. func (self *Tree) Describe() string { - if self == nil { - return "" - } - self.lock.RLock() - defer self.lock.RUnlock() - return self.describeIndented(0, 0) + if self == nil { + return "" + } + self.lock.RLock() + defer self.lock.RUnlock() + return self.describeIndented(0, 0) } // FakeDel will insert a tombstone at key with timestamp in this Tree. func (self *Tree) FakeDel(key []byte, timestamp int64) (oldBytes []byte, oldTree *Tree, existed bool) { - self.lock.Lock() - defer self.lock.Unlock() - var ex int - self.root, oldBytes, oldTree, _, ex = self.root.fakeDel(nil, Rip(key), byteValue, timestamp, self.timer.ContinuousTime()) - existed = ex&byteValue != 0 - if existed { - self.mirrorFakeDel(key, oldBytes, timestamp) - self.log(persistence.Op{ - Key: key, - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + var ex int + self.root, oldBytes, oldTree, _, ex = self.root.fakeDel(nil, Rip(key), byteValue, timestamp, self.timer.ContinuousTime()) + existed = ex&byteValue != 0 + if existed { + self.mirrorFakeDel(key, oldBytes, timestamp) + self.log(persistence.Op{ + Key: key, + }) + } + return } func (self *Tree) put(key []Nibble, byteValue []byte, treeValue *Tree, use int, timestamp int64) (oldBytes []byte, oldTree *Tree, existed int) { - self.dataTimestamp = timestamp - self.root, oldBytes, oldTree, _, existed = self.root.insert(nil, newNode(key, byteValue, treeValue, timestamp, false, use), self.timer.ContinuousTime()) - return + self.dataTimestamp = timestamp + self.root, oldBytes, oldTree, _, existed = self.root.insert(nil, newNode(key, byteValue, treeValue, timestamp, false, use), self.timer.ContinuousTime()) + return } // Put will put key and value with timestamp in this Tree. func (self *Tree) Put(key []byte, bValue []byte, timestamp int64) (oldBytes []byte, existed bool) { - self.lock.Lock() - defer self.lock.Unlock() - oldBytes, _, ex := self.put(Rip(key), bValue, nil, byteValue, timestamp) - existed = ex*byteValue != 0 - if existed { - self.mirrorDel(key, oldBytes) - } - self.mirrorPut(key, bValue, timestamp) - self.log(persistence.Op{ - Key: key, - Value: bValue, - Timestamp: timestamp, - Put: true, - }) - return + self.lock.Lock() + defer self.lock.Unlock() + oldBytes, _, ex := self.put(Rip(key), bValue, nil, byteValue, timestamp) + existed = ex*byteValue != 0 + if existed { + self.mirrorDel(key, oldBytes) + } + self.mirrorPut(key, bValue, timestamp) + self.log(persistence.Op{ + Key: key, + Value: bValue, + Timestamp: timestamp, + Put: true, + }) + return } // Get will return the value and timestamp at key. func (self *Tree) Get(key []byte) (bValue []byte, timestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - bValue, _, timestamp, ex := self.root.get(Rip(key)) - existed = ex&byteValue != 0 - return + self.lock.RLock() + defer self.lock.RUnlock() + bValue, _, timestamp, ex := self.root.get(Rip(key)) + existed = ex&byteValue != 0 + return } // PrevMarker returns the previous key of tombstone or real value before key. func (self *Tree) PrevMarker(key []byte) (prevKey []byte, existed bool) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - self.root.reverseEachBetween(nil, nil, Rip(key), 0, 0, 0, func(k, b []byte, t *Tree, u int, v int64) bool { - prevKey, existed = k, true - return false - }) - return + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + self.root.reverseEachBetween(nil, nil, Rip(key), 0, 0, 0, func(k, b []byte, t *Tree, u int, v int64) bool { + prevKey, existed = k, true + return false + }) + return } // NextMarker returns the next key of tombstone or real value after key. func (self *Tree) NextMarker(key []byte) (nextKey []byte, existed bool) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - self.root.eachBetween(nil, Rip(key), nil, 0, 0, 0, func(k, b []byte, t *Tree, u int, v int64) bool { - nextKey, existed = k, true - return false - }) - return + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + self.root.eachBetween(nil, Rip(key), nil, 0, 0, 0, func(k, b []byte, t *Tree, u int, v int64) bool { + nextKey, existed = k, true + return false + }) + return } // MirrorPrev returns the previous key, value and timestamp before key in the mirror Tree. func (self *Tree) MirrorPrev(key []byte) (prevKey, prevValue []byte, prevTimestamp int64, existed bool) { - if self == nil || self.mirror == nil { - return - } - prevKey, prevValue, prevTimestamp, existed = self.mirror.Prev(key) - prevKey = prevKey[:len(prevKey)-len(escapeBytes(prevValue))-1] - return + if self == nil || self.mirror == nil { + return + } + prevKey, prevValue, prevTimestamp, existed = self.mirror.Prev(key) + prevKey = prevKey[:len(prevKey)-len(escapeBytes(prevValue))-1] + return } // MirrorNext returns the next key, value and timestamp after key in the mirror Tree. func (self *Tree) MirrorNext(key []byte) (nextKey, nextValue []byte, nextTimestamp int64, existed bool) { - if self == nil || self.mirror == nil { - return - } - nextKey, nextValue, nextTimestamp, existed = self.mirror.Next(key) - nextKey = nextKey[:len(nextKey)-len(escapeBytes(nextValue))-1] - return + if self == nil || self.mirror == nil { + return + } + nextKey, nextValue, nextTimestamp, existed = self.mirror.Next(key) + nextKey = nextKey[:len(nextKey)-len(escapeBytes(nextValue))-1] + return } // Prev will return the previous key, value and timestamp before key in this Tree. func (self *Tree) Prev(key []byte) (prevKey, prevValue []byte, prevTimestamp int64, existed bool) { - self.ReverseEachBetween(nil, key, false, false, func(k, v []byte, timestamp int64) bool { - prevKey, prevValue, prevTimestamp, existed = k, v, timestamp, true - return false - }) - return + self.ReverseEachBetween(nil, key, false, false, func(k, v []byte, timestamp int64) bool { + prevKey, prevValue, prevTimestamp, existed = k, v, timestamp, true + return false + }) + return } // Next will return the next key, value and timestamp after key in this Tree. func (self *Tree) Next(key []byte) (nextKey, nextValue []byte, nextTimestamp int64, existed bool) { - self.EachBetween(key, nil, false, false, func(k, v []byte, timestamp int64) bool { - nextKey, nextValue, nextTimestamp, existed = k, v, timestamp, true - return false - }) - return + self.EachBetween(key, nil, false, false, func(k, v []byte, timestamp int64) bool { + nextKey, nextValue, nextTimestamp, existed = k, v, timestamp, true + return false + }) + return } // NextMarkerIndex will return the next key of tombstone or real value after the given index in this Tree. func (self *Tree) NextMarkerIndex(index int) (key []byte, existed bool) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - self.root.eachBetweenIndex(nil, 0, &index, nil, 0, func(k, b []byte, t *Tree, u int, v int64, i int) bool { - key, existed = k, true - return false - }) - return + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + self.root.eachBetweenIndex(nil, 0, &index, nil, 0, func(k, b []byte, t *Tree, u int, v int64, i int) bool { + key, existed = k, true + return false + }) + return } // PrevMarkerIndex will return the previous key of tombstone or real value before the given index in this Tree. func (self *Tree) PrevMarkerIndex(index int) (key []byte, existed bool) { - if self == nil { - return - } - self.lock.RLock() - defer self.lock.RUnlock() - self.root.reverseEachBetweenIndex(nil, 0, nil, &index, 0, func(k, b []byte, t *Tree, u int, v int64, i int) bool { - key, existed = k, true - return false - }) - return + if self == nil { + return + } + self.lock.RLock() + defer self.lock.RUnlock() + self.root.reverseEachBetweenIndex(nil, 0, nil, &index, 0, func(k, b []byte, t *Tree, u int, v int64, i int) bool { + key, existed = k, true + return false + }) + return } // MirrorNextIndex will return the next key, value, timestamp and index after index in the mirror Tree. func (self *Tree) MirrorNextIndex(index int) (key, value []byte, timestamp int64, ind int, existed bool) { - if self == nil || self.mirror == nil { - return - } - key, value, timestamp, ind, existed = self.mirror.NextIndex(index) - if existed { - key = key[:len(key)-len(escapeBytes(value))-1] - } - return + if self == nil || self.mirror == nil { + return + } + key, value, timestamp, ind, existed = self.mirror.NextIndex(index) + if existed { + key = key[:len(key)-len(escapeBytes(value))-1] + } + return } // MirrorPrevIndex will return the previous key, value, timestamp and index before index in the mirror Tree. func (self *Tree) MirrorPrevIndex(index int) (key, value []byte, timestamp int64, ind int, existed bool) { - if self == nil || self.mirror == nil { - return - } - key, value, timestamp, ind, existed = self.mirror.PrevIndex(index) - if existed { - key = key[:len(key)-len(escapeBytes(value))-1] - } - return + if self == nil || self.mirror == nil { + return + } + key, value, timestamp, ind, existed = self.mirror.PrevIndex(index) + if existed { + key = key[:len(key)-len(escapeBytes(value))-1] + } + return } // NextIndex will return the next key, value, timestamp and index after index in this Tree. func (self *Tree) NextIndex(index int) (key, value []byte, timestamp int64, ind int, existed bool) { - n := index + 1 - self.EachBetweenIndex(&n, &n, func(k, v []byte, t int64, i int) bool { - key, value, timestamp, ind, existed = k, v, t, i, true - return false - }) - return + n := index + 1 + self.EachBetweenIndex(&n, &n, func(k, v []byte, t int64, i int) bool { + key, value, timestamp, ind, existed = k, v, t, i, true + return false + }) + return } // PrevIndex will return the previous key, value, timestamp and index before index in this Tree. func (self *Tree) PrevIndex(index int) (key, value []byte, timestamp int64, ind int, existed bool) { - p := index - 1 - self.EachBetweenIndex(&p, &p, func(k, v []byte, t int64, i int) bool { - key, value, timestamp, ind, existed = k, v, t, i, true - return false - }) - return + p := index - 1 + self.EachBetweenIndex(&p, &p, func(k, v []byte, t int64, i int) bool { + key, value, timestamp, ind, existed = k, v, t, i, true + return false + }) + return } // MirrorFirst will return the first key, value and timestamp of the mirror Tree. func (self *Tree) MirrorFirst() (key, byteValue []byte, timestamp int64, existed bool) { - if self == nil || self.mirror == nil { - return - } - key, byteValue, timestamp, existed = self.mirror.First() - key = key[:len(key)-len(escapeBytes(byteValue))-1] - return + if self == nil || self.mirror == nil { + return + } + key, byteValue, timestamp, existed = self.mirror.First() + key = key[:len(key)-len(escapeBytes(byteValue))-1] + return } // MirrorLast will return the last key, value and timestamp of the mirror Tree. func (self *Tree) MirrorLast() (key, byteValue []byte, timestamp int64, existed bool) { - if self == nil || self.mirror == nil { - return - } - key, byteValue, timestamp, existed = self.mirror.Last() - key = key[:len(key)-len(escapeBytes(byteValue))-1] - return + if self == nil || self.mirror == nil { + return + } + key, byteValue, timestamp, existed = self.mirror.Last() + key = key[:len(key)-len(escapeBytes(byteValue))-1] + return } // First returns the first key, value and timestamp in this Tree. func (self *Tree) First() (key, byteValue []byte, timestamp int64, existed bool) { - self.Each(func(k []byte, b []byte, ver int64) bool { - key, byteValue, timestamp, existed = k, b, ver, true - return false - }) - return + self.Each(func(k []byte, b []byte, ver int64) bool { + key, byteValue, timestamp, existed = k, b, ver, true + return false + }) + return } // Last returns the last key, value and timestamp in this Tree. func (self *Tree) Last() (key, byteValue []byte, timestamp int64, existed bool) { - self.ReverseEach(func(k []byte, b []byte, ver int64) bool { - key, byteValue, timestamp, existed = k, b, ver, true - return false - }) - return + self.ReverseEach(func(k []byte, b []byte, ver int64) bool { + key, byteValue, timestamp, existed = k, b, ver, true + return false + }) + return } // MirrorIndex returns the key, value and timestamp at index in the mirror Tree. func (self *Tree) MirrorIndex(n int) (key, byteValue []byte, timestamp int64, existed bool) { - if self == nil || self.mirror == nil { - return - } - key, byteValue, timestamp, existed = self.mirror.Index(n) - key = key[:len(key)-len(escapeBytes(byteValue))-1] - return + if self == nil || self.mirror == nil { + return + } + key, byteValue, timestamp, existed = self.mirror.Index(n) + key = key[:len(key)-len(escapeBytes(byteValue))-1] + return } // MirrorReverseIndex returns the key, value and timestamp at index from the end in the mirror Tree. func (self *Tree) MirrorReverseIndex(n int) (key, byteValue []byte, timestamp int64, existed bool) { - if self == nil || self.mirror == nil { - return - } - key, byteValue, timestamp, existed = self.mirror.Index(n) - key = key[:len(key)-len(escapeBytes(byteValue))-1] - return + if self == nil || self.mirror == nil { + return + } + key, byteValue, timestamp, existed = self.mirror.Index(n) + key = key[:len(key)-len(escapeBytes(byteValue))-1] + return } // Index returns the key, value and timestamp at index in this Tree. func (self *Tree) Index(n int) (key []byte, byteValue []byte, timestamp int64, existed bool) { - self.EachBetweenIndex(&n, &n, func(k []byte, b []byte, ver int64, index int) bool { - key, byteValue, timestamp, existed = k, b, ver, true - return false - }) - return + self.EachBetweenIndex(&n, &n, func(k []byte, b []byte, ver int64, index int) bool { + key, byteValue, timestamp, existed = k, b, ver, true + return false + }) + return } // ReverseIndex returns the key, value and timestamp at index from the end in this Tree. func (self *Tree) ReverseIndex(n int) (key []byte, byteValue []byte, timestamp int64, existed bool) { - self.ReverseEachBetweenIndex(&n, &n, func(k []byte, b []byte, ver int64, index int) bool { - key, byteValue, timestamp, existed = k, b, ver, true - return false - }) - return + self.ReverseEachBetweenIndex(&n, &n, func(k []byte, b []byte, ver int64, index int) bool { + key, byteValue, timestamp, existed = k, b, ver, true + return false + }) + return } -// Clear will remove all content of this Tree (including tombstones and sub trees) and any mirror Tree and replace the all with one giant tombstone, and clear any persistence.Logger assigned to this Tree. +// Clear will remove all content of this Tree (including tombstones and sub trees) and any mirror Tree, replace them all with one giant tombstone, +// and clear any persistence.Logger assigned to this Tree. func (self *Tree) Clear(timestamp int64) { - self.lock.Lock() - defer self.lock.Unlock() - self.dataTimestamp, self.root = timestamp, nil - self.root, _, _, _, _ = self.root.insert(nil, newNode(nil, nil, nil, 0, true, 0), self.timer.ContinuousTime()) - self.mirrorClear(timestamp) - if self.logger != nil { - self.logger.Clear() - } + self.lock.Lock() + defer self.lock.Unlock() + self.dataTimestamp, self.root = timestamp, nil + self.root, _, _, _, _ = self.root.insert(nil, newNode(nil, nil, nil, 0, true, 0), self.timer.ContinuousTime()) + self.mirrorClear(timestamp) + if self.logger != nil { + self.logger.Clear() + } } func (self *Tree) del(key []Nibble, use int) (oldBytes []byte, existed bool) { - var ex int - self.root, oldBytes, _, _, ex = self.root.del(nil, key, use, self.timer.ContinuousTime()) - existed = ex&byteValue != 0 - return + var ex int + self.root, oldBytes, _, _, ex = self.root.del(nil, key, use, self.timer.ContinuousTime()) + existed = ex&byteValue != 0 + return } // Del will remove key from this Tree without keeping a tombstone. func (self *Tree) Del(key []byte) (oldBytes []byte, existed bool) { - self.lock.Lock() - defer self.lock.Unlock() - oldBytes, existed = self.del(Rip(key), byteValue) - if existed { - self.mirrorDel(key, oldBytes) - self.log(persistence.Op{ - Key: key, - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + oldBytes, existed = self.del(Rip(key), byteValue) + if existed { + self.mirrorDel(key, oldBytes) + self.log(persistence.Op{ + Key: key, + }) + } + return } func (self *Tree) SubMirrorReverseIndexOf(key, subKey []byte) (index int, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - index, existed = subTree.MirrorReverseIndexOf(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + index, existed = subTree.MirrorReverseIndexOf(subKey) + } + return } func (self *Tree) SubMirrorIndexOf(key, subKey []byte) (index int, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - index, existed = subTree.MirrorIndexOf(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + index, existed = subTree.MirrorIndexOf(subKey) + } + return } func (self *Tree) SubReverseIndexOf(key, subKey []byte) (index int, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - index, existed = subTree.ReverseIndexOf(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + index, existed = subTree.ReverseIndexOf(subKey) + } + return } func (self *Tree) SubIndexOf(key, subKey []byte) (index int, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - index, existed = subTree.IndexOf(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + index, existed = subTree.IndexOf(subKey) + } + return } func (self *Tree) SubMirrorPrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundTimestamp int64, foundIndex int, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - foundKey, foundValue, foundTimestamp, foundIndex, existed = subTree.MirrorPrevIndex(index) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + foundKey, foundValue, foundTimestamp, foundIndex, existed = subTree.MirrorPrevIndex(index) + } + return } func (self *Tree) SubMirrorNextIndex(key []byte, index int) (foundKey, foundValue []byte, foundTimestamp int64, foundIndex int, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - foundKey, foundValue, foundTimestamp, foundIndex, existed = subTree.MirrorNextIndex(index) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + foundKey, foundValue, foundTimestamp, foundIndex, existed = subTree.MirrorNextIndex(index) + } + return } func (self *Tree) SubPrevIndex(key []byte, index int) (foundKey, foundValue []byte, foundTimestamp int64, foundIndex int, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - foundKey, foundValue, foundTimestamp, foundIndex, existed = subTree.PrevIndex(index) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + foundKey, foundValue, foundTimestamp, foundIndex, existed = subTree.PrevIndex(index) + } + return } func (self *Tree) SubNextIndex(key []byte, index int) (foundKey, foundValue []byte, foundTimestamp int64, foundIndex int, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - foundKey, foundValue, foundTimestamp, foundIndex, existed = subTree.NextIndex(index) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + foundKey, foundValue, foundTimestamp, foundIndex, existed = subTree.NextIndex(index) + } + return } func (self *Tree) SubMirrorFirst(key []byte) (firstKey []byte, firstBytes []byte, firstTimestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - firstKey, firstBytes, firstTimestamp, existed = subTree.MirrorFirst() - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + firstKey, firstBytes, firstTimestamp, existed = subTree.MirrorFirst() + } + return } func (self *Tree) SubMirrorLast(key []byte) (lastKey []byte, lastBytes []byte, lastTimestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - lastKey, lastBytes, lastTimestamp, existed = subTree.MirrorLast() - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + lastKey, lastBytes, lastTimestamp, existed = subTree.MirrorLast() + } + return } func (self *Tree) SubFirst(key []byte) (firstKey []byte, firstBytes []byte, firstTimestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - firstKey, firstBytes, firstTimestamp, existed = subTree.First() - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + firstKey, firstBytes, firstTimestamp, existed = subTree.First() + } + return } func (self *Tree) SubLast(key []byte) (lastKey []byte, lastBytes []byte, lastTimestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - lastKey, lastBytes, lastTimestamp, existed = subTree.Last() - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + lastKey, lastBytes, lastTimestamp, existed = subTree.Last() + } + return } func (self *Tree) SubMirrorPrev(key, subKey []byte) (prevKey, prevValue []byte, prevTimestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - prevKey, prevValue, prevTimestamp, existed = subTree.MirrorPrev(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + prevKey, prevValue, prevTimestamp, existed = subTree.MirrorPrev(subKey) + } + return } func (self *Tree) SubMirrorNext(key, subKey []byte) (nextKey, nextValue []byte, nextTimestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - nextKey, nextValue, nextTimestamp, existed = subTree.MirrorNext(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + nextKey, nextValue, nextTimestamp, existed = subTree.MirrorNext(subKey) + } + return } func (self *Tree) SubPrev(key, subKey []byte) (prevKey, prevValue []byte, prevTimestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - prevKey, prevValue, prevTimestamp, existed = subTree.Prev(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + prevKey, prevValue, prevTimestamp, existed = subTree.Prev(subKey) + } + return } func (self *Tree) SubNext(key, subKey []byte) (nextKey, nextValue []byte, nextTimestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - nextKey, nextValue, nextTimestamp, existed = subTree.Next(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + nextKey, nextValue, nextTimestamp, existed = subTree.Next(subKey) + } + return } func (self *Tree) SubSize(key []byte) (result int) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - result = subTree.Size() - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + result = subTree.Size() + } + return } func (self *Tree) SubMirrorSizeBetween(key, min, max []byte, mininc, maxinc bool) (result int) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - result = subTree.MirrorSizeBetween(min, max, mininc, maxinc) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + result = subTree.MirrorSizeBetween(min, max, mininc, maxinc) + } + return } func (self *Tree) SubSizeBetween(key, min, max []byte, mininc, maxinc bool) (result int) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - result = subTree.SizeBetween(min, max, mininc, maxinc) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + result = subTree.SizeBetween(min, max, mininc, maxinc) + } + return } func (self *Tree) SubGet(key, subKey []byte) (byteValue []byte, timestamp int64, existed bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - byteValue, timestamp, existed = subTree.Get(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + byteValue, timestamp, existed = subTree.Get(subKey) + } + return } func (self *Tree) SubMirrorReverseEachBetween(key, min, max []byte, mininc, maxinc bool, f TreeIterator) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - subTree.MirrorReverseEachBetween(min, max, mininc, maxinc, f) - } + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + subTree.MirrorReverseEachBetween(min, max, mininc, maxinc, f) + } } func (self *Tree) SubMirrorEachBetween(key, min, max []byte, mininc, maxinc bool, f TreeIterator) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - subTree.MirrorEachBetween(min, max, mininc, maxinc, f) - } + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + subTree.MirrorEachBetween(min, max, mininc, maxinc, f) + } } func (self *Tree) SubMirrorReverseEachBetweenIndex(key []byte, min, max *int, f TreeIndexIterator) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - subTree.MirrorReverseEachBetweenIndex(min, max, f) - } + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + subTree.MirrorReverseEachBetweenIndex(min, max, f) + } } func (self *Tree) SubMirrorEachBetweenIndex(key []byte, min, max *int, f TreeIndexIterator) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - subTree.MirrorEachBetweenIndex(min, max, f) - } + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + subTree.MirrorEachBetweenIndex(min, max, f) + } } func (self *Tree) SubReverseEachBetween(key, min, max []byte, mininc, maxinc bool, f TreeIterator) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - subTree.ReverseEachBetween(min, max, mininc, maxinc, f) - } + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + subTree.ReverseEachBetween(min, max, mininc, maxinc, f) + } } func (self *Tree) SubEachBetween(key, min, max []byte, mininc, maxinc bool, f TreeIterator) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - subTree.EachBetween(min, max, mininc, maxinc, f) - } + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + subTree.EachBetween(min, max, mininc, maxinc, f) + } } func (self *Tree) SubReverseEachBetweenIndex(key []byte, min, max *int, f TreeIndexIterator) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - subTree.ReverseEachBetweenIndex(min, max, f) - } + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + subTree.ReverseEachBetweenIndex(min, max, f) + } } func (self *Tree) SubEachBetweenIndex(key []byte, min, max *int, f TreeIndexIterator) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - subTree.EachBetweenIndex(min, max, f) - } + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + subTree.EachBetweenIndex(min, max, f) + } } func (self *Tree) SubPut(key, subKey []byte, byteValue []byte, timestamp int64) (oldBytes []byte, existed bool) { - self.lock.Lock() - defer self.lock.Unlock() - ripped := Rip(key) - _, subTree, subTreeTimestamp, ex := self.root.get(ripped) - if ex&treeValue == 0 || subTree == nil { - subTree = self.newTreeWith(Rip(subKey), byteValue, timestamp) - } else { - oldBytes, existed = subTree.Put(subKey, byteValue, timestamp) - } - self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) - self.log(persistence.Op{ - Key: key, - SubKey: subKey, - Value: byteValue, - Timestamp: timestamp, - Put: true, - }) - return + self.lock.Lock() + defer self.lock.Unlock() + ripped := Rip(key) + _, subTree, subTreeTimestamp, ex := self.root.get(ripped) + if ex&treeValue == 0 || subTree == nil { + subTree = self.newTreeWith(Rip(subKey), byteValue, timestamp) + } else { + oldBytes, existed = subTree.Put(subKey, byteValue, timestamp) + } + self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) + self.log(persistence.Op{ + Key: key, + SubKey: subKey, + Value: byteValue, + Timestamp: timestamp, + Put: true, + }) + return } func (self *Tree) SubDel(key, subKey []byte) (oldBytes []byte, existed bool) { - self.lock.Lock() - defer self.lock.Unlock() - ripped := Rip(key) - if _, subTree, subTreeTimestamp, ex := self.root.get(ripped); ex&treeValue != 0 && subTree != nil { - oldBytes, existed = subTree.Del(subKey) - if subTree.RealSize() == 0 { - self.del(ripped, treeValue) - } else { - self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) - } - } - if existed { - self.log(persistence.Op{ - Key: key, - SubKey: subKey, - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + ripped := Rip(key) + if _, subTree, subTreeTimestamp, ex := self.root.get(ripped); ex&treeValue != 0 && subTree != nil { + oldBytes, existed = subTree.Del(subKey) + if subTree.RealSize() == 0 { + self.del(ripped, treeValue) + } else { + self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) + } + } + if existed { + self.log(persistence.Op{ + Key: key, + SubKey: subKey, + }) + } + return } func (self *Tree) SubFakeDel(key, subKey []byte, timestamp int64) (oldBytes []byte, existed bool) { - self.lock.Lock() - defer self.lock.Unlock() - ripped := Rip(key) - if _, subTree, subTreeTimestamp, ex := self.root.get(ripped); ex&treeValue != 0 && subTree != nil { - oldBytes, _, existed = subTree.FakeDel(subKey, timestamp) - self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) - } - if existed { - self.log(persistence.Op{ - Key: key, - SubKey: subKey, - }) - } - return -} + self.lock.Lock() + defer self.lock.Unlock() + ripped := Rip(key) + if _, subTree, subTreeTimestamp, ex := self.root.get(ripped); ex&treeValue != 0 && subTree != nil { + oldBytes, _, existed = subTree.FakeDel(subKey, timestamp) + self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) + } + if existed { + self.log(persistence.Op{ + Key: key, + SubKey: subKey, + }) + } + return +} + +// SubClear does Clear on the sub tree. func (self *Tree) SubClear(key []byte, timestamp int64) (deleted int) { - self.lock.Lock() - defer self.lock.Unlock() - ripped := Rip(key) - if _, subTree, subTreeTimestamp, ex := self.root.get(ripped); ex&treeValue != 0 && subTree != nil { - deleted = subTree.Size() - subTree.Clear(timestamp) - self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) - } - if deleted > 0 { - self.log(persistence.Op{ - Key: key, - Clear: true, - Timestamp: timestamp, - }) - } - return -} + self.lock.Lock() + defer self.lock.Unlock() + ripped := Rip(key) + if _, subTree, subTreeTimestamp, ex := self.root.get(ripped); ex&treeValue != 0 && subTree != nil { + deleted = subTree.Size() + subTree.Clear(timestamp) + self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) + } + if deleted > 0 { + self.log(persistence.Op{ + Key: key, + Clear: true, + Timestamp: timestamp, + }) + } + return +} + +// SubKill will completely remove the sub tree. func (self *Tree) SubKill(key []byte) (deleted int) { - self.lock.Lock() - defer self.lock.Unlock() - ripped := Rip(key) - if _, subTree, _, ex := self.root.get(ripped); ex&treeValue != 0 && subTree != nil { - deleted = subTree.Size() - self.del(ripped, treeValue) - } - if deleted > 0 { - self.log(persistence.Op{ - Key: key, - Clear: true, - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + ripped := Rip(key) + if _, subTree, _, ex := self.root.get(ripped); ex&treeValue != 0 && subTree != nil { + deleted = subTree.Size() + self.del(ripped, treeValue) + } + if deleted > 0 { + self.log(persistence.Op{ + Key: key, + Clear: true, + }) + } + return } func (self *Tree) Finger(key []Nibble) *Print { - self.lock.RLock() - defer self.lock.RUnlock() - return self.root.finger(&Print{}, key) + self.lock.RLock() + defer self.lock.RUnlock() + return self.root.finger(&Print{}, key) } func (self *Tree) GetTimestamp(key []Nibble) (bValue []byte, timestamp int64, present bool) { - self.lock.RLock() - defer self.lock.RUnlock() - bValue, _, timestamp, ex := self.root.get(key) - present = ex&byteValue != 0 - return + self.lock.RLock() + defer self.lock.RUnlock() + bValue, _, timestamp, ex := self.root.get(key) + present = ex&byteValue != 0 + return } func (self *Tree) putTimestamp(key []Nibble, bValue []byte, treeValue *Tree, nodeUse, insertUse int, expected, timestamp int64) (result bool, oldBytes []byte) { - if _, _, current, _ := self.root.get(key); current == expected { - self.dataTimestamp, result = timestamp, true - self.root, oldBytes, _, _, _ = self.root.insertHelp(nil, newNode(key, bValue, treeValue, timestamp, false, nodeUse), insertUse, self.timer.ContinuousTime()) - } - return + if _, _, current, _ := self.root.get(key); current == expected { + self.dataTimestamp, result = timestamp, true + self.root, oldBytes, _, _, _ = self.root.insertHelp(nil, newNode(key, bValue, treeValue, timestamp, false, nodeUse), insertUse, self.timer.ContinuousTime()) + } + return } func (self *Tree) PutTimestamp(key []Nibble, bValue []byte, present bool, expected, timestamp int64) (result bool) { - self.lock.Lock() - defer self.lock.Unlock() - nodeUse := 0 - if present { - nodeUse = byteValue - } - var oldBytes []byte - result, oldBytes = self.putTimestamp(key, bValue, nil, nodeUse, byteValue, expected, timestamp) - if result { - stitched := Stitch(key) - self.mirrorDel(stitched, oldBytes) - self.mirrorPut(stitched, bValue, timestamp) - self.log(persistence.Op{ - Key: Stitch(key), - Value: bValue, - Timestamp: timestamp, - Put: true, - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + nodeUse := 0 + if present { + nodeUse = byteValue + } + var oldBytes []byte + result, oldBytes = self.putTimestamp(key, bValue, nil, nodeUse, byteValue, expected, timestamp) + if result { + stitched := Stitch(key) + self.mirrorDel(stitched, oldBytes) + self.mirrorPut(stitched, bValue, timestamp) + self.log(persistence.Op{ + Key: Stitch(key), + Value: bValue, + Timestamp: timestamp, + Put: true, + }) + } + return } func (self *Tree) delTimestamp(key []Nibble, use int, expected int64) (result bool, oldBytes []byte) { - if _, _, current, _ := self.root.get(key); current == expected { - result = true - self.root, oldBytes, _, _, _ = self.root.del(nil, key, use, self.timer.ContinuousTime()) - } - return + if _, _, current, _ := self.root.get(key); current == expected { + result = true + self.root, oldBytes, _, _, _ = self.root.del(nil, key, use, self.timer.ContinuousTime()) + } + return } func (self *Tree) DelTimestamp(key []Nibble, expected int64) (result bool) { - self.lock.Lock() - defer self.lock.Unlock() - var oldBytes []byte - result, oldBytes = self.delTimestamp(key, byteValue, expected) - if result { - self.mirrorDel(Stitch(key), oldBytes) - self.log(persistence.Op{ - Key: Stitch(key), - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + var oldBytes []byte + result, oldBytes = self.delTimestamp(key, byteValue, expected) + if result { + self.mirrorDel(Stitch(key), oldBytes) + self.log(persistence.Op{ + Key: Stitch(key), + }) + } + return } func (self *Tree) subConfiguration(key []byte) (conf map[string]string, timestamp int64) { - if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { - conf, timestamp = subTree.Configuration() - } else { - conf = make(map[string]string) - } - return + if _, subTree, _, ex := self.root.get(Rip(key)); ex&treeValue != 0 && subTree != nil { + conf, timestamp = subTree.Configuration() + } else { + conf = make(map[string]string) + } + return } func (self *Tree) SubConfiguration(key []byte) (conf map[string]string, timestamp int64) { - self.lock.RLock() - defer self.lock.RUnlock() - return self.subConfiguration(key) + self.lock.RLock() + defer self.lock.RUnlock() + return self.subConfiguration(key) } func (self *Tree) subConfigure(key []byte, conf map[string]string, timestamp int64) { - ripped := Rip(key) - _, subTree, subTreeTimestamp, ex := self.root.get(ripped) - if ex&treeValue == 0 || subTree == nil { - subTree = NewTreeTimer(self.timer) - } - subTree.Configure(conf, timestamp) - self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) - self.log(persistence.Op{ - Key: key, - Configuration: conf, - Timestamp: timestamp, - }) + ripped := Rip(key) + _, subTree, subTreeTimestamp, ex := self.root.get(ripped) + if ex&treeValue == 0 || subTree == nil { + subTree = NewTreeTimer(self.timer) + } + subTree.Configure(conf, timestamp) + self.put(ripped, nil, subTree, treeValue, subTreeTimestamp) + self.log(persistence.Op{ + Key: key, + Configuration: conf, + Timestamp: timestamp, + }) } func (self *Tree) SubConfigure(key []byte, conf map[string]string, timestamp int64) { - self.lock.Lock() - defer self.lock.Unlock() - self.subConfigure(key, conf, timestamp) + self.lock.Lock() + defer self.lock.Unlock() + self.subConfigure(key, conf, timestamp) } func (self *Tree) SubAddConfiguration(treeKey []byte, ts int64, key, value string) bool { - self.lock.Lock() - defer self.lock.Unlock() - oldConf, _ := self.subConfiguration(treeKey) - if oldConf[key] != value { - oldConf[key] = value - self.subConfigure(treeKey, oldConf, ts) - return true - } - return false + self.lock.Lock() + defer self.lock.Unlock() + oldConf, _ := self.subConfiguration(treeKey) + if oldConf[key] != value { + oldConf[key] = value + self.subConfigure(treeKey, oldConf, ts) + return true + } + return false } func (self *Tree) SubFinger(key, subKey []Nibble) (result *Print) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil { - result = subTree.Finger(subKey) - } else { - result = &Print{} - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil { + result = subTree.Finger(subKey) + } else { + result = &Print{} + } + return } func (self *Tree) SubGetTimestamp(key, subKey []Nibble) (byteValue []byte, timestamp int64, present bool) { - self.lock.RLock() - defer self.lock.RUnlock() - if _, subTree, _, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil { - byteValue, timestamp, present = subTree.GetTimestamp(subKey) - } - return + self.lock.RLock() + defer self.lock.RUnlock() + if _, subTree, _, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil { + byteValue, timestamp, present = subTree.GetTimestamp(subKey) + } + return } func (self *Tree) SubPutTimestamp(key, subKey []Nibble, bValue []byte, present bool, subExpected, subTimestamp int64) (result bool) { - self.lock.Lock() - defer self.lock.Unlock() - _, subTree, subTreeTimestamp, _ := self.root.get(key) - if subTree == nil { - result = true - subTree = self.newTreeWith(subKey, bValue, subTimestamp) - } else { - result = subTree.PutTimestamp(subKey, bValue, present, subExpected, subTimestamp) - } - self.putTimestamp(key, nil, subTree, treeValue, treeValue, subTreeTimestamp, subTreeTimestamp) - if result { - self.log(persistence.Op{ - Key: Stitch(key), - SubKey: Stitch(subKey), - Value: bValue, - Timestamp: subTimestamp, - Put: true, - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + _, subTree, subTreeTimestamp, _ := self.root.get(key) + if subTree == nil { + result = true + subTree = self.newTreeWith(subKey, bValue, subTimestamp) + } else { + result = subTree.PutTimestamp(subKey, bValue, present, subExpected, subTimestamp) + } + self.putTimestamp(key, nil, subTree, treeValue, treeValue, subTreeTimestamp, subTreeTimestamp) + if result { + self.log(persistence.Op{ + Key: Stitch(key), + SubKey: Stitch(subKey), + Value: bValue, + Timestamp: subTimestamp, + Put: true, + }) + } + return } func (self *Tree) SubDelTimestamp(key, subKey []Nibble, subExpected int64) (result bool) { - self.lock.Lock() - defer self.lock.Unlock() - if _, subTree, subTreeTimestamp, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil { - result = subTree.DelTimestamp(subKey, subExpected) - if subTree.Size() == 0 { - self.delTimestamp(key, treeValue, subTreeTimestamp) - } else { - self.putTimestamp(key, nil, subTree, treeValue, treeValue, subTreeTimestamp, subTreeTimestamp) - } - } - if result { - self.log(persistence.Op{ - Key: Stitch(key), - SubKey: Stitch(subKey), - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + if _, subTree, subTreeTimestamp, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil { + result = subTree.DelTimestamp(subKey, subExpected) + if subTree.Size() == 0 { + self.delTimestamp(key, treeValue, subTreeTimestamp) + } else { + self.putTimestamp(key, nil, subTree, treeValue, treeValue, subTreeTimestamp, subTreeTimestamp) + } + } + if result { + self.log(persistence.Op{ + Key: Stitch(key), + SubKey: Stitch(subKey), + }) + } + return } func (self *Tree) SubClearTimestamp(key []Nibble, expected, timestamp int64) (deleted int) { - self.lock.Lock() - defer self.lock.Unlock() - if _, subTree, subTreeTimestamp, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil && subTree.DataTimestamp() == expected { - deleted = subTree.Size() - subTree.Clear(timestamp) - self.putTimestamp(key, nil, subTree, treeValue, treeValue, subTreeTimestamp, subTreeTimestamp) - } - if deleted > 0 { - self.log(persistence.Op{ - Key: Stitch(key), - Clear: true, - Timestamp: timestamp, - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + if _, subTree, subTreeTimestamp, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil && subTree.DataTimestamp() == expected { + deleted = subTree.Size() + subTree.Clear(timestamp) + self.putTimestamp(key, nil, subTree, treeValue, treeValue, subTreeTimestamp, subTreeTimestamp) + } + if deleted > 0 { + self.log(persistence.Op{ + Key: Stitch(key), + Clear: true, + Timestamp: timestamp, + }) + } + return } func (self *Tree) SubKillTimestamp(key []Nibble, expected int64) (deleted int) { - self.lock.Lock() - defer self.lock.Unlock() - if _, subTree, subTreeTimestamp, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil && subTree.DataTimestamp() == expected { - deleted = subTree.Size() - self.delTimestamp(key, treeValue, subTreeTimestamp) - } - if deleted > 0 { - self.log(persistence.Op{ - Key: Stitch(key), - Clear: true, - }) - } - return + self.lock.Lock() + defer self.lock.Unlock() + if _, subTree, subTreeTimestamp, ex := self.root.get(key); ex&treeValue != 0 && subTree != nil && subTree.DataTimestamp() == expected { + deleted = subTree.Size() + self.delTimestamp(key, treeValue, subTreeTimestamp) + } + if deleted > 0 { + self.log(persistence.Op{ + Key: Stitch(key), + Clear: true, + }) + } + return } diff --git a/setop/README.md b/setop/README.md deleted file mode 100644 index 4f98f34..0000000 --- a/setop/README.md +++ /dev/null @@ -1,4 +0,0 @@ -setop -=== - -A bunch of functionality that does set operations on sorted and skippable sets. diff --git a/setop/merges.go b/setop/merges.go deleted file mode 100644 index cc9a049..0000000 --- a/setop/merges.go +++ /dev/null @@ -1,335 +0,0 @@ -package setop - -import ( - "bytes" - "encoding/binary" - "fmt" - "github.com/zond/god/common" - "math/big" -) - -type mergeFunc func(oldValues [][]byte, newValues [][]byte, weightForNewValues float64) (result [][]byte) - -func getMerger(m SetOpMerge) mergeFunc { - switch m { - case Append: - return _append - case ConCat: - return conCat - case IntegerSum: - return integerSum - case IntegerDiv: - return integerDiv - case IntegerMul: - return integerMul - case FloatSum: - return floatSum - case FloatDiv: - return floatDiv - case FloatMul: - return floatMul - case BigIntAnd: - return bigIntAnd - case BigIntAdd: - return bigIntAdd - case BigIntAndNot: - return bigIntAndNot - case BigIntDiv: - return bigIntDiv - case BigIntMod: - return bigIntMod - case BigIntMul: - return bigIntMul - case BigIntOr: - return bigIntOr - case BigIntRem: - return bigIntRem - case BigIntXor: - return bigIntXor - case First: - return first - case Last: - return last - } - panic(fmt.Errorf("Unknown SetOpType %v", int(m))) -} - -func last(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - return [][]byte{newValues[len(newValues)-1]} -} -func first(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - if oldValues == nil { - return [][]byte{newValues[0]} - } - return [][]byte{oldValues[0]} -} -func _append(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - result = oldValues - for i := 0; i < int(w); i++ { - result = append(result, newValues...) - } - return -} -func conCat(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var res []byte - for _, b := range oldValues { - res = append(res, b...) - } - for i := 0; i < int(w); i++ { - for _, b := range newValues { - res = append(res, b...) - } - } - return [][]byte{res} -} -func integerSum(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum int64 - var tmp int64 - var err error - for _, b := range oldValues { - if tmp, err = common.DecodeInt64(b); err == nil { - sum += tmp - } - } - for _, b := range newValues { - if tmp, err = common.DecodeInt64(b); err == nil { - sum += (tmp * int64(w)) - } - } - res := new(bytes.Buffer) - binary.Write(res, binary.BigEndian, sum) - return [][]byte{res.Bytes()} -} -func integerDiv(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum int64 - var tmp int64 - var err error - if oldValues != nil { - if tmp, err = common.DecodeInt64(oldValues[0]); err == nil { - sum = tmp - } - for _, b := range newValues { - if tmp, err = common.DecodeInt64(b); err == nil { - sum /= (tmp * int64(w)) - } - } - } else { - if tmp, err = common.DecodeInt64(newValues[0]); err == nil { - sum = (tmp * int64(w)) - } - for _, b := range newValues[1:] { - if tmp, err = common.DecodeInt64(b); err == nil { - sum /= (tmp * int64(w)) - } - } - } - res := new(bytes.Buffer) - binary.Write(res, binary.BigEndian, sum) - return [][]byte{res.Bytes()} -} -func integerMul(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum int64 = 1 - var tmp int64 - var err error - for _, b := range oldValues { - if tmp, err = common.DecodeInt64(b); err == nil { - sum *= tmp - } - } - for _, b := range newValues { - if tmp, err = common.DecodeInt64(b); err == nil { - sum *= (tmp * int64(w)) - } - } - res := new(bytes.Buffer) - binary.Write(res, binary.BigEndian, sum) - return [][]byte{res.Bytes()} -} -func floatSum(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum float64 - var tmp float64 - var err error - for _, b := range oldValues { - if tmp, err = common.DecodeFloat64(b); err == nil { - sum += tmp - } - } - for _, b := range newValues { - if tmp, err = common.DecodeFloat64(b); err == nil { - sum += (tmp * w) - } - } - res := new(bytes.Buffer) - binary.Write(res, binary.BigEndian, sum) - return [][]byte{res.Bytes()} -} -func floatDiv(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum float64 - var tmp float64 - var err error - if oldValues != nil { - if tmp, err = common.DecodeFloat64(oldValues[0]); err == nil { - sum = tmp - } - for _, b := range newValues { - if tmp, err = common.DecodeFloat64(b); err == nil { - sum /= (tmp * w) - } - } - } else { - if tmp, err = common.DecodeFloat64(newValues[0]); err == nil { - sum = (tmp * w) - } - for _, b := range newValues[1:] { - if tmp, err = common.DecodeFloat64(b); err == nil { - sum /= (tmp * w) - } - } - } - res := new(bytes.Buffer) - binary.Write(res, binary.BigEndian, sum) - return [][]byte{res.Bytes()} -} -func floatMul(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum float64 = 1 - var tmp float64 - var err error - for _, b := range oldValues { - if tmp, err = common.DecodeFloat64(b); err == nil { - sum *= tmp - } - } - for _, b := range newValues { - if tmp, err = common.DecodeFloat64(b); err == nil { - sum *= (tmp * w) - } - } - res := new(bytes.Buffer) - binary.Write(res, binary.BigEndian, sum) - return [][]byte{res.Bytes()} -} -func bigIntAnd(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum *big.Int - if oldValues != nil { - sum = new(big.Int).SetBytes(oldValues[0]) - for _, b := range newValues { - sum.And(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } else { - sum = new(big.Int).Mul(new(big.Int).SetBytes(newValues[0]), big.NewInt(int64(w))) - for _, b := range newValues[1:] { - sum.And(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } - return [][]byte{sum.Bytes()} -} -func bigIntAdd(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - sum := new(big.Int) - for _, b := range oldValues { - sum.Add(sum, common.DecodeBigInt(b)) - } - for _, b := range newValues { - sum.Add(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - return [][]byte{sum.Bytes()} -} -func bigIntAndNot(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum *big.Int - if oldValues != nil { - sum = new(big.Int).SetBytes(oldValues[0]) - for _, b := range newValues { - sum.AndNot(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } else { - sum = new(big.Int).Mul(new(big.Int).SetBytes(newValues[0]), big.NewInt(int64(w))) - for _, b := range newValues[1:] { - sum.AndNot(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } - return [][]byte{sum.Bytes()} -} -func bigIntDiv(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum *big.Int - if oldValues != nil { - sum = new(big.Int).SetBytes(oldValues[0]) - for _, b := range newValues { - sum.Div(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } else { - sum = new(big.Int).Mul(new(big.Int).SetBytes(newValues[0]), big.NewInt(int64(w))) - for _, b := range newValues[1:] { - sum.Div(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } - return [][]byte{sum.Bytes()} -} -func bigIntMod(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum *big.Int - if oldValues != nil { - sum = new(big.Int).SetBytes(oldValues[0]) - for _, b := range newValues { - sum.Mod(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } else { - sum = new(big.Int).Mul(new(big.Int).SetBytes(newValues[0]), big.NewInt(int64(w))) - for _, b := range newValues[1:] { - sum.Mod(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } - return [][]byte{sum.Bytes()} -} -func bigIntMul(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - sum := big.NewInt(1) - for _, b := range oldValues { - sum.Mul(sum, common.DecodeBigInt(b)) - } - for _, b := range newValues { - sum.Mul(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - return [][]byte{sum.Bytes()} -} -func bigIntOr(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum *big.Int - if oldValues != nil { - sum = new(big.Int).SetBytes(oldValues[0]) - for _, b := range newValues { - sum.Or(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } else { - sum = new(big.Int).Mul(new(big.Int).SetBytes(newValues[0]), big.NewInt(int64(w))) - for _, b := range newValues[1:] { - sum.Or(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } - return [][]byte{sum.Bytes()} -} -func bigIntRem(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum *big.Int - if oldValues != nil { - sum = new(big.Int).SetBytes(oldValues[0]) - for _, b := range newValues { - sum.Rem(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } else { - sum = new(big.Int).Mul(new(big.Int).SetBytes(newValues[0]), big.NewInt(int64(w))) - for _, b := range newValues[1:] { - sum.Rem(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } - return [][]byte{sum.Bytes()} -} -func bigIntXor(oldValues [][]byte, newValues [][]byte, w float64) (result [][]byte) { - var sum *big.Int - if oldValues != nil { - sum = new(big.Int).SetBytes(oldValues[0]) - for _, b := range newValues { - sum.Xor(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } else { - sum = new(big.Int).Mul(new(big.Int).SetBytes(newValues[0]), big.NewInt(int64(w))) - for _, b := range newValues[1:] { - sum.Xor(sum, new(big.Int).Mul(common.DecodeBigInt(b), big.NewInt(int64(w)))) - } - } - return [][]byte{sum.Bytes()} -} diff --git a/setop/operations.go b/setop/operations.go deleted file mode 100644 index 3cb53c5..0000000 --- a/setop/operations.go +++ /dev/null @@ -1,305 +0,0 @@ -package setop - -import ( - "bytes" - "fmt" -) - -type Skipper interface { - // skip returns a value matching the min and inclusive criteria. - // If the last yielded value matches the criteria the same value will be returned again. - Skip(min []byte, inc bool) (result *SetOpResult, err error) -} - -func createSkippersAndWeights(r RawSourceCreator, sources []SetOpSource) (skippers []Skipper, weights []float64) { - skippers = make([]Skipper, len(sources)) - weights = make([]float64, len(sources)) - for index, source := range sources { - if source.Key != nil { - skippers[index] = r(source.Key) - } else { - skippers[index] = createSkipper(r, source.SetOp) - } - if source.Weight != nil { - weights[index] = *source.Weight - } else { - weights[index] = 1 - } - } - return -} - -func createSkipper(r RawSourceCreator, op *SetOp) (result Skipper) { - skippers, weights := createSkippersAndWeights(r, op.Sources) - switch op.Type { - case Union: - result = &unionOp{ - skippers: skippers, - weights: weights, - merger: getMerger(op.Merge), - } - case Intersection: - result = &interOp{ - skippers: skippers, - weights: weights, - merger: getMerger(op.Merge), - } - case Difference: - result = &diffOp{ - skippers: skippers, - weights: weights, - merger: getMerger(op.Merge), - } - case Xor: - result = &xorOp{ - skippers: skippers, - weights: weights, - merger: getMerger(op.Merge), - } - default: - panic(fmt.Errorf("Unknown SetOp Type %v", op.Type)) - } - return -} - -type xorOp struct { - skippers []Skipper - weights []float64 - curr *SetOpResult - merger mergeFunc -} - -func (self *xorOp) Skip(min []byte, inc bool) (result *SetOpResult, err error) { - gt := 0 - if inc { - gt = -1 - } - - if self.curr != nil && bytes.Compare(self.curr.Key, min) > gt { - result = self.curr - return - } - - newSkippers := make([]Skipper, 0, len(self.skippers)) - - var res *SetOpResult - var cmp int - var multi bool - - for result == nil { - for index, thisSkipper := range self.skippers { - if res, err = thisSkipper.Skip(min, inc); err != nil { - result = nil - self.curr = nil - return - } - if res != nil { - newSkippers = append(newSkippers, thisSkipper) - if result == nil { - result = res.ShallowCopy() - result.Values = self.merger(nil, result.Values, self.weights[index]) - multi = false - } else { - cmp = bytes.Compare(res.Key, result.Key) - if cmp < 0 { - multi = false - result = res.ShallowCopy() - result.Values = self.merger(nil, result.Values, self.weights[index]) - } else if cmp == 0 { - multi = true - } - } - } - } - - if len(newSkippers) == 0 { - result = nil - self.curr = nil - return - } - - if result != nil && multi { - min = result.Key - inc = false - result = nil - } - - self.skippers = newSkippers - newSkippers = newSkippers[:0] - - } - - self.curr = result - - return -} - -type unionOp struct { - skippers []Skipper - weights []float64 - curr *SetOpResult - merger mergeFunc -} - -func (self *unionOp) Skip(min []byte, inc bool) (result *SetOpResult, err error) { - gt := 0 - if inc { - gt = -1 - } - - if self.curr != nil && bytes.Compare(self.curr.Key, min) > gt { - result = self.curr - return - } - - newSkippers := make([]Skipper, 0, len(self.skippers)) - - var cmp int - var res *SetOpResult - - for index, thisSkipper := range self.skippers { - if res, err = thisSkipper.Skip(min, inc); err != nil { - result = nil - self.curr = nil - return - } - if res != nil { - newSkippers = append(newSkippers, thisSkipper) - if result == nil { - result = res.ShallowCopy() - result.Values = self.merger(nil, result.Values, self.weights[index]) - } else { - cmp = bytes.Compare(res.Key, result.Key) - if cmp < 0 { - result = res.ShallowCopy() - result.Values = self.merger(nil, result.Values, self.weights[index]) - } else if cmp == 0 { - result.Values = self.merger(result.Values, res.Values, self.weights[index]) - } - } - } - } - - self.skippers = newSkippers - - self.curr = result - - return -} - -type interOp struct { - skippers []Skipper - weights []float64 - curr *SetOpResult - merger mergeFunc -} - -func (self *interOp) Skip(min []byte, inc bool) (result *SetOpResult, err error) { - gt := 0 - if inc { - gt = -1 - } - - if self.curr != nil && bytes.Compare(self.curr.Key, min) > gt { - result = self.curr - return - } - - var maxKey []byte - var res *SetOpResult - var cmp int - - for result == nil { - maxKey = nil - for index, thisSkipper := range self.skippers { - if res, err = thisSkipper.Skip(min, inc); res == nil || err != nil { - result = nil - self.curr = nil - return - } - if maxKey == nil { - maxKey = res.Key - result = res.ShallowCopy() - result.Values = self.merger(nil, result.Values, self.weights[index]) - } else { - cmp = bytes.Compare(res.Key, maxKey) - if cmp != 0 { - if cmp > 0 { - maxKey = res.Key - } - result = nil - } else { - result.Values = self.merger(result.Values, res.Values, self.weights[index]) - } - } - } - - min = maxKey - inc = true - } - - self.curr = result - - return -} - -type diffOp struct { - skippers []Skipper - weights []float64 - curr *SetOpResult - merger mergeFunc -} - -func (self *diffOp) Skip(min []byte, inc bool) (result *SetOpResult, err error) { - gt := 0 - if inc { - gt = -1 - } - - if self.curr != nil && bytes.Compare(self.curr.Key, min) > gt { - result = self.curr - return - } - - var newSkippers = make([]Skipper, 0, len(self.skippers)) - var res *SetOpResult - - for result == nil { - for index, thisSkipper := range self.skippers { - if res, err = thisSkipper.Skip(min, inc); err != nil { - result = nil - self.curr = nil - return - } - if index == 0 { - if res == nil { - result = nil - self.curr = nil - return - } - result = res.ShallowCopy() - result.Values = self.merger(nil, result.Values, self.weights[0]) - newSkippers = append(newSkippers, thisSkipper) - min = res.Key - inc = true - } else { - if res != nil { - newSkippers = append(newSkippers, thisSkipper) - if bytes.Compare(min, res.Key) == 0 { - result = nil - break - } - } - } - } - - self.skippers = newSkippers - newSkippers = newSkippers[:0] - inc = false - - } - - self.curr = result - - return -} diff --git a/setop/parser_test.go b/setop/parser_test.go deleted file mode 100644 index 7e8eacb..0000000 --- a/setop/parser_test.go +++ /dev/null @@ -1,61 +0,0 @@ -package setop - -import ( - "reflect" - "testing" -) - -func TestSetOpParser(t *testing.T) { - var x2 float64 = 2 - var x3 float64 = 3 - op, err := NewSetOpParser("(U (I ccc aa (D ffff*2 gg)*3) (I:ConCat c23 b_ff) (X dbla e&44))").Parse() - if err != nil { - t.Error(err) - } - cmp := &SetOp{ - Type: Union, - Sources: []SetOpSource{ - SetOpSource{ - SetOp: &SetOp{ - Type: Intersection, - Sources: []SetOpSource{ - SetOpSource{Key: []byte("ccc")}, - SetOpSource{Key: []byte("aa")}, - SetOpSource{ - SetOp: &SetOp{ - Type: Difference, - Sources: []SetOpSource{ - SetOpSource{Key: []byte("ffff"), Weight: &x2}, - SetOpSource{Key: []byte("gg")}, - }, - }, - Weight: &x3, - }, - }, - }, - }, - SetOpSource{ - SetOp: &SetOp{ - Type: Intersection, - Merge: ConCat, - Sources: []SetOpSource{ - SetOpSource{Key: []byte("c23")}, - SetOpSource{Key: []byte("b_ff")}, - }, - }, - }, - SetOpSource{ - SetOp: &SetOp{ - Type: Xor, - Sources: []SetOpSource{ - SetOpSource{Key: []byte("dbla")}, - SetOpSource{Key: []byte("e&44")}, - }, - }, - }, - }, - } - if !reflect.DeepEqual(op, cmp) { - t.Errorf("%v and %v should be equal", op, cmp) - } -} diff --git a/setop/set_op.go b/setop/set_op.go deleted file mode 100644 index 70b5774..0000000 --- a/setop/set_op.go +++ /dev/null @@ -1,259 +0,0 @@ -package setop - -import ( - "bytes" - "fmt" - "strings" -) - -// RawSourceCreator is a function that takes the name of a raw skippable sortable set, and returns a Skipper interface. -type RawSourceCreator func(b []byte) Skipper - -// SetOpResultIterator is something that handles the results of a SetExpression. -type SetOpResultIterator func(res *SetOpResult) - -const ( - // Append simply appends all elements in the input lists and builds an output list from them. - Append = iota - // ConCat appends all elements in the input lists into a single element, and builds an output list with only that element. - ConCat - // IntegerSum decodes all values as int64 using common.DecodeInt64 and sums them. - IntegerSum - // IntegerDiv decodes all values as int64 using common.DecodeInt64 and divides the first value in the input lists by all other values in turn. - IntegerDiv - // IntegerMul decodes all values as int64 using common.DecodeInt64 and multiplies them with each other. - IntegerMul - // FloatSum decodes all values as float64 using common.DecodeFloat64 and sums them. - FloatSum - // FloatDiv decodes all values as float64 using common.DecodeFloat64 and divides the first value in the input lists by all other values in turn. - FloatDiv - // FloatMul decodes all values as float64 using common.DecodeFloat64 and multiplies them with each other. - FloatMul - // BigIntAnd decodes all values as big.Ints using common.DecodeBigInt and logical ANDs them with each other. - BigIntAnd - // BigIntAdd decodes all values as big.Ints using common.DecodeBigInt and sums them. - BigIntAdd - // BigIntAndNot decodes all values as big.Ints using common.DecodeBigInt and logcal AND NOTs them with each other. - BigIntAndNot - // BigIntDiv decodes all values as big.Ints using common.DecodeBigInt and divides the first value in the input lists by all other values in them. - BigIntDiv - // BigIntMod decodes all values as big.Ints using common.DecodeBigInt and does a modulo operation on each one in turn, with the first one as source value. - BigIntMod - // BigIntMul decodes all values as big.Ints using common.DecodeBigInt and multiplies them with each other. - BigIntMul - // BigIntOr decodes all values as big.Ints using common.DecodeBigInt and logical ORs them with each other. - BigIntOr - // BigIntRem decodes all values as big.Ints using common.DecodeBigInt and does a remainder operation on each one in turn, with the first one as source value. - BigIntRem - // BigIntXor decodes all values as big.Ints using common.DecodeBigInt and logical XORs them with each other. - BigIntXor - // First will simply return the first slice from the inputs. - First - // Last will simply return the last slice from the inputs. - Last -) - -// SetOpMerge defines how a SetOp merges the values in the input sets. -type SetOpMerge int - -func ParseSetOpMerge(s string) (result SetOpMerge, err error) { - switch s { - case "Append": - result = Append - case "ConCat": - result = ConCat - case "IntegerSum": - result = IntegerSum - case "IntegerDiv": - result = IntegerDiv - case "IntegerMul": - result = IntegerMul - case "FloatSum": - result = FloatSum - case "FloatDiv": - result = FloatDiv - case "FloatMul": - result = FloatMul - case "BigIntAnd": - result = BigIntAnd - case "BigIntAdd": - result = BigIntAdd - case "BigIntAndNot": - result = BigIntAndNot - case "BigIntDiv": - result = BigIntDiv - case "BigIntMod": - result = BigIntMod - case "BigIntMul": - result = BigIntMul - case "BigIntOr": - result = BigIntOr - case "BigIntRem": - result = BigIntRem - case "BigIntXor": - result = BigIntXor - case "First": - result = First - case "Last": - result = Last - default: - err = fmt.Errorf("Unknown SetOpType %v. Legal values: Append, ConCat, IntegerSum, IntegerDiv, IntegerMul, FloatSum, FloatDiv, FloatMul, BigIntAdd, BigIntAnd, BigIntAndNot, BigIntDiv, BigIntMod, BigIntMul, BigIntOr, BigIntRem, BigIntXor, First, Last.", s) - } - return -} - -func (self SetOpMerge) String() string { - switch self { - case Append: - return "Append" - case ConCat: - return "ConCat" - case IntegerSum: - return "IntegerSum" - case IntegerDiv: - return "IntegerDiv" - case IntegerMul: - return "IntegerMul" - case FloatSum: - return "FloatSum" - case FloatDiv: - return "FloatDiv" - case FloatMul: - return "FloatMul" - case BigIntAnd: - return "BigIntAnd" - case BigIntAdd: - return "BigIntAdd" - case BigIntAndNot: - return "BigIntAndNot" - case BigIntDiv: - return "BigIntDiv" - case BigIntMod: - return "BigIntMod" - case BigIntMul: - return "BigIntMul" - case BigIntOr: - return "BigIntOr" - case BigIntRem: - return "BigIntRem" - case BigIntXor: - return "BigIntXor" - case First: - return "First" - case Last: - return "Last" - } - panic(fmt.Errorf("Unknown SetOpType %v", int(self))) -} - -const ( - Union = iota - Intersection - Difference - // Xor differs from the definition in http://en.wikipedia.org/wiki/Exclusive_or by only returning keys present in exactly ONE input set. - Xor -) - -// SetOpType is the set operation to perform in a SetExpression. -type SetOpType int - -func (self SetOpType) String() string { - switch self { - case Union: - return "U" - case Intersection: - return "I" - case Difference: - return "D" - case Xor: - return "X" - } - panic(fmt.Errorf("Unknown SetOpType %v", int(self))) -} - -// SetOpSource is either a key to a raw source producing input data, or another SetOp that calculates input data. -// Weight is the weight of this source in the chosen Merge for the parent SetOp, if any. -type SetOpSource struct { - Key []byte - SetOp *SetOp - Weight *float64 -} - -// SetOp is a set operation to perform on a slice of SetOpSources, using a SetOpMerge function to merge the calculated values. -type SetOp struct { - Sources []SetOpSource - Type SetOpType - Merge SetOpMerge -} - -func (self *SetOp) String() string { - sources := make([]string, len(self.Sources)) - for index, source := range self.Sources { - if source.Key != nil { - sources[index] = string(source.Key) - } else { - sources[index] = fmt.Sprint(source.SetOp) - } - if source.Weight != nil { - sources[index] = fmt.Sprintf("%v*%v", sources[index], *source.Weight) - } - } - return fmt.Sprintf("(%v %v)", self.Type, strings.Join(sources, " ")) -} - -// SetExpression is a set operation defined by the Op or Code fields, coupled with range parameters and a Dest key defining where to put the results. -type SetExpression struct { - Op *SetOp - Code string - Min []byte - Max []byte - MinInc bool - MaxInc bool - Len int - Dest []byte -} - -// Each will execute the set expression, using the provided RawSourceCreator, and iterate over the result using f. -func (self *SetExpression) Each(r RawSourceCreator, f SetOpResultIterator) (err error) { - if self.Op == nil { - self.Op = MustParse(self.Code) - } - skipper := createSkipper(r, self.Op) - min := self.Min - mininc := self.MinInc - count := 0 - gt := -1 - if self.MaxInc { - gt = 0 - } - var res *SetOpResult - for res, err = skipper.Skip(min, mininc); res != nil && err == nil; res, err = skipper.Skip(min, mininc) { - if (self.Len > 0 && count >= self.Len) || (self.Max != nil && bytes.Compare(res.Key, self.Max) > gt) { - return - } - count++ - min = res.Key - mininc = false - f(res) - } - return -} - -// SetOpResult is a key and any values the Merge returned. -type SetOpResult struct { - Key []byte - Values [][]byte -} - -// ShallowCopy returns another SetOpResult with the same Key and a copy of the Values. -func (self *SetOpResult) ShallowCopy() (result *SetOpResult) { - result = &SetOpResult{ - Key: self.Key, - Values: make([][]byte, len(self.Values)), - } - copy(result.Values, self.Values) - return -} -func (self *SetOpResult) String() string { - return fmt.Sprintf("%+v", *self) -} diff --git a/setop/set_op_parser.go b/setop/set_op_parser.go deleted file mode 100644 index 9f189b2..0000000 --- a/setop/set_op_parser.go +++ /dev/null @@ -1,215 +0,0 @@ -package setop - -import ( - "bytes" - "fmt" - "regexp" - "strconv" -) - -var operationPattern = regexp.MustCompile("^(\\w)(:(\\w+))?$") - -const ( - empty = iota - lparen - name - params - param - weight - finished -) - -// SetOpParser is a simple s-expression parser to parse expressions -// of set algebra. -// -// It seems simplest to provide a few examples: -// -// (U s1 s2 s3) will return the union of s1-3. -// -// (I (U s1 s2) s3 s4) will return the intersection of s3-4 with the union of s1-2. -// -// (D s1 s3 s3) will return the difference between s1 and s2-3, which is all elements in s1 not present in s2 or s3. -// -// (X s1 s2 s3) will return all element only present in one of s1, s2 and s3. Note that this does not follow the XOR set operation definition at http://en.wikipedia.org/wiki/Exclusive_or -// -// To use another merge function than Append (the default), append :MERGEFUNCNAME to the function name in the s-expression. -// -// (I:IntegerSum s1 s2) will return the integer sum of all elements present in both s1 and s2. -type SetOpParser struct { - in string - nextName *bytes.Buffer - nextWeight *bytes.Buffer - start int - pos int -} - -func NewSetOpParser(in string) *SetOpParser { - return &SetOpParser{ - in: in, - nextName: new(bytes.Buffer), - nextWeight: new(bytes.Buffer), - } -} - -func (self *SetOpParser) Parse() (result *SetOp, err error) { - if result, err = self.parse(); err != nil { - return - } - if self.pos < len([]byte(self.in)) { - err = fmt.Errorf("Unexpected characters at %v in %v.", self.pos, self.in) - } - return -} - -func MustParse(in string) *SetOp { - res, err := NewSetOpParser(in).Parse() - if err != nil { - panic(err) - } - return res -} - -func (self *SetOpParser) parse() (result *SetOp, err error) { - state := empty - result = &SetOp{} - for state != finished { - if self.pos >= len(self.in) { - err = fmt.Errorf("Unexpected EOF at %v in %v.", self.pos, self.in) - return - } - switch state { - case empty: - switch self.in[self.pos] { - case '(': - state = name - case ' ': - default: - err = fmt.Errorf("Expected ( at %v in %v.", self.pos, self.in) - return - } - case name: - switch self.in[self.pos] { - case ' ': - if match := operationPattern.FindStringSubmatch(string(self.nextName.Bytes())); match != nil { - switch match[1] { - case "U": - result.Type = Union - case "I": - result.Type = Intersection - case "X": - result.Type = Xor - case "D": - result.Type = Difference - default: - err = fmt.Errorf("Unknown operation type %c at %v in %v. Legal values: U,I,X,D.", self.in[self.pos], self.pos, self.in) - return - } - if match[3] != "" { - if result.Merge, err = ParseSetOpMerge(match[3]); err != nil { - return - } - } - state = params - self.nextName = new(bytes.Buffer) - } else { - err = fmt.Errorf("Unknown operation type %c at %v in %v. Legal values: U,I,X,D.", self.in[self.pos], self.pos, self.in) - return - } - case ')': - err = fmt.Errorf("Empty operation not allowed at %v in %v.", self.pos, self.in) - return - default: - self.nextName.WriteByte(self.in[self.pos]) - } - case params: - switch self.in[self.pos] { - case ' ': - case ')': - if len(result.Sources) == 0 { - err = fmt.Errorf("Operation without parameters not allowed at %v in %v.", self.pos, self.in) - return - } - if self.nextName.Len() > 0 { - result.Sources = append(result.Sources, SetOpSource{Key: self.nextName.Bytes()}) - self.nextName = new(bytes.Buffer) - } - state = finished - case '(': - if self.nextName.Len() > 0 { - err = fmt.Errorf("Unexpected ( at %v in %v.", self.pos, self.in) - return - } - var nested *SetOp - if nested, err = self.parse(); err != nil { - return - } - self.pos-- - result.Sources = append(result.Sources, SetOpSource{SetOp: nested}) - case '*': - self.nextWeight = new(bytes.Buffer) - state = weight - default: - state = param - self.nextName.WriteByte(self.in[self.pos]) - } - case weight: - switch self.in[self.pos] { - case '*': - err = fmt.Errorf("Unexpected * at %v in %v.", self.pos, self.in) - return - case '(': - err = fmt.Errorf("Unexpected ( at %v in %v.", self.pos, self.in) - return - case ')': - var w float64 - if w, err = strconv.ParseFloat(string(self.nextWeight.Bytes()), 64); err != nil { - err = fmt.Errorf("Unparseable float64 at %v in %v.", self.pos, self.in) - return - } - result.Sources[len(result.Sources)-1].Weight = &w - self.nextWeight = new(bytes.Buffer) - state = finished - case ' ': - var w float64 - if w, err = strconv.ParseFloat(string(self.nextWeight.Bytes()), 64); err != nil { - err = fmt.Errorf("Unparseable float64 at %v in %v.", self.pos, self.in) - return - } - result.Sources[len(result.Sources)-1].Weight = &w - self.nextWeight = new(bytes.Buffer) - state = params - default: - self.nextWeight.WriteByte(self.in[self.pos]) - } - case param: - switch self.in[self.pos] { - case '*': - if self.nextName.Len() > 0 { - result.Sources = append(result.Sources, SetOpSource{Key: self.nextName.Bytes()}) - self.nextName = new(bytes.Buffer) - } - self.nextWeight = new(bytes.Buffer) - state = weight - case ' ': - if self.nextName.Len() > 0 { - result.Sources = append(result.Sources, SetOpSource{Key: self.nextName.Bytes()}) - self.nextName = new(bytes.Buffer) - } - state = params - case ')': - if self.nextName.Len() > 0 { - result.Sources = append(result.Sources, SetOpSource{Key: self.nextName.Bytes()}) - self.nextName = new(bytes.Buffer) - } - state = finished - case '(': - err = fmt.Errorf("Unexpected ( at %v in %v.", self.pos, self.in) - return - default: - self.nextName.WriteByte(self.in[self.pos]) - } - } - self.pos++ - } - return -} diff --git a/setop/set_op_test.go b/setop/set_op_test.go deleted file mode 100644 index 5c07c2a..0000000 --- a/setop/set_op_test.go +++ /dev/null @@ -1,554 +0,0 @@ -package setop - -import ( - "bytes" - "fmt" - "github.com/zond/god/common" - "math/big" - "reflect" - "sort" - "testing" -) - -type testSkipper struct { - pairs []tP - index int -} -type tP [2]string - -func (self *testSkipper) Skip(min []byte, inc bool) (result *SetOpResult, err error) { - lt := 1 - if inc { - lt = 0 - } - for self.index < len(self.pairs) && bytes.Compare([]byte(self.pairs[self.index][0]), min) < lt { - self.index++ - } - if self.index < len(self.pairs) { - return &SetOpResult{ - Key: []byte(self.pairs[self.index][0]), - Values: [][]byte{[]byte(self.pairs[self.index][1])}, - }, nil - } - return nil, nil -} - -var testSets = map[string]*testSkipper{ - "a": &testSkipper{ - pairs: []tP{ - tP{"a", "a"}, - tP{"b", "b"}, - tP{"c", "c"}, - }, - }, - "b": &testSkipper{ - pairs: []tP{ - tP{"a", "a"}, - tP{"c", "c"}, - tP{"d", "d"}, - }, - }, -} - -func resetSets() { - for _, set := range testSets { - set.index = 0 - } -} - -func findTestSet(b []byte) Skipper { - set, ok := testSets[string(b)] - if !ok { - panic(fmt.Errorf("couldn't find test set %s", string(b))) - } - return set -} - -func collect(t *testing.T, expr string) []*SetOpResult { - s, err := NewSetOpParser(expr).Parse() - if err != nil { - t.Fatal(err) - } - se := &SetExpression{ - Op: s, - } - var collector []*SetOpResult - se.Each(findTestSet, func(res *SetOpResult) { - collector = append(collector, res) - }) - return collector -} - -type testResults []*SetOpResult - -func (self testResults) Len() int { - return len(self) -} -func (self testResults) Swap(i, j int) { - self[i], self[j] = self[j], self[i] -} -func (self testResults) Less(i, j int) bool { - return bytes.Compare(self[i].Key, self[j].Key) < 0 -} - -func diff(merger mergeFunc, sets [][]tP, weights []float64) (result []*SetOpResult) { - hashes := make([]map[string][]byte, len(sets)) - for index, set := range sets { - hashes[index] = make(map[string][]byte) - for _, pair := range set { - hashes[index][pair[0]] = []byte(pair[1]) - } - } - resultMap := make(map[string][][]byte) - for k, v := range hashes[0] { - resultMap[k] = merger(resultMap[k], [][]byte{v}, weights[0]) - } - for _, m := range hashes[1:] { - for k, _ := range m { - delete(resultMap, k) - } - } - for k, v := range resultMap { - result = append(result, &SetOpResult{ - Key: []byte(k), - Values: v, - }) - } - sort.Sort(testResults(result)) - return -} - -func inter(merger mergeFunc, sets [][]tP, weights []float64) (result []*SetOpResult) { - hashes := make([]map[string][]byte, len(sets)) - for index, set := range sets { - hashes[index] = make(map[string][]byte) - for _, pair := range set { - hashes[index][pair[0]] = []byte(pair[1]) - } - } - resultMap := make(map[string][][]byte) - for index, m := range hashes { - for k, v := range m { - isOk := true - for _, m2 := range hashes { - _, ex := m2[k] - isOk = isOk && ex - } - if isOk { - resultMap[k] = merger(resultMap[k], [][]byte{v}, weights[index]) - } - } - } - for k, v := range resultMap { - result = append(result, &SetOpResult{ - Key: []byte(k), - Values: v, - }) - } - sort.Sort(testResults(result)) - return -} - -func xor(merger mergeFunc, sets [][]tP, weights []float64) (result []*SetOpResult) { - hashes := make([]map[string][]byte, len(sets)) - for index, set := range sets { - hashes[index] = make(map[string][]byte) - for _, pair := range set { - hashes[index][pair[0]] = []byte(pair[1]) - } - } - matchMap := make(map[string]int) - resultMap := make(map[string][][]byte) - for index, m := range hashes { - for k, v := range m { - resultMap[k] = merger(resultMap[k], [][]byte{v}, weights[index]) - matchMap[k] += 1 - } - } - for k, v := range resultMap { - if matchMap[k] == 1 { - result = append(result, &SetOpResult{ - Key: []byte(k), - Values: v, - }) - } - } - sort.Sort(testResults(result)) - return -} - -func union(merger mergeFunc, sets [][]tP, weights []float64) (result []*SetOpResult) { - hashes := make([]map[string][]byte, len(sets)) - for index, set := range sets { - hashes[index] = make(map[string][]byte) - for _, pair := range set { - hashes[index][pair[0]] = []byte(pair[1]) - } - } - resultMap := make(map[string][][]byte) - for index, m := range hashes { - for k, v := range m { - resultMap[k] = merger(resultMap[k], [][]byte{v}, weights[index]) - } - } - for k, v := range resultMap { - result = append(result, &SetOpResult{ - Key: []byte(k), - Values: v, - }) - } - sort.Sort(testResults(result)) - return -} - -func TestBigIntXor(t *testing.T) { - found := bigIntXor([][]byte{common.EncodeBigInt(big.NewInt(15))}, [][]byte{common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(8))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntXor(nil, [][]byte{common.EncodeBigInt(big.NewInt(15)), common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(8))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntXor([][]byte{common.EncodeBigInt(big.NewInt(15))}, [][]byte{common.EncodeBigInt(big.NewInt(3))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(9))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestBigIntRem(t *testing.T) { - found := bigIntRem([][]byte{common.EncodeBigInt(big.NewInt(50))}, [][]byte{common.EncodeBigInt(big.NewInt(30)), common.EncodeBigInt(big.NewInt(11)), common.EncodeBigInt(big.NewInt(7))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(2))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntRem(nil, [][]byte{common.EncodeBigInt(big.NewInt(50)), common.EncodeBigInt(big.NewInt(30)), common.EncodeBigInt(big.NewInt(11)), common.EncodeBigInt(big.NewInt(7))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(2))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntRem([][]byte{common.EncodeBigInt(big.NewInt(50))}, [][]byte{common.EncodeBigInt(big.NewInt(7))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(8))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestBigIntMul(t *testing.T) { - found := bigIntMul([][]byte{common.EncodeBigInt(big.NewInt(1))}, [][]byte{common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(24))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntMul(nil, [][]byte{common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(24))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntMul([][]byte{common.EncodeBigInt(big.NewInt(1))}, [][]byte{common.EncodeBigInt(big.NewInt(2))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(4))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestBigIntOr(t *testing.T) { - found := bigIntOr([][]byte{common.EncodeBigInt(big.NewInt(1))}, [][]byte{common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(7))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntOr(nil, [][]byte{common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(7))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntOr([][]byte{common.EncodeBigInt(big.NewInt(1))}, [][]byte{common.EncodeBigInt(big.NewInt(2))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(5))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestBigMod(t *testing.T) { - found := bigIntMod([][]byte{common.EncodeBigInt(big.NewInt(50))}, [][]byte{common.EncodeBigInt(big.NewInt(30)), common.EncodeBigInt(big.NewInt(7)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(2))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntMod(nil, [][]byte{common.EncodeBigInt(big.NewInt(50)), common.EncodeBigInt(big.NewInt(30)), common.EncodeBigInt(big.NewInt(7)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(2))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntMod([][]byte{common.EncodeBigInt(big.NewInt(50))}, [][]byte{common.EncodeBigInt(big.NewInt(15))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(20))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestBigIntDiv(t *testing.T) { - found := bigIntDiv([][]byte{common.EncodeBigInt(big.NewInt(48))}, [][]byte{common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(2))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntDiv(nil, [][]byte{common.EncodeBigInt(big.NewInt(48)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(2))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntDiv([][]byte{common.EncodeBigInt(big.NewInt(48))}, [][]byte{common.EncodeBigInt(big.NewInt(2))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(12))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestBigIntAndNot(t *testing.T) { - found := bigIntAndNot([][]byte{common.EncodeBigInt(big.NewInt(15))}, [][]byte{common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(8))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntAndNot(nil, [][]byte{common.EncodeBigInt(big.NewInt(15)), common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(8))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntAndNot([][]byte{common.EncodeBigInt(big.NewInt(15))}, [][]byte{common.EncodeBigInt(big.NewInt(2))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(11))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestBigIntAdd(t *testing.T) { - found := bigIntAdd([][]byte{common.EncodeBigInt(big.NewInt(1))}, [][]byte{common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(10))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntAdd(nil, [][]byte{common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(10))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntAdd([][]byte{common.EncodeBigInt(big.NewInt(1))}, [][]byte{common.EncodeBigInt(big.NewInt(2))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(5))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestBigIntAnd(t *testing.T) { - found := bigIntAnd([][]byte{common.EncodeBigInt(big.NewInt(1))}, [][]byte{common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected := [][]byte{common.EncodeBigInt(big.NewInt(0))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntAnd([][]byte{common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(3))}, [][]byte{common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(5))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(1))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntAnd(nil, [][]byte{common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(2)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(4))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(0))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntAnd(nil, [][]byte{common.EncodeBigInt(big.NewInt(1)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(3)), common.EncodeBigInt(big.NewInt(5))}, 1) - expected = [][]byte{common.EncodeBigInt(big.NewInt(1))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } - found = bigIntAnd([][]byte{common.EncodeBigInt(big.NewInt(15))}, [][]byte{common.EncodeBigInt(big.NewInt(3))}, 2) - expected = [][]byte{common.EncodeBigInt(big.NewInt(6))} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeBigInt(found[0])), fmt.Sprint(common.DecodeBigInt(expected[0]))) - } -} - -func TestFloatMul(t *testing.T) { - found := floatMul([][]byte{common.EncodeFloat64(1)}, [][]byte{common.EncodeFloat64(2), common.EncodeFloat64(3), common.EncodeFloat64(4)}, 1) - expected := [][]byte{common.EncodeFloat64(24)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeFloat64(found[0])), fmt.Sprint(common.DecodeFloat64(expected[0]))) - } - found = floatMul(nil, [][]byte{common.EncodeFloat64(1), common.EncodeFloat64(2), common.EncodeFloat64(3), common.EncodeFloat64(4)}, 1) - expected = [][]byte{common.EncodeFloat64(24)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeFloat64(found[0])), fmt.Sprint(common.DecodeFloat64(expected[0]))) - } - found = floatMul([][]byte{common.EncodeFloat64(2)}, [][]byte{common.EncodeFloat64(2)}, 2) - expected = [][]byte{common.EncodeFloat64(8)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeFloat64(found[0])), fmt.Sprint(common.DecodeFloat64(expected[0]))) - } -} - -func TestFloatDiv(t *testing.T) { - found := floatDiv([][]byte{common.EncodeFloat64(48)}, [][]byte{common.EncodeFloat64(2), common.EncodeFloat64(3), common.EncodeFloat64(4)}, 1) - expected := [][]byte{common.EncodeFloat64(2)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeFloat64(found[0])), fmt.Sprint(common.DecodeFloat64(expected[0]))) - } - found = floatDiv(nil, [][]byte{common.EncodeFloat64(48), common.EncodeFloat64(2), common.EncodeFloat64(3), common.EncodeFloat64(4)}, 1) - expected = [][]byte{common.EncodeFloat64(2)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeFloat64(found[0])), fmt.Sprint(common.DecodeFloat64(expected[0]))) - } - found = floatDiv([][]byte{common.EncodeFloat64(48)}, [][]byte{common.EncodeFloat64(2)}, 2) - expected = [][]byte{common.EncodeFloat64(12)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", fmt.Sprint(common.DecodeFloat64(found[0])), fmt.Sprint(common.DecodeFloat64(expected[0]))) - } -} - -func TestFloatSum(t *testing.T) { - found := floatSum([][]byte{common.EncodeFloat64(1)}, [][]byte{common.EncodeFloat64(2), common.EncodeFloat64(3), common.EncodeFloat64(4)}, 1) - expected := [][]byte{common.EncodeFloat64(10)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = floatSum(nil, [][]byte{common.EncodeFloat64(1), common.EncodeFloat64(2), common.EncodeFloat64(3), common.EncodeFloat64(4)}, 1) - expected = [][]byte{common.EncodeFloat64(10)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = floatSum([][]byte{common.EncodeFloat64(1)}, [][]byte{common.EncodeFloat64(2)}, 2) - expected = [][]byte{common.EncodeFloat64(5)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestIntegerMul(t *testing.T) { - found := integerMul([][]byte{common.EncodeInt64(1)}, [][]byte{common.EncodeInt64(2), common.EncodeInt64(3), common.EncodeInt64(4)}, 1) - expected := [][]byte{common.EncodeInt64(24)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = integerMul(nil, [][]byte{common.EncodeInt64(1), common.EncodeInt64(2), common.EncodeInt64(3), common.EncodeInt64(4)}, 1) - expected = [][]byte{common.EncodeInt64(24)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = integerMul([][]byte{common.EncodeInt64(2)}, [][]byte{common.EncodeInt64(2)}, 2) - expected = [][]byte{common.EncodeInt64(8)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestIntegerDiv(t *testing.T) { - found := integerDiv([][]byte{common.EncodeInt64(48)}, [][]byte{common.EncodeInt64(2), common.EncodeInt64(3), common.EncodeInt64(4)}, 1) - expected := [][]byte{common.EncodeInt64(2)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = integerDiv(nil, [][]byte{common.EncodeInt64(48), common.EncodeInt64(2), common.EncodeInt64(3), common.EncodeInt64(4)}, 1) - expected = [][]byte{common.EncodeInt64(2)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = integerDiv([][]byte{common.EncodeInt64(48)}, [][]byte{common.EncodeInt64(2)}, 2) - expected = [][]byte{common.EncodeInt64(12)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestIntegerSum(t *testing.T) { - found := integerSum([][]byte{common.EncodeInt64(1)}, [][]byte{common.EncodeInt64(2), common.EncodeInt64(3), common.EncodeInt64(4)}, 1) - expected := [][]byte{common.EncodeInt64(10)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = integerSum(nil, [][]byte{common.EncodeInt64(1), common.EncodeInt64(2), common.EncodeInt64(3), common.EncodeInt64(4)}, 1) - expected = [][]byte{common.EncodeInt64(10)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = integerSum([][]byte{common.EncodeInt64(1)}, [][]byte{common.EncodeInt64(2)}, 2) - expected = [][]byte{common.EncodeInt64(5)} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestConCat(t *testing.T) { - found := conCat([][]byte{[]byte{1}}, [][]byte{[]byte{2}, []byte{3}, []byte{4}}, 1) - expected := [][]byte{[]byte{1, 2, 3, 4}} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = conCat(nil, [][]byte{[]byte{1}, []byte{2}, []byte{3}, []byte{4}}, 1) - expected = [][]byte{[]byte{1, 2, 3, 4}} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = conCat([][]byte{[]byte{1}}, [][]byte{[]byte{2}}, 2) - expected = [][]byte{[]byte{1, 2, 2}} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestAppend(t *testing.T) { - found := _append([][]byte{[]byte{1}}, [][]byte{[]byte{2}, []byte{3}, []byte{4}}, 1) - expected := [][]byte{[]byte{1}, []byte{2}, []byte{3}, []byte{4}} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = _append(nil, [][]byte{[]byte{1}, []byte{2}, []byte{3}, []byte{4}}, 1) - expected = [][]byte{[]byte{1}, []byte{2}, []byte{3}, []byte{4}} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } - found = _append([][]byte{[]byte{1}}, [][]byte{[]byte{2}}, 2) - expected = [][]byte{[]byte{1}, []byte{2}, []byte{2}} - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestUnion(t *testing.T) { - resetSets() - found := collect(t, "(U a b)") - expected := union(_append, [][]tP{testSets["a"].pairs, testSets["b"].pairs}, []float64{1, 1}) - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestInter(t *testing.T) { - resetSets() - found := collect(t, "(I a b)") - expected := inter(_append, [][]tP{testSets["a"].pairs, testSets["b"].pairs}, []float64{1, 1}) - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestDiff(t *testing.T) { - resetSets() - found := collect(t, "(D a b)") - expected := diff(_append, [][]tP{testSets["a"].pairs, testSets["b"].pairs}, []float64{1, 1}) - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} - -func TestXor(t *testing.T) { - resetSets() - found := collect(t, "(X a b)") - expected := xor(_append, [][]tP{testSets["a"].pairs, testSets["b"].pairs}, []float64{1, 1}) - if !reflect.DeepEqual(found, expected) { - t.Errorf("%v should be %v", found, expected) - } -} diff --git a/templates/css.go b/templates/css.go index 7a4a8c0..4380a5b 100644 --- a/templates/css.go +++ b/templates/css.go @@ -3,5 +3,5 @@ import "text/template" var CSS = template.New("css") func init() { template.Must(CSS.New("bootstrap.min.css").Parse("/*!\n * Bootstrap v2.2.1\n *\n * Copyright 2012 Twitter, Inc\n * Licensed under the Apache License v2.0\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Designed and built with all the love in the world @twitter by @mdo and @fat.\n */\n.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:\"\";line-height:0;}\n.clearfix:after{clear:both;}\n.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;}\n.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}\narticle,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}\naudio,canvas,video{display:inline-block;*display:inline;*zoom:1;}\naudio:not([controls]){display:none;}\nhtml{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;}\na:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}\na:hover,a:active{outline:0;}\nsub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;}\nsup{top:-0.5em;}\nsub{bottom:-0.25em;}\nimg{max-width:100%;width:auto\\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;}\n#map_canvas img,.google-maps img{max-width:none;}\nbutton,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;}\nbutton,input{*overflow:visible;line-height:normal;}\nbutton::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;}\nbutton,html input[type=\"button\"],input[type=\"reset\"],input[type=\"submit\"]{-webkit-appearance:button;cursor:pointer;}\ninput[type=\"search\"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;}\ninput[type=\"search\"]::-webkit-search-decoration,input[type=\"search\"]::-webkit-search-cancel-button{-webkit-appearance:none;}\ntextarea{overflow:auto;vertical-align:top;}\nbody{margin:0;font-family:\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333333;background-color:#ffffff;}\na{color:#0088cc;text-decoration:none;}\na:hover{color:#005580;text-decoration:underline;}\n.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}\n.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);}\n.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;}\n.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:\"\";line-height:0;}\n.row:after{clear:both;}\n[class*=\"span\"]{float:left;min-height:1px;margin-left:20px;}\n.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}\n.span12{width:940px;}\n.span11{width:860px;}\n.span10{width:780px;}\n.span9{width:700px;}\n.span8{width:620px;}\n.span7{width:540px;}\n.span6{width:460px;}\n.span5{width:380px;}\n.span4{width:300px;}\n.span3{width:220px;}\n.span2{width:140px;}\n.span1{width:60px;}\n.offset12{margin-left:980px;}\n.offset11{margin-left:900px;}\n.offset10{margin-left:820px;}\n.offset9{margin-left:740px;}\n.offset8{margin-left:660px;}\n.offset7{margin-left:580px;}\n.offset6{margin-left:500px;}\n.offset5{margin-left:420px;}\n.offset4{margin-left:340px;}\n.offset3{margin-left:260px;}\n.offset2{margin-left:180px;}\n.offset1{margin-left:100px;}\n.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:\"\";line-height:0;}\n.row-fluid:after{clear:both;}\n.row-fluid [class*=\"span\"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;}\n.row-fluid [class*=\"span\"]:first-child{margin-left:0;}\n.row-fluid .controls-row [class*=\"span\"]+[class*=\"span\"]{margin-left:2.127659574468085%;}\n.row-fluid .span12{width:100%;*width:99.94680851063829%;}\n.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;}\n.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;}\n.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;}\n.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;}\n.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;}\n.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;}\n.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;}\n.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;}\n.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;}\n.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;}\n.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;}\n.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;}\n.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;}\n.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;}\n.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;}\n.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;}\n.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;}\n.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;}\n.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;}\n.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;}\n.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;}\n.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;}\n.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;}\n.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;}\n.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;}\n.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;}\n.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;}\n.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;}\n.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;}\n.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;}\n.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;}\n.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;}\n.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;}\n.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;}\n.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;}\n[class*=\"span\"].hide,.row-fluid [class*=\"span\"].hide{display:none;}\n[class*=\"span\"].pull-right,.row-fluid [class*=\"span\"].pull-right{float:right;}\n.container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:\"\";line-height:0;}\n.container:after{clear:both;}\n.container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:\"\";line-height:0;}\n.container-fluid:after{clear:both;}\np{margin:0 0 10px;}\n.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;}\nsmall{font-size:85%;}\nstrong{font-weight:bold;}\nem{font-style:italic;}\ncite{font-style:normal;}\n.muted{color:#999999;}\n.text-warning{color:#c09853;}\na.text-warning:hover{color:#a47e3c;}\n.text-error{color:#b94a48;}\na.text-error:hover{color:#953b39;}\n.text-info{color:#3a87ad;}\na.text-info:hover{color:#2d6987;}\n.text-success{color:#468847;}\na.text-success:hover{color:#356635;}\nh1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999999;}\nh1,h2,h3{line-height:40px;}\nh1{font-size:38.5px;}\nh2{font-size:31.5px;}\nh3{font-size:24.5px;}\nh4{font-size:17.5px;}\nh5{font-size:14px;}\nh6{font-size:11.9px;}\nh1 small{font-size:24.5px;}\nh2 small{font-size:17.5px;}\nh3 small{font-size:14px;}\nh4 small{font-size:14px;}\n.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;}\nul,ol{padding:0;margin:0 0 10px 25px;}\nul ul,ul ol,ol ol,ol ul{margin-bottom:0;}\nli{line-height:20px;}\nul.unstyled,ol.unstyled{margin-left:0;list-style:none;}\ndl{margin-bottom:20px;}\ndt,dd{line-height:20px;}\ndt{font-weight:bold;}\ndd{margin-left:10px;}\n.dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:\"\";line-height:0;}\n.dl-horizontal:after{clear:both;}\n.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;}\n.dl-horizontal dd{margin-left:180px;}\nhr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;}\nabbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;}\nabbr.initialism{font-size:90%;text-transform:uppercase;}\nblockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:16px;font-weight:300;line-height:25px;}\nblockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\\2014 \\00A0';}\nblockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;}\nblockquote.pull-right small:before{content:'';}\nblockquote.pull-right small:after{content:'\\00A0 \\2014';}\nq:before,q:after,blockquote:before,blockquote:after{content:\"\";}\naddress{display:block;margin-bottom:20px;font-style:normal;line-height:20px;}\ncode,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,\"Courier New\",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\ncode{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;}\npre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:20px;}\npre code{padding:0;color:inherit;background-color:transparent;border:0;}\n.pre-scrollable{max-height:340px;overflow-y:scroll;}\n.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;}\n.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n.badge{padding-left:9px;padding-right:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;}\na.label:hover,a.badge:hover{color:#ffffff;text-decoration:none;cursor:pointer;}\n.label-important,.badge-important{background-color:#b94a48;}\n.label-important[href],.badge-important[href]{background-color:#953b39;}\n.label-warning,.badge-warning{background-color:#f89406;}\n.label-warning[href],.badge-warning[href]{background-color:#c67605;}\n.label-success,.badge-success{background-color:#468847;}\n.label-success[href],.badge-success[href]{background-color:#356635;}\n.label-info,.badge-info{background-color:#3a87ad;}\n.label-info[href],.badge-info[href]{background-color:#2d6987;}\n.label-inverse,.badge-inverse{background-color:#333333;}\n.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;}\n.btn .label,.btn .badge{position:relative;top:-1px;}\n.btn-mini .label,.btn-mini .badge{top:0;}\ntable{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;}\n.table{width:100%;margin-bottom:20px;}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;}\n.table th{font-weight:bold;}\n.table thead th{vertical-align:bottom;}\n.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;}\n.table tbody+tbody{border-top:2px solid #dddddd;}\n.table-condensed th,.table-condensed td{padding:4px 5px;}\n.table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;}\n.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;}\n.table-bordered thead:first-child tr:first-child th:first-child,.table-bordered tbody:first-child tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;}\n.table-bordered thead:first-child tr:first-child th:last-child,.table-bordered tbody:first-child tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px;}\n.table-bordered thead:last-child tr:last-child th:first-child,.table-bordered tbody:last-child tr:last-child td:first-child,.table-bordered tfoot:last-child tr:last-child td:first-child{-webkit-border-radius:0 0 0 4px;-moz-border-radius:0 0 0 4px;border-radius:0 0 0 4px;-webkit-border-bottom-left-radius:4px;border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;}\n.table-bordered thead:last-child tr:last-child th:last-child,.table-bordered tbody:last-child tr:last-child td:last-child,.table-bordered tfoot:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:4px;border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;}\n.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;border-top-left-radius:4px;-moz-border-radius-topleft:4px;}\n.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;border-top-right-radius:4px;-moz-border-radius-topright:4px;}\n.table-striped tbody tr:nth-child(odd) td,.table-striped tbody tr:nth-child(odd) th{background-color:#f9f9f9;}\n.table-hover tbody tr:hover td,.table-hover tbody tr:hover th{background-color:#f5f5f5;}\ntable td[class*=\"span\"],table th[class*=\"span\"],.row-fluid table td[class*=\"span\"],.row-fluid table th[class*=\"span\"]{display:table-cell;float:none;margin-left:0;}\n.table td.span1,.table th.span1{float:none;width:44px;margin-left:0;}\n.table td.span2,.table th.span2{float:none;width:124px;margin-left:0;}\n.table td.span3,.table th.span3{float:none;width:204px;margin-left:0;}\n.table td.span4,.table th.span4{float:none;width:284px;margin-left:0;}\n.table td.span5,.table th.span5{float:none;width:364px;margin-left:0;}\n.table td.span6,.table th.span6{float:none;width:444px;margin-left:0;}\n.table td.span7,.table th.span7{float:none;width:524px;margin-left:0;}\n.table td.span8,.table th.span8{float:none;width:604px;margin-left:0;}\n.table td.span9,.table th.span9{float:none;width:684px;margin-left:0;}\n.table td.span10,.table th.span10{float:none;width:764px;margin-left:0;}\n.table td.span11,.table th.span11{float:none;width:844px;margin-left:0;}\n.table td.span12,.table th.span12{float:none;width:924px;margin-left:0;}\n.table tbody tr.success td{background-color:#dff0d8;}\n.table tbody tr.error td{background-color:#f2dede;}\n.table tbody tr.warning td{background-color:#fcf8e3;}\n.table tbody tr.info td{background-color:#d9edf7;}\n.table-hover tbody tr.success:hover td{background-color:#d0e9c6;}\n.table-hover tbody tr.error:hover td{background-color:#ebcccc;}\n.table-hover tbody tr.warning:hover td{background-color:#faf2cc;}\n.table-hover tbody tr.info:hover td{background-color:#c4e3f3;}\nform{margin:0 0 20px;}\nfieldset{padding:0;margin:0;border:0;}\nlegend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;}\nlabel,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;}\ninput,button,select,textarea{font-family:\"Helvetica Neue\",Helvetica,Arial,sans-serif;}\nlabel{display:block;margin-bottom:5px;}\nselect,textarea,input[type=\"text\"],input[type=\"password\"],input[type=\"datetime\"],input[type=\"datetime-local\"],input[type=\"date\"],input[type=\"month\"],input[type=\"time\"],input[type=\"week\"],input[type=\"number\"],input[type=\"email\"],input[type=\"url\"],input[type=\"search\"],input[type=\"tel\"],input[type=\"color\"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;}\ninput,textarea,.uneditable-input{width:206px;}\ntextarea{height:auto;}\ntextarea,input[type=\"text\"],input[type=\"password\"],input[type=\"datetime\"],input[type=\"datetime-local\"],input[type=\"date\"],input[type=\"month\"],input[type=\"time\"],input[type=\"week\"],input[type=\"number\"],input[type=\"email\"],input[type=\"url\"],input[type=\"search\"],input[type=\"tel\"],input[type=\"color\"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;}textarea:focus,input[type=\"text\"]:focus,input[type=\"password\"]:focus,input[type=\"datetime\"]:focus,input[type=\"datetime-local\"]:focus,input[type=\"date\"]:focus,input[type=\"month\"]:focus,input[type=\"time\"]:focus,input[type=\"week\"]:focus,input[type=\"number\"]:focus,input[type=\"email\"]:focus,input[type=\"url\"]:focus,input[type=\"search\"]:focus,input[type=\"tel\"]:focus,input[type=\"color\"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \\9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);}\ninput[type=\"radio\"],input[type=\"checkbox\"]{margin:4px 0 0;*margin-top:0;margin-top:1px \\9;line-height:normal;cursor:pointer;}\ninput[type=\"file\"],input[type=\"image\"],input[type=\"submit\"],input[type=\"reset\"],input[type=\"button\"],input[type=\"radio\"],input[type=\"checkbox\"]{width:auto;}\nselect,input[type=\"file\"]{height:30px;*margin-top:4px;line-height:30px;}\nselect{width:220px;border:1px solid #cccccc;background-color:#ffffff;}\nselect[multiple],select[size]{height:auto;}\nselect:focus,input[type=\"file\"]:focus,input[type=\"radio\"]:focus,input[type=\"checkbox\"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}\n.uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;}\n.uneditable-input{overflow:hidden;white-space:nowrap;}\n.uneditable-textarea{width:auto;height:auto;}\ninput:-moz-placeholder,textarea:-moz-placeholder{color:#999999;}\ninput:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;}\ninput::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;}\n.radio,.checkbox{min-height:20px;padding-left:20px;}\n.radio input[type=\"radio\"],.checkbox input[type=\"checkbox\"]{float:left;margin-left:-20px;}\n.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;}\n.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;}\n.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;}\n.input-mini{width:60px;}\n.input-small{width:90px;}\n.input-medium{width:150px;}\n.input-large{width:210px;}\n.input-xlarge{width:270px;}\n.input-xxlarge{width:530px;}\ninput[class*=\"span\"],select[class*=\"span\"],textarea[class*=\"span\"],.uneditable-input[class*=\"span\"],.row-fluid input[class*=\"span\"],.row-fluid select[class*=\"span\"],.row-fluid textarea[class*=\"span\"],.row-fluid .uneditable-input[class*=\"span\"]{float:none;margin-left:0;}\n.input-append input[class*=\"span\"],.input-append .uneditable-input[class*=\"span\"],.input-prepend input[class*=\"span\"],.input-prepend .uneditable-input[class*=\"span\"],.row-fluid input[class*=\"span\"],.row-fluid select[class*=\"span\"],.row-fluid textarea[class*=\"span\"],.row-fluid .uneditable-input[class*=\"span\"],.row-fluid .input-prepend [class*=\"span\"],.row-fluid .input-append [class*=\"span\"]{display:inline-block;}\ninput,textarea,.uneditable-input{margin-left:0;}\n.controls-row [class*=\"span\"]+[class*=\"span\"]{margin-left:20px;}\ninput.span12, textarea.span12, .uneditable-input.span12{width:926px;}\ninput.span11, textarea.span11, .uneditable-input.span11{width:846px;}\ninput.span10, textarea.span10, .uneditable-input.span10{width:766px;}\ninput.span9, textarea.span9, .uneditable-input.span9{width:686px;}\ninput.span8, textarea.span8, .uneditable-input.span8{width:606px;}\ninput.span7, textarea.span7, .uneditable-input.span7{width:526px;}\ninput.span6, textarea.span6, .uneditable-input.span6{width:446px;}\ninput.span5, textarea.span5, .uneditable-input.span5{width:366px;}\ninput.span4, textarea.span4, .uneditable-input.span4{width:286px;}\ninput.span3, textarea.span3, .uneditable-input.span3{width:206px;}\ninput.span2, textarea.span2, .uneditable-input.span2{width:126px;}\ninput.span1, textarea.span1, .uneditable-input.span1{width:46px;}\n.controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:\"\";line-height:0;}\n.controls-row:after{clear:both;}\n.controls-row [class*=\"span\"],.row-fluid .controls-row [class*=\"span\"]{float:left;}\n.controls-row .checkbox[class*=\"span\"],.controls-row .radio[class*=\"span\"]{padding-top:5px;}\ninput[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;}\ninput[type=\"radio\"][disabled],input[type=\"checkbox\"][disabled],input[type=\"radio\"][readonly],input[type=\"checkbox\"][readonly]{background-color:transparent;}\n.control-group.warning>label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;}\n.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;}\n.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;}\n.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;}\n.control-group.error>label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;}\n.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;}\n.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;}\n.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;}\n.control-group.success>label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;}\n.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;}\n.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;}\n.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;}\n.control-group.info>label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;}\n.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;}\n.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;}\n.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;}\ninput:focus:required:invalid,textarea:focus:required:invalid,select:focus:required:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:required:invalid:focus,textarea:focus:required:invalid:focus,select:focus:required:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;}\n.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:\"\";line-height:0;}\n.form-actions:after{clear:both;}\n.help-block,.help-inline{color:#595959;}\n.help-block{display:block;margin-bottom:10px;}\n.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;}\n.input-append,.input-prepend{margin-bottom:5px;font-size:0;white-space:nowrap;}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu{font-size:14px;}\n.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2;}\n.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc;}\n.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}\n.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;}\n.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;}\n.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}\n.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}.input-append input+.btn-group .btn,.input-append select+.btn-group .btn,.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}\n.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;}\n.input-append .add-on:last-child,.input-append .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}\n.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}\n.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}\n.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}\n.input-prepend.input-append .btn-group:first-child{margin-left:0;}\ninput.search-query{padding-right:14px;padding-right:4px \\9;padding-left:14px;padding-left:4px \\9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}\n.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}\n.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}\n.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}\n.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;}\n.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;}\n.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle;}\n.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;}\n.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;}\n.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;}\n.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;}\n.form-search .radio input[type=\"radio\"],.form-search .checkbox input[type=\"checkbox\"],.form-inline .radio input[type=\"radio\"],.form-inline .checkbox input[type=\"checkbox\"]{float:left;margin-right:3px;margin-left:0;}\n.control-group{margin-bottom:10px;}\nlegend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;}\n.form-horizontal .control-group{margin-bottom:20px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:\"\";line-height:0;}\n.form-horizontal .control-group:after{clear:both;}\n.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;}\n.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;}\n.form-horizontal .help-block{margin-bottom:0;}\n.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block{margin-top:10px;}\n.form-horizontal .form-actions{padding-left:180px;}\n.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;*line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #bbbbbb;*border:0;border-bottom-color:#a2a2a2;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;}\n.btn:active,.btn.active{background-color:#cccccc \\9;}\n.btn:first-child{*margin-left:0;}\n.btn:hover{color:#333333;text-decoration:none;background-color:#e6e6e6;*background-color:#d9d9d9;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;}\n.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;}\n.btn.active,.btn:active{background-color:#e6e6e6;background-color:#d9d9d9 \\9;background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}\n.btn.disabled,.btn[disabled]{cursor:default;background-color:#e6e6e6;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}\n.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}\n.btn-large [class^=\"icon-\"],.btn-large [class*=\" icon-\"]{margin-top:2px;}\n.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n.btn-small [class^=\"icon-\"],.btn-small [class*=\" icon-\"]{margin-top:0;}\n.btn-mini{padding:1px 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n.btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;}\n.btn-block+.btn-block{margin-top:5px;}\ninput[type=\"submit\"].btn-block,input[type=\"reset\"].btn-block,input[type=\"button\"].btn-block{width:100%;}\n.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);}\n.btn{border-color:#c5c5c5;border-color:rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25);}\n.btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;}\n.btn-primary:active,.btn-primary.active{background-color:#003399 \\9;}\n.btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;}\n.btn-warning:active,.btn-warning.active{background-color:#c67605 \\9;}\n.btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;}\n.btn-danger:active,.btn-danger.active{background-color:#942a25 \\9;}\n.btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;}\n.btn-success:active,.btn-success.active{background-color:#408140 \\9;}\n.btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;}\n.btn-info:active,.btn-info.active{background-color:#24748c \\9;}\n.btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;}\n.btn-inverse:active,.btn-inverse.active{background-color:#080808 \\9;}\nbutton.btn,input[type=\"submit\"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type=\"submit\"].btn::-moz-focus-inner{padding:0;border:0;}\nbutton.btn.btn-large,input[type=\"submit\"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;}\nbutton.btn.btn-small,input[type=\"submit\"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;}\nbutton.btn.btn-mini,input[type=\"submit\"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;}\n.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;}\n.btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}\n.btn-link:hover{color:#005580;text-decoration:underline;background-color:transparent;}\n.btn-link[disabled]:hover{color:#333333;text-decoration:none;}\n[class^=\"icon-\"],[class*=\" icon-\"]{display:inline-block;width:14px;height:14px;*margin-right:.3em;line-height:14px;vertical-align:text-top;background-image:url(http://github.com/%22../img/glyphicons-halflings.png/");background-position:14px 14px;background-repeat:no-repeat;margin-top:1px;}\n.icon-white,.nav-pills>.active>a>[class^=\"icon-\"],.nav-pills>.active>a>[class*=\" icon-\"],.nav-list>.active>a>[class^=\"icon-\"],.nav-list>.active>a>[class*=\" icon-\"],.navbar-inverse .nav>.active>a>[class^=\"icon-\"],.navbar-inverse .nav>.active>a>[class*=\" icon-\"],.dropdown-menu>li>a:hover>[class^=\"icon-\"],.dropdown-menu>li>a:hover>[class*=\" icon-\"],.dropdown-menu>.active>a>[class^=\"icon-\"],.dropdown-menu>.active>a>[class*=\" icon-\"],.dropdown-submenu:hover>a>[class^=\"icon-\"],.dropdown-submenu:hover>a>[class*=\" icon-\"]{background-image:url(http://github.com/%22../img/glyphicons-halflings-white.png/");}\n.icon-glass{background-position:0 0;}\n.icon-music{background-position:-24px 0;}\n.icon-search{background-position:-48px 0;}\n.icon-envelope{background-position:-72px 0;}\n.icon-heart{background-position:-96px 0;}\n.icon-star{background-position:-120px 0;}\n.icon-star-empty{background-position:-144px 0;}\n.icon-user{background-position:-168px 0;}\n.icon-film{background-position:-192px 0;}\n.icon-th-large{background-position:-216px 0;}\n.icon-th{background-position:-240px 0;}\n.icon-th-list{background-position:-264px 0;}\n.icon-ok{background-position:-288px 0;}\n.icon-remove{background-position:-312px 0;}\n.icon-zoom-in{background-position:-336px 0;}\n.icon-zoom-out{background-position:-360px 0;}\n.icon-off{background-position:-384px 0;}\n.icon-signal{background-position:-408px 0;}\n.icon-cog{background-position:-432px 0;}\n.icon-trash{background-position:-456px 0;}\n.icon-home{background-position:0 -24px;}\n.icon-file{background-position:-24px -24px;}\n.icon-time{background-position:-48px -24px;}\n.icon-road{background-position:-72px -24px;}\n.icon-download-alt{background-position:-96px -24px;}\n.icon-download{background-position:-120px -24px;}\n.icon-upload{background-position:-144px -24px;}\n.icon-inbox{background-position:-168px -24px;}\n.icon-play-circle{background-position:-192px -24px;}\n.icon-repeat{background-position:-216px -24px;}\n.icon-refresh{background-position:-240px -24px;}\n.icon-list-alt{background-position:-264px -24px;}\n.icon-lock{background-position:-287px -24px;}\n.icon-flag{background-position:-312px -24px;}\n.icon-headphones{background-position:-336px -24px;}\n.icon-volume-off{background-position:-360px -24px;}\n.icon-volume-down{background-position:-384px -24px;}\n.icon-volume-up{background-position:-408px -24px;}\n.icon-qrcode{background-position:-432px -24px;}\n.icon-barcode{background-position:-456px -24px;}\n.icon-tag{background-position:0 -48px;}\n.icon-tags{background-position:-25px -48px;}\n.icon-book{background-position:-48px -48px;}\n.icon-bookmark{background-position:-72px -48px;}\n.icon-print{background-position:-96px -48px;}\n.icon-camera{background-position:-120px -48px;}\n.icon-font{background-position:-144px -48px;}\n.icon-bold{background-position:-167px -48px;}\n.icon-italic{background-position:-192px -48px;}\n.icon-text-height{background-position:-216px -48px;}\n.icon-text-width{background-position:-240px -48px;}\n.icon-align-left{background-position:-264px -48px;}\n.icon-align-center{background-position:-288px -48px;}\n.icon-align-right{background-position:-312px -48px;}\n.icon-align-justify{background-position:-336px -48px;}\n.icon-list{background-position:-360px -48px;}\n.icon-indent-left{background-position:-384px -48px;}\n.icon-indent-right{background-position:-408px -48px;}\n.icon-facetime-video{background-position:-432px -48px;}\n.icon-picture{background-position:-456px -48px;}\n.icon-pencil{background-position:0 -72px;}\n.icon-map-marker{background-position:-24px -72px;}\n.icon-adjust{background-position:-48px -72px;}\n.icon-tint{background-position:-72px -72px;}\n.icon-edit{background-position:-96px -72px;}\n.icon-share{background-position:-120px -72px;}\n.icon-check{background-position:-144px -72px;}\n.icon-move{background-position:-168px -72px;}\n.icon-step-backward{background-position:-192px -72px;}\n.icon-fast-backward{background-position:-216px -72px;}\n.icon-backward{background-position:-240px -72px;}\n.icon-play{background-position:-264px -72px;}\n.icon-pause{background-position:-288px -72px;}\n.icon-stop{background-position:-312px -72px;}\n.icon-forward{background-position:-336px -72px;}\n.icon-fast-forward{background-position:-360px -72px;}\n.icon-step-forward{background-position:-384px -72px;}\n.icon-eject{background-position:-408px -72px;}\n.icon-chevron-left{background-position:-432px -72px;}\n.icon-chevron-right{background-position:-456px -72px;}\n.icon-plus-sign{background-position:0 -96px;}\n.icon-minus-sign{background-position:-24px -96px;}\n.icon-remove-sign{background-position:-48px -96px;}\n.icon-ok-sign{background-position:-72px -96px;}\n.icon-question-sign{background-position:-96px -96px;}\n.icon-info-sign{background-position:-120px -96px;}\n.icon-screenshot{background-position:-144px -96px;}\n.icon-remove-circle{background-position:-168px -96px;}\n.icon-ok-circle{background-position:-192px -96px;}\n.icon-ban-circle{background-position:-216px -96px;}\n.icon-arrow-left{background-position:-240px -96px;}\n.icon-arrow-right{background-position:-264px -96px;}\n.icon-arrow-up{background-position:-289px -96px;}\n.icon-arrow-down{background-position:-312px -96px;}\n.icon-share-alt{background-position:-336px -96px;}\n.icon-resize-full{background-position:-360px -96px;}\n.icon-resize-small{background-position:-384px -96px;}\n.icon-plus{background-position:-408px -96px;}\n.icon-minus{background-position:-433px -96px;}\n.icon-asterisk{background-position:-456px -96px;}\n.icon-exclamation-sign{background-position:0 -120px;}\n.icon-gift{background-position:-24px -120px;}\n.icon-leaf{background-position:-48px -120px;}\n.icon-fire{background-position:-72px -120px;}\n.icon-eye-open{background-position:-96px -120px;}\n.icon-eye-close{background-position:-120px -120px;}\n.icon-warning-sign{background-position:-144px -120px;}\n.icon-plane{background-position:-168px -120px;}\n.icon-calendar{background-position:-192px -120px;}\n.icon-random{background-position:-216px -120px;width:16px;}\n.icon-comment{background-position:-240px -120px;}\n.icon-magnet{background-position:-264px -120px;}\n.icon-chevron-up{background-position:-288px -120px;}\n.icon-chevron-down{background-position:-313px -119px;}\n.icon-retweet{background-position:-336px -120px;}\n.icon-shopping-cart{background-position:-360px -120px;}\n.icon-folder-close{background-position:-384px -120px;}\n.icon-folder-open{background-position:-408px -120px;width:16px;}\n.icon-resize-vertical{background-position:-432px -119px;}\n.icon-resize-horizontal{background-position:-456px -118px;}\n.icon-hdd{background-position:0 -144px;}\n.icon-bullhorn{background-position:-24px -144px;}\n.icon-bell{background-position:-48px -144px;}\n.icon-certificate{background-position:-72px -144px;}\n.icon-thumbs-up{background-position:-96px -144px;}\n.icon-thumbs-down{background-position:-120px -144px;}\n.icon-hand-right{background-position:-144px -144px;}\n.icon-hand-left{background-position:-168px -144px;}\n.icon-hand-up{background-position:-192px -144px;}\n.icon-hand-down{background-position:-216px -144px;}\n.icon-circle-arrow-right{background-position:-240px -144px;}\n.icon-circle-arrow-left{background-position:-264px -144px;}\n.icon-circle-arrow-up{background-position:-288px -144px;}\n.icon-circle-arrow-down{background-position:-312px -144px;}\n.icon-globe{background-position:-336px -144px;}\n.icon-wrench{background-position:-360px -144px;}\n.icon-tasks{background-position:-384px -144px;}\n.icon-filter{background-position:-408px -144px;}\n.icon-briefcase{background-position:-432px -144px;}\n.icon-fullscreen{background-position:-456px -144px;}\n.btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em;}.btn-group:first-child{*margin-left:0;}\n.btn-group+.btn-group{margin-left:5px;}\n.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px;}.btn-toolbar .btn+.btn,.btn-toolbar .btn-group+.btn,.btn-toolbar .btn+.btn-group{margin-left:5px;}\n.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}\n.btn-group>.btn+.btn{margin-left:-1px;}\n.btn-group>.btn,.btn-group>.dropdown-menu{font-size:14px;}\n.btn-group>.btn-mini{font-size:11px;}\n.btn-group>.btn-small{font-size:12px;}\n.btn-group>.btn-large{font-size:16px;}\n.btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}\n.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}\n.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}\n.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}\n.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;}\n.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;}\n.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px;}\n.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;}\n.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;}\n.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;}\n.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);}\n.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;}\n.btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;}\n.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;}\n.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;}\n.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;}\n.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;}\n.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;}\n.btn .caret{margin-top:8px;margin-left:0;}\n.btn-mini .caret,.btn-small .caret,.btn-large .caret{margin-top:6px;}\n.btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;}\n.dropup .btn-large .caret{border-bottom-width:5px;}\n.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}\n.btn-group-vertical{display:inline-block;*display:inline;*zoom:1;}\n.btn-group-vertical .btn{display:block;float:none;width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}\n.btn-group-vertical .btn+.btn{margin-left:0;margin-top:-1px;}\n.btn-group-vertical .btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}\n.btn-group-vertical .btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}\n.btn-group-vertical .btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;}\n.btn-group-vertical .btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}\n.nav{margin-left:0;margin-bottom:20px;list-style:none;}\n.nav>li>a{display:block;}\n.nav>li>a:hover{text-decoration:none;background-color:#eeeeee;}\n.nav>.pull-right{float:right;}\n.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;}\n.nav li+.nav-header{margin-top:9px;}\n.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;}\n.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);}\n.nav-list>li>a{padding:3px 15px;}\n.nav-list>.active>a,.nav-list>.active>a:hover{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;}\n.nav-list [class^=\"icon-\"],.nav-list [class*=\" icon-\"]{margin-right:2px;}\n.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}\n.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:\"\";line-height:0;}\n.nav-tabs:after,.nav-pills:after{clear:both;}\n.nav-tabs>li,.nav-pills>li{float:left;}\n.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;}\n.nav-tabs{border-bottom:1px solid #ddd;}\n.nav-tabs>li{margin-bottom:-1px;}\n.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #dddddd;}\n.nav-tabs>.active>a,.nav-tabs>.active>a:hover{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;}\n.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;}\n.nav-pills>.active>a,.nav-pills>.active>a:hover{color:#ffffff;background-color:#0088cc;}\n.nav-stacked>li{float:none;}\n.nav-stacked>li>a{margin-right:0;}\n.nav-tabs.nav-stacked{border-bottom:0;}\n.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}\n.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;}\n.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}\n.nav-tabs.nav-stacked>li>a:hover{border-color:#ddd;z-index:2;}\n.nav-pills.nav-stacked>li>a{margin-bottom:3px;}\n.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;}\n.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;}\n.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}\n.nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;}\n.nav .dropdown-toggle:hover .caret{border-top-color:#005580;border-bottom-color:#005580;}\n.nav-tabs .dropdown-toggle .caret{margin-top:8px;}\n.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;}\n.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;}\n.nav>.dropdown.active>a:hover{cursor:pointer;}\n.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover{color:#ffffff;background-color:#999999;border-color:#999999;}\n.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);}\n.tabs-stacked .open>a:hover{border-color:#999999;}\n.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:\"\";line-height:0;}\n.tabbable:after{clear:both;}\n.tab-content{overflow:auto;}\n.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;}\n.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;}\n.tab-content>.active,.pill-content>.active{display:block;}\n.tabs-below>.nav-tabs{border-top:1px solid #ddd;}\n.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;}\n.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover{border-bottom-color:transparent;border-top-color:#ddd;}\n.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover{border-color:transparent #ddd #ddd #ddd;}\n.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;}\n.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;}\n.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;}\n.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}\n.tabs-left>.nav-tabs>li>a:hover{border-color:#eeeeee #dddddd #eeeeee #eeeeee;}\n.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;}\n.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;}\n.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}\n.tabs-right>.nav-tabs>li>a:hover{border-color:#eeeeee #eeeeee #eeeeee #dddddd;}\n.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;}\n.nav>.disabled>a{color:#999999;}\n.nav>.disabled>a:hover{text-decoration:none;background-color:transparent;cursor:default;}\n.navbar{overflow:visible;margin-bottom:20px;color:#777777;*position:relative;*z-index:2;}\n.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:\"\";line-height:0;}\n.navbar-inner:after{clear:both;}\n.navbar .container{width:auto;}\n.nav-collapse.collapse{height:auto;overflow:visible;}\n.navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover{text-decoration:none;}\n.navbar-text{margin-bottom:0;line-height:40px;}\n.navbar-link{color:#777777;}.navbar-link:hover{color:#333333;}\n.navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;}\n.navbar .btn,.navbar .btn-group{margin-top:5px;}\n.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn{margin-top:0;}\n.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:\"\";line-height:0;}\n.navbar-form:after{clear:both;}\n.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;}\n.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;}\n.navbar-form input[type=\"image\"],.navbar-form input[type=\"checkbox\"],.navbar-form input[type=\"radio\"]{margin-top:3px;}\n.navbar-form .input-append,.navbar-form .input-prepend{margin-top:6px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;}\n.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0;}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:\"Helvetica Neue\",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}\n.navbar-static-top{position:static;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}\n.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;}\n.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;}\n.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;}\n.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}\n.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;}\n.navbar-fixed-top{top:0;}\n.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1);}\n.navbar-fixed-bottom{bottom:0;}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1);}\n.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;}\n.navbar .nav.pull-right{float:right;margin-right:0;}\n.navbar .nav>li{float:left;}\n.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;}\n.navbar .nav .dropdown-toggle .caret{margin-top:8px;}\n.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;}\n.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);}\n.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);}.navbar .btn-navbar:hover,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;}\n.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \\9;}\n.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);}\n.btn-navbar .icon-bar+.icon-bar{margin-top:3px;}\n.navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;}\n.navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;}\n.navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;}\n.navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;}\n.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555555;}\n.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;}\n.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;}\n.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0;}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px;}\n.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;}\n.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}\n.navbar-inverse{color:#999999;}.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;}\n.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover{color:#ffffff;}\n.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;}\n.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;}\n.navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover{color:#ffffff;}\n.navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;}\n.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111111;color:#ffffff;}\n.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;}\n.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;}\n.navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none;}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#cccccc;}\n.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;}\n.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;}\n.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;}\n.navbar-inverse .btn-navbar{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;}\n.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \\9;}\n.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.breadcrumb li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}\n.breadcrumb .divider{padding:0 5px;color:#ccc;}\n.breadcrumb .active{color:#999999;}\n.pagination{margin:20px 0;}\n.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);}\n.pagination ul>li{display:inline;}\n.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;}\n.pagination ul>li>a:hover,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;}\n.pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;}\n.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover{color:#999999;background-color:transparent;cursor:default;}\n.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;}\n.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;}\n.pagination-centered{text-align:center;}\n.pagination-right{text-align:right;}\n.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px;}\n.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;}\n.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;}\n.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px;}\n.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px;}\n.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px;}\n.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:1px 6px;font-size:10.5px;}\n.pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:\"\";line-height:0;}\n.pager:after{clear:both;}\n.pager li{display:inline;}\n.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;}\n.pager li>a:hover{text-decoration:none;background-color:#f5f5f5;}\n.pager .next>a,.pager .next>span{float:right;}\n.pager .previous>a,.pager .previous>span{float:left;}\n.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>span{color:#999999;background-color:#fff;cursor:default;}\n.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:\"\";line-height:0;}\n.thumbnails:after{clear:both;}\n.row-fluid .thumbnails{margin-left:0;}\n.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;}\n.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;}\na.thumbnail:hover{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);}\n.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;}\n.thumbnail .caption{padding:9px;color:#555555;}\n.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;color:#c09853;}\n.alert h4{margin:0;}\n.alert .close{position:relative;top:-2px;right:-21px;line-height:20px;}\n.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;}\n.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;}\n.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;}\n.alert-block{padding-top:14px;padding-bottom:14px;}\n.alert-block>p,.alert-block>ul{margin-bottom:0;}\n.alert-block p+p{margin-top:5px;}\n@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-o-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}\n.progress .bar{width:0%;height:100%;color:#ffffff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;}\n.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);}\n.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;}\n.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;}\n.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);}\n.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}\n.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);}\n.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}\n.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);}\n.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}\n.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);}\n.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);}\n.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;}\n.hero-unit li{line-height:30px;}\n.media,.media-body{overflow:hidden;*overflow:visible;zoom:1;}\n.media,.media .media{margin-top:15px;}\n.media:first-child{margin-top:0;}\n.media-object{display:block;}\n.media-heading{margin:0 0 5px;}\n.media .pull-left{margin-right:10px;}\n.media .pull-right{margin-left:10px;}\n.media-list{margin-left:0;list-style:none;}\n.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;padding:5px;font-size:11px;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);}\n.tooltip.top{margin-top:-3px;}\n.tooltip.right{margin-left:3px;}\n.tooltip.bottom{margin-top:3px;}\n.tooltip.left{margin-left:-3px;}\n.tooltip-inner{max-width:200px;padding:3px 8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}\n.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;}\n.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;}\n.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;}\n.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;}\n.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;}\n.popover{position:absolute;top:0;left:0;z-index:1010;display:none;width:236px;padding:1px;background-color:#ffffff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);}.popover.top{margin-top:-10px;}\n.popover.right{margin-left:10px;}\n.popover.bottom{margin-top:10px;}\n.popover.left{margin-left:-10px;}\n.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}\n.popover-content{padding:9px 14px;}.popover-content p,.popover-content ul,.popover-content ol{margin-bottom:0;}\n.popover .arrow,.popover .arrow:after{position:absolute;display:inline-block;width:0;height:0;border-color:transparent;border-style:solid;}\n.popover .arrow:after{content:\"\";z-index:-1;}\n.popover.top .arrow{bottom:-10px;left:50%;margin-left:-10px;border-width:10px 10px 0;border-top-color:#ffffff;}.popover.top .arrow:after{border-width:11px 11px 0;border-top-color:rgba(0, 0, 0, 0.25);bottom:-1px;left:-11px;}\n.popover.right .arrow{top:50%;left:-10px;margin-top:-10px;border-width:10px 10px 10px 0;border-right-color:#ffffff;}.popover.right .arrow:after{border-width:11px 11px 11px 0;border-right-color:rgba(0, 0, 0, 0.25);bottom:-11px;left:-1px;}\n.popover.bottom .arrow{top:-10px;left:50%;margin-left:-10px;border-width:0 10px 10px;border-bottom-color:#ffffff;}.popover.bottom .arrow:after{border-width:0 11px 11px;border-bottom-color:rgba(0, 0, 0, 0.25);top:-1px;left:-11px;}\n.popover.left .arrow{top:50%;right:-10px;margin-top:-10px;border-width:10px 0 10px 10px;border-left-color:#ffffff;}.popover.left .arrow:after{border-width:11px 0 11px 11px;border-left-color:rgba(0, 0, 0, 0.25);bottom:-11px;right:-1px;}\n.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;}\n.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);}\n.modal{position:fixed;top:50%;left:50%;z-index:1050;width:560px;margin:-250px 0 0 -280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;}\n.modal.fade.in{top:50%;}\n.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;}\n.modal-header h3{margin:0;line-height:30px;}\n.modal-body{overflow-y:auto;max-height:400px;padding:15px;}\n.modal-form{margin-bottom:0;}\n.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:\"\";line-height:0;}\n.modal-footer:after{clear:both;}\n.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;}\n.modal-footer .btn-group .btn+.btn{margin-left:-1px;}\n.modal-footer .btn-block+.btn-block{margin-left:0;}\n.dropup,.dropdown{position:relative;}\n.dropdown-toggle{*margin-bottom:-3px;}\n.dropdown-toggle:active,.open .dropdown-toggle{outline:0;}\n.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:\"\";}\n.dropdown .caret{margin-top:8px;margin-left:2px;}\n.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}.dropdown-menu.pull-right{right:0;left:auto;}\n.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;}\n.dropdown-menu li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;}\n.dropdown-menu li>a:hover,.dropdown-menu li>a:focus,.dropdown-submenu:hover>a{text-decoration:none;color:#ffffff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}\n.dropdown-menu .active>a,.dropdown-menu .active>a:hover{color:#333333;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);}\n.dropdown-menu .disabled>a,.dropdown-menu .disabled>a:hover{color:#999999;}\n.dropdown-menu .disabled>a:hover{text-decoration:none;background-color:transparent;background-image:none;cursor:default;}\n.open{*z-index:1000;}.open >.dropdown-menu{display:block;}\n.pull-right>.dropdown-menu{right:0;left:auto;}\n.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:\"\";}\n.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;}\n.dropdown-submenu{position:relative;}\n.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;}\n.dropdown-submenu:hover>.dropdown-menu{display:block;}\n.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0;}\n.dropdown-submenu>a:after{display:block;content:\" \";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;}\n.dropdown-submenu:hover>a:after{border-left-color:#ffffff;}\n.dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;}\n.dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;}\n.typeahead{margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}\n.accordion{margin-bottom:20px;}\n.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}\n.accordion-heading{border-bottom:0;}\n.accordion-heading .accordion-toggle{display:block;padding:8px 15px;}\n.accordion-toggle{cursor:pointer;}\n.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;}\n.carousel{position:relative;margin-bottom:20px;line-height:1;}\n.carousel-inner{overflow:hidden;width:100%;position:relative;}\n.carousel .item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}\n.carousel .item>img{display:block;line-height:1;}\n.carousel .active,.carousel .next,.carousel .prev{display:block;}\n.carousel .active{left:0;}\n.carousel .next,.carousel .prev{position:absolute;top:0;width:100%;}\n.carousel .next{left:100%;}\n.carousel .prev{left:-100%;}\n.carousel .next.left,.carousel .prev.right{left:0;}\n.carousel .active.left{left:-100%;}\n.carousel .active.right{left:100%;}\n.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;}\n.carousel-control:hover{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);}\n.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);}\n.carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;}\n.carousel-caption h4{margin:0 0 5px;}\n.carousel-caption p{margin-bottom:0;}\n.media,.media-body{overflow:hidden;*overflow:visible;zoom:1;}\n.media,.media .media{margin-top:15px;}\n.media:first-child{margin-top:0;}\n.media-object{display:block;}\n.media-heading{margin:0 0 5px;}\n.media .pull-left{margin-right:10px;}\n.media .pull-right{margin-left:10px;}\n.media-list{margin-left:0;list-style:none;}\n.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);}\n.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}\n.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;}\n.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);}\nbutton.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;}\n.pull-right{float:right;}\n.pull-left{float:left;}\n.hide{display:none;}\n.show{display:block;}\n.invisible{visibility:hidden;}\n.affix{position:fixed;}\n.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;}\n.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;}\n.hidden{display:none;visibility:hidden;}\n.visible-phone{display:none !important;}\n.visible-tablet{display:none !important;}\n.hidden-desktop{display:none !important;}\n.visible-desktop{display:inherit !important;}\n@media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important ;} .visible-tablet{display:inherit !important;} .hidden-tablet{display:none !important;}}@media (max-width:767px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important;} .visible-phone{display:inherit !important;} .hidden-phone{display:none !important;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px;} .container-fluid{padding:0;} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left;} .dl-horizontal dd{margin-left:0;} .container{width:auto;} .row-fluid{width:100%;} .row,.thumbnails{margin-left:0;} .thumbnails>li{float:none;margin-left:0;} [class*=\"span\"],.uneditable-input[class*=\"span\"],.row-fluid [class*=\"span\"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .row-fluid [class*=\"offset\"]:first-child{margin-left:0;} .input-large,.input-xlarge,.input-xxlarge,input[class*=\"span\"],select[class*=\"span\"],textarea[class*=\"span\"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .input-prepend input,.input-append input,.input-prepend input[class*=\"span\"],.input-append input[class*=\"span\"]{display:inline-block;width:auto;} .controls-row [class*=\"span\"]+[class*=\"span\"]{margin-left:0;} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0;}.modal.fade{top:-100px;} .modal.fade.in{top:20px;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:20px;} input[type=\"checkbox\"],input[type=\"radio\"]{border:1px solid #ccc;} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px;} .media-object{margin-right:0;margin-left:0;} .modal{top:10px;left:10px;right:10px;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:\"\";line-height:0;} .row:after{clear:both;} [class*=\"span\"]{float:left;min-height:1px;margin-left:20px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:\"\";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*=\"span\"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;} .row-fluid [class*=\"span\"]:first-child{margin-left:0;} .row-fluid .controls-row [class*=\"span\"]+[class*=\"span\"]{margin-left:2.7624309392265194%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%;} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%;} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%;} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%;} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%;} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%;} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%;} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%;} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%;} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%;} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%;} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%;} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%;} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%;} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%;} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%;} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%;} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%;} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%;} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%;} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%;} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%;} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%;} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%;} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%;} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%;} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%;} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%;} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%;} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%;} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%;} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%;} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%;} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%;} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*=\"span\"]+[class*=\"span\"]{margin-left:20px;} input.span12, textarea.span12, .uneditable-input.span12{width:710px;} input.span11, textarea.span11, .uneditable-input.span11{width:648px;} input.span10, textarea.span10, .uneditable-input.span10{width:586px;} input.span9, textarea.span9, .uneditable-input.span9{width:524px;} input.span8, textarea.span8, .uneditable-input.span8{width:462px;} input.span7, textarea.span7, .uneditable-input.span7{width:400px;} input.span6, textarea.span6, .uneditable-input.span6{width:338px;} input.span5, textarea.span5, .uneditable-input.span5{width:276px;} input.span4, textarea.span4, .uneditable-input.span4{width:214px;} input.span3, textarea.span3, .uneditable-input.span3{width:152px;} input.span2, textarea.span2, .uneditable-input.span2{width:90px;} input.span1, textarea.span1, .uneditable-input.span1{width:28px;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:\"\";line-height:0;} .row:after{clear:both;} [class*=\"span\"]{float:left;min-height:1px;margin-left:30px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:\"\";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*=\"span\"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;} .row-fluid [class*=\"span\"]:first-child{margin-left:0;} .row-fluid .controls-row [class*=\"span\"]+[class*=\"span\"]{margin-left:2.564102564102564%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%;} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%;} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%;} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%;} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%;} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%;} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%;} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%;} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%;} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%;} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%;} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%;} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%;} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%;} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%;} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%;} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%;} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%;} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%;} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%;} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%;} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%;} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%;} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%;} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%;} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%;} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%;} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%;} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%;} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%;} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%;} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%;} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%;} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%;} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*=\"span\"]+[class*=\"span\"]{margin-left:30px;} input.span12, textarea.span12, .uneditable-input.span12{width:1156px;} input.span11, textarea.span11, .uneditable-input.span11{width:1056px;} input.span10, textarea.span10, .uneditable-input.span10{width:956px;} input.span9, textarea.span9, .uneditable-input.span9{width:856px;} input.span8, textarea.span8, .uneditable-input.span8{width:756px;} input.span7, textarea.span7, .uneditable-input.span7{width:656px;} input.span6, textarea.span6, .uneditable-input.span6{width:556px;} input.span5, textarea.span5, .uneditable-input.span5{width:456px;} input.span4, textarea.span4, .uneditable-input.span4{width:356px;} input.span3, textarea.span3, .uneditable-input.span3{width:256px;} input.span2, textarea.span2, .uneditable-input.span2{width:156px;} input.span1, textarea.span1, .uneditable-input.span1{width:56px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;} .row-fluid .thumbnails{margin-left:0;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top,.navbar-fixed-bottom{position:static;} .navbar-fixed-top{margin-bottom:20px;} .navbar-fixed-bottom{margin-top:20px;} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .nav-collapse{clear:both;} .nav-collapse .nav{float:none;margin:0 0 10px;} .nav-collapse .nav>li{float:none;} .nav-collapse .nav>li>a{margin-bottom:2px;} .nav-collapse .nav>.divider-vertical{display:none;} .nav-collapse .nav .nav-header{color:#777777;text-shadow:none;} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px;} .nav-collapse .nav>li>a:hover,.nav-collapse .dropdown-menu a:hover{background-color:#f2f2f2;} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999999;} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:hover{background-color:#111111;} .nav-collapse.in .btn-group{margin-top:5px;padding:0;} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .nav-collapse .open>.dropdown-menu{display:block;} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none;} .nav-collapse .dropdown-menu .divider{display:none;} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none;} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111111;border-bottom-color:#111111;} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0;} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0;} .navbar .btn-navbar{display:block;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}}\n")) - template.Must(CSS.New("common.css").Parse("#chord_container {\n width: 100%;\n text-align: center;\n position: absolute;\n z-index: -10;\n}\n#chord {\n margin: auto;\n width: 1200px;\n height: 800px;\n}\n#nodes_container {\n float: right;\n font-family: \"Courier\";\n}\n#node_container {\n display: none;\n float: left;\n font-family: \"Courier\";\n}\n.node {\n cursor: pointer;\n}\n#code {\n width: 30em;\n height: 20em;\n}\n#execute {\n display: block;\n}\n")) + template.Must(CSS.New("common.css").Parse("#chord_container {\n width: 100%;\n text-align: center;\n position: absolute;\n z-index: -10;\n}\n#chord {\n margin: auto;\n width: 1200px;\n height: 800px;\n}\n#nodes_container {\n float: right;\n font-family: \"Courier\";\n}\n#nodes {\n background-color: rgba(255,255,255,0.9);\n border: 1px solid black;\n}\n#node_container {\n display: none;\n float: left;\n font-family: \"Courier\";\n}\n.node {\n cursor: pointer;\n}\n#code {\n width: 30em;\n height: 20em;\n}\n#execute {\n display: block;\n}\n")) } diff --git a/templates/css/common.css b/templates/css/common.css index 3ee853c..db798e0 100644 --- a/templates/css/common.css +++ b/templates/css/common.css @@ -1,30 +1,34 @@ #chord_container { - width: 100%; - text-align: center; - position: absolute; - z-index: -10; + width: 100%; + text-align: center; + position: absolute; + z-index: -10; } #chord { - margin: auto; - width: 1200px; - height: 800px; + margin: auto; + width: 1200px; + height: 800px; } #nodes_container { float: right; - font-family: "Courier"; + font-family: "Courier"; +} +#nodes { + background-color: rgba(255,255,255,0.9); + border: 1px solid black; } #node_container { - display: none; - float: left; - font-family: "Courier"; + display: none; + float: left; + font-family: "Courier"; } .node { - cursor: pointer; + cursor: pointer; } #code { - width: 30em; - height: 20em; + width: 30em; + height: 20em; } #execute { - display: block; + display: block; } diff --git a/templates/html.go b/templates/html.go index f807384..c937367 100644 --- a/templates/html.go +++ b/templates/html.go @@ -2,5 +2,5 @@ package templates import "html/template" var HTML = template.New("html") func init() { - template.Must(HTML.New("index.html").Parse("\n \n \n Go Database! Manager\n \n \n \n \n \n \n \n \n \n
\n \n
\n
\n \n \n \n \n \n \n
nodes
addressposition
\n

Architectural documentation

\n

Go client API documentation

\n
\n
\n \n
\n
\n \n Endpoint\n \n \n
    \n
\n
\n
\n
\n
\n
\n
\n
\n
\n ×\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
node
gob rpc address
JSON/HTTP rpc address
position
owned keys
held keys
load
\n
\n \n\n")) + template.Must(HTML.New("index.html").Parse("\n \n \n Go Database! Manager\n \n \n \n \n \n \n \n\n \n
\n \n
\n
\n \n \n \n \n \n \n
nodes
addressposition
\n

Architectural documentation

\n

Go client API documentation

\n
\n
\n \n
\n
\n \n Endpoint\n \n \n
    \n
\n
\n
\n
\n
\n
\n
\n
\n
\n ×\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n
node
gob rpc address
JSON/HTTP rpc address
position
owned keys
held keys
load
\n
\n\n\n")) } diff --git a/templates/html/index.html b/templates/html/index.html index 3297096..95b0369 100644 --- a/templates/html/index.html +++ b/templates/html/index.html @@ -1,86 +1,86 @@ - - - Go Database! Manager - - - - - - - - - -
- -
-
- - - - - - -
nodes
addressposition
-

Architectural documentation

-

Go client API documentation

-
-
- -
- -
-
-
-
-
-
-
- × - - - - - - - - - - - - - - - - - - - - - - - - - - -
node
gob rpc address
JSON/HTTP rpc address
position
owned keys
held keys
load
-
- + + + + + + + + +
+ +
+
+ + + + + + +
nodes
addressposition
+

Architectural documentation

+

Go client API documentation

+
+
+ +
+ +
+
+
+
+
+
+
+ × + + + + + + + + + + + + + + + + + + + + + + + + + + +
node
gob rpc address
JSON/HTTP rpc address
position
owned keys
held keys
load
+
+ diff --git a/templates/templates.go b/templates/templates.go index 392100a..6d438d1 100644 --- a/templates/templates.go +++ b/templates/templates.go @@ -1,4 +1,4 @@ package templates const ( - Timestamp = 1357893161292766000 + Timestamp = 1371395444937947947 ) diff --git a/timenet/README.md b/timenet/README.md index 1c15701..26b21c2 100644 --- a/timenet/README.md +++ b/timenet/README.md @@ -1,4 +1,4 @@ timenet === -A simple timing network where all nodes randomly contacts each other to synchronize their times. +A simple timing network where all nodes randomly contact each other to synchronize their times. diff --git a/timenet/timenet_test.go b/timenet/timenet_test.go index ffa1c13..051f235 100644 --- a/timenet/timenet_test.go +++ b/timenet/timenet_test.go @@ -2,11 +2,12 @@ package timenet import ( "fmt" - "github.com/zond/god/common" "math" "math/rand" "testing" "time" + + "github.com/zond/god/common" ) func init() { @@ -78,5 +79,5 @@ func TestSample(t *testing.T) { common.AssertWithin(t, func() (string, bool) { d := producer.deviance() return fmt.Sprint(d), d > 0 && d < 1000000 - }, time.Second*10) + }, time.Second*20) }