chord_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. package chord_test
  2. import (
  3. "runtime"
  4. "testing"
  5. "time"
  6. "trial/chord"
  7. )
  8. type MultiLocalTrans struct {
  9. remote chord.Transport
  10. hosts map[string]*chord.LocalTransport
  11. }
  12. func InitMLTransport() *MultiLocalTrans {
  13. hosts := make(map[string]*chord.LocalTransport)
  14. remote := &chord.BlackholeTransport{}
  15. ml := &MultiLocalTrans{hosts: hosts}
  16. ml.remote = remote
  17. return ml
  18. }
  19. func (ml *MultiLocalTrans) ListVnodes(host string) ([]*chord.Vnode, error) {
  20. if local, ok := ml.hosts[host]; ok {
  21. return local.ListVnodes(host)
  22. }
  23. return ml.remote.ListVnodes(host)
  24. }
  25. // Ping a Vnode, check for liveness
  26. func (ml *MultiLocalTrans) Ping(v *chord.Vnode) (bool, error) {
  27. if local, ok := ml.hosts[v.Host]; ok {
  28. return local.Ping(v)
  29. }
  30. return ml.remote.Ping(v)
  31. }
  32. // Request a nodes predecessor
  33. func (ml *MultiLocalTrans) GetPredecessor(v *chord.Vnode) (*chord.Vnode, error) {
  34. if local, ok := ml.hosts[v.Host]; ok {
  35. return local.GetPredecessor(v)
  36. }
  37. return ml.remote.GetPredecessor(v)
  38. }
  39. // Notify our successor of ourselves
  40. func (ml *MultiLocalTrans) Notify(target, self *chord.Vnode) ([]*chord.Vnode, error) {
  41. if local, ok := ml.hosts[target.Host]; ok {
  42. return local.Notify(target, self)
  43. }
  44. return ml.remote.Notify(target, self)
  45. }
  46. // Find a successor
  47. func (ml *MultiLocalTrans) FindSuccessors(v *chord.Vnode, n int, k []byte) ([]*chord.Vnode, error) {
  48. if local, ok := ml.hosts[v.Host]; ok {
  49. return local.FindSuccessors(v, n, k)
  50. }
  51. return ml.remote.FindSuccessors(v, n, k)
  52. }
  53. // Clears a predecessor if it matches a given vnode. Used to leave.
  54. func (ml *MultiLocalTrans) ClearPredecessor(target, self *chord.Vnode) error {
  55. if local, ok := ml.hosts[target.Host]; ok {
  56. return local.ClearPredecessor(target, self)
  57. }
  58. return ml.remote.ClearPredecessor(target, self)
  59. }
  60. // Instructs a node to skip a given successor. Used to leave.
  61. func (ml *MultiLocalTrans) SkipSuccessor(target, self *chord.Vnode) error {
  62. if local, ok := ml.hosts[target.Host]; ok {
  63. return local.SkipSuccessor(target, self)
  64. }
  65. return ml.remote.SkipSuccessor(target, self)
  66. }
  67. func (ml *MultiLocalTrans) Register(v *chord.Vnode, o chord.VnodeRPC) {
  68. local, ok := ml.hosts[v.Host]
  69. if !ok {
  70. local = chord.InitLocalTransport(nil).(*chord.LocalTransport)
  71. ml.hosts[v.Host] = local
  72. }
  73. local.Register(v, o)
  74. }
  75. func (ml *MultiLocalTrans) Deregister(host string) {
  76. delete(ml.hosts, host)
  77. }
  78. func TestDefaultConfig(t *testing.T) {
  79. conf := chord.DefaultConfig("test")
  80. if conf.Hostname != "test" {
  81. t.Fatalf("bad hostname")
  82. }
  83. if conf.NumVnodes != 8 {
  84. t.Fatalf("bad num Vnodes")
  85. }
  86. if conf.NumSuccessors != 8 {
  87. t.Fatalf("bad num succ")
  88. }
  89. if conf.HashFunc == nil {
  90. t.Fatalf("bad hash")
  91. }
  92. if conf.HashBits != 160 {
  93. t.Fatalf("bad hash bits")
  94. }
  95. if conf.StabilizeMin != time.Duration(15*time.Second) {
  96. t.Fatalf("bad min stable")
  97. }
  98. if conf.StabilizeMax != time.Duration(45*time.Second) {
  99. t.Fatalf("bad max stable")
  100. }
  101. if conf.Delegate != nil {
  102. t.Fatalf("bad delegate")
  103. }
  104. }
  105. func fastConf() *chord.Config {
  106. conf := chord.DefaultConfig("test")
  107. conf.StabilizeMin = time.Duration(15 * time.Millisecond)
  108. conf.StabilizeMax = time.Duration(45 * time.Millisecond)
  109. return conf
  110. }
  111. func TestCreateShutdown(t *testing.T) {
  112. // Start the timer thread
  113. time.After(15)
  114. conf := fastConf()
  115. numGo := runtime.NumGoroutine()
  116. r, err := chord.Create(conf, nil)
  117. if err != nil {
  118. t.Fatalf("unexpected err. %s", err)
  119. }
  120. r.Shutdown()
  121. after := runtime.NumGoroutine()
  122. if after != numGo {
  123. t.Fatalf("unexpected routines! A:%d B:%d", after, numGo)
  124. }
  125. }
  126. func TestJoin(t *testing.T) {
  127. // Create a multi transport
  128. ml := InitMLTransport()
  129. // Create the initial ring
  130. conf := fastConf()
  131. r, err := chord.Create(conf, ml)
  132. if err != nil {
  133. t.Fatalf("unexpected err. %s", err)
  134. }
  135. // Create a second ring
  136. conf2 := fastConf()
  137. conf2.Hostname = "test2"
  138. r2, err := chord.Join(conf2, ml, "test")
  139. if err != nil {
  140. t.Fatalf("failed to join local node! Got %s", err)
  141. }
  142. // Shutdown
  143. r.Shutdown()
  144. r2.Shutdown()
  145. }
  146. func TestJoinDeadHost(t *testing.T) {
  147. // Create a multi transport
  148. ml := InitMLTransport()
  149. // Create the initial ring
  150. conf := fastConf()
  151. _, err := chord.Join(conf, ml, "noop")
  152. if err == nil {
  153. t.Fatalf("expected err!")
  154. }
  155. }
  156. func TestLeave(t *testing.T) {
  157. // Create a multi transport
  158. ml := InitMLTransport()
  159. // Create the initial ring
  160. conf := fastConf()
  161. r, err := chord.Create(conf, ml)
  162. if err != nil {
  163. t.Fatalf("unexpected err. %s", err)
  164. }
  165. // Create a second ring
  166. conf2 := fastConf()
  167. conf2.Hostname = "test2"
  168. r2, err := chord.Join(conf2, ml, "test")
  169. if err != nil {
  170. t.Fatalf("failed to join local node! Got %s", err)
  171. }
  172. // Wait for some stabilization
  173. <-time.After(100 * time.Millisecond)
  174. // Node 1 should leave
  175. r.Leave()
  176. ml.Deregister("test")
  177. // Wait for stabilization
  178. <-time.After(100 * time.Millisecond)
  179. // Verify r2 ring is still in tact
  180. num := len(r2.Vnodes)
  181. for idx, vn := range r2.Vnodes {
  182. if vn.Successors[0] != &r2.Vnodes[(idx+1)%num].Vnode {
  183. t.Fatalf("bad successor! Got:%s:%s", vn.Successors[0].Host,
  184. vn.Successors[0])
  185. }
  186. }
  187. }
  188. func TestLookupBadN(t *testing.T) {
  189. // Create a multi transport
  190. ml := InitMLTransport()
  191. // Create the initial ring
  192. conf := fastConf()
  193. r, err := chord.Create(conf, ml)
  194. if err != nil {
  195. t.Fatalf("unexpected err. %s", err)
  196. }
  197. _, err = r.Lookup(10, []byte("test"))
  198. if err == nil {
  199. t.Fatalf("expected err!")
  200. }
  201. }
  202. func TestLookup(t *testing.T) {
  203. // Create a multi transport
  204. ml := InitMLTransport()
  205. // Create the initial ring
  206. conf := fastConf()
  207. r, err := chord.Create(conf, ml)
  208. if err != nil {
  209. t.Fatalf("unexpected err. %s", err)
  210. }
  211. // Create a second ring
  212. conf2 := fastConf()
  213. conf2.Hostname = "test2"
  214. r2, err := chord.Join(conf2, ml, "test")
  215. if err != nil {
  216. t.Fatalf("failed to join local node! Got %s", err)
  217. }
  218. // Wait for some stabilization
  219. <-time.After(100 * time.Millisecond)
  220. // Try key lookup
  221. keys := [][]byte{[]byte("test"), []byte("foo"), []byte("bar")}
  222. for _, k := range keys {
  223. vn1, err := r.Lookup(3, k)
  224. if err != nil {
  225. t.Fatalf("unexpected err %s", err)
  226. }
  227. vn2, err := r2.Lookup(3, k)
  228. if err != nil {
  229. t.Fatalf("unexpected err %s", err)
  230. }
  231. if len(vn1) != len(vn2) {
  232. t.Fatalf("result len differs!")
  233. }
  234. for idx := range vn1 {
  235. if vn1[idx].String() != vn2[idx].String() {
  236. t.Fatalf("results differ!")
  237. }
  238. }
  239. }
  240. }