distributiontable.go 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package cluster
  11. import (
  12. "bytes"
  13. "errors"
  14. "fmt"
  15. "math"
  16. )
  17. /*
  18. defaultDistributionRange is the default range of possible addresses for any cluster.
  19. Depending on the cluster size each member is in charge of a certain part of this range.
  20. */
  21. var defaultDistributionRange = uint64(math.MaxUint64)
  22. /*
  23. DistributionTable is used to locate data in a cluster. The table contains
  24. all cluster members and can identify replication members for given data locations.
  25. */
  26. type DistributionTable struct {
  27. members []string // All known cluster members
  28. memberRange uint64 // Range for a single member
  29. distrange []uint64 // Distribution range among members
  30. mranges map[string]uint64 // Map member ranges
  31. replicas map[string][]string // Map of replicas (which members a replicas of a member)
  32. replicates map[string][]string // Map of replicates (what is replicated on a member)
  33. repFac int // Replication factor of the cluster
  34. space uint64 // Address space which is distributed in the cluster
  35. }
  36. /*
  37. NewDistributionTable creates a new distribution table.
  38. */
  39. func NewDistributionTable(members []string, repFac int) (*DistributionTable, error) {
  40. return createDistributionTable(members, repFac, defaultDistributionRange)
  41. }
  42. /*
  43. createDistributionTable creates a new distribution table.
  44. */
  45. func createDistributionTable(members []string, repFac int, space uint64) (*DistributionTable, error) {
  46. var distrange []uint64
  47. replicas := make(map[string][]string)
  48. replicates := make(map[string][]string)
  49. mranges := make(map[string]uint64)
  50. // Check for bogus values
  51. if repFac < 1 {
  52. return nil, errors.New("Replication factor must be > 0")
  53. } else if repFac > len(members) {
  54. return nil, fmt.Errorf("Not enough members (%v) for given replication factor: %v",
  55. len(members), repFac)
  56. }
  57. // Do the range calculations
  58. memberRange := uint64(space / uint64(len(members)))
  59. for i := 0; i < len(members); i++ {
  60. mrange := uint64(i) * memberRange
  61. mranges[members[i]] = mrange
  62. distrange = append(distrange, mrange)
  63. var replicasList []string
  64. for j := 1; j < repFac; j++ {
  65. replicasList = append(replicasList, members[(i+j)%len(members)])
  66. }
  67. replicas[members[i]] = replicasList
  68. replicates[members[i]] = make([]string, 0, repFac)
  69. }
  70. for m, r := range replicas {
  71. for _, rm := range r {
  72. replicates[rm] = append(replicates[rm], m)
  73. }
  74. }
  75. return &DistributionTable{members, memberRange, distrange, mranges, replicas,
  76. replicates, repFac, space}, nil
  77. }
  78. /*
  79. Members returns all known cluster members.
  80. */
  81. func (dd *DistributionTable) Members() []string {
  82. return dd.members
  83. }
  84. /*
  85. Replicas returns all replicas for a given member.
  86. */
  87. func (dd *DistributionTable) Replicas(name string) []string {
  88. return dd.replicas[name]
  89. }
  90. /*
  91. MemberRange returns the location range of a given member.
  92. */
  93. func (dd *DistributionTable) MemberRange(name string) (uint64, uint64) {
  94. mrange := dd.mranges[name]
  95. if name == dd.members[len(dd.members)-1] {
  96. return mrange, dd.space
  97. }
  98. return mrange, mrange + dd.memberRange - 1
  99. }
  100. /*
  101. ReplicationRange return the location range which is replicated by a given member.
  102. */
  103. func (dd *DistributionTable) ReplicationRange(name string) (uint64, uint64) {
  104. var start, end uint64
  105. start = defaultDistributionRange
  106. for _, r := range dd.replicates[name] {
  107. rstart, rend := dd.MemberRange(r)
  108. if rstart < start {
  109. start = rstart
  110. }
  111. if rend > end {
  112. end = rend
  113. }
  114. }
  115. return start, end
  116. }
  117. /*
  118. LocationHome return the member which is in charge of a given location and all its replicas.
  119. */
  120. func (dd *DistributionTable) LocationHome(loc uint64) (string, []string) {
  121. var member string
  122. for i, r := range dd.distrange {
  123. if loc < r {
  124. member = dd.members[i-1]
  125. return member, dd.replicas[member]
  126. }
  127. }
  128. member = dd.members[len(dd.members)-1]
  129. return member, dd.replicas[member]
  130. }
  131. /*
  132. OtherReplicationMembers returns all members of a replication group (identified
  133. by a given locqtion) minus a given member.
  134. */
  135. func (dd *DistributionTable) OtherReplicationMembers(loc uint64, name string) []string {
  136. var ret []string
  137. primary, replicas := dd.LocationHome(loc)
  138. if name == primary {
  139. ret = replicas
  140. } else {
  141. ret = append(ret, primary)
  142. for _, rep := range replicas {
  143. if rep != name {
  144. ret = append(ret, rep)
  145. }
  146. }
  147. }
  148. return ret
  149. }
  150. /*
  151. String returns a string representation of this distribution table.
  152. */
  153. func (dd *DistributionTable) String() string {
  154. var ret bytes.Buffer
  155. ret.WriteString("Location ranges:\n")
  156. for _, member := range dd.members {
  157. f, t := dd.MemberRange(member)
  158. ret.WriteString(fmt.Sprintf("%v: %v -> %v\n", member, f, t))
  159. }
  160. ret.WriteString(fmt.Sprintf("Replicas (factor=%v) :\n", dd.repFac))
  161. for _, member := range dd.members {
  162. ret.WriteString(fmt.Sprintf("%v: %v\n", member, dd.replicas[member]))
  163. }
  164. return ret.String()
  165. }