ec_volume_info.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249
  1. package erasure_coding
  2. import (
  3. "math/bits"
  4. "github.com/seaweedfs/seaweedfs/weed/pb/master_pb"
  5. "github.com/seaweedfs/seaweedfs/weed/storage/needle"
  6. )
  7. // data structure used in master
  8. type EcVolumeInfo struct {
  9. VolumeId needle.VolumeId
  10. Collection string
  11. ShardBits ShardBits
  12. DiskType string
  13. DiskId uint32 // ID of the disk this EC volume is on
  14. ExpireAtSec uint64 // ec volume destroy time, calculated from the ec volume was created
  15. ShardSizes []int64 // optimized: sizes for shards in order of set bits in ShardBits
  16. }
  17. func (ecInfo *EcVolumeInfo) AddShardId(id ShardId) {
  18. oldBits := ecInfo.ShardBits
  19. ecInfo.ShardBits = ecInfo.ShardBits.AddShardId(id)
  20. // If shard was actually added, resize ShardSizes array
  21. if oldBits != ecInfo.ShardBits {
  22. ecInfo.resizeShardSizes(oldBits)
  23. }
  24. }
  25. func (ecInfo *EcVolumeInfo) RemoveShardId(id ShardId) {
  26. oldBits := ecInfo.ShardBits
  27. ecInfo.ShardBits = ecInfo.ShardBits.RemoveShardId(id)
  28. // If shard was actually removed, resize ShardSizes array
  29. if oldBits != ecInfo.ShardBits {
  30. ecInfo.resizeShardSizes(oldBits)
  31. }
  32. }
  33. func (ecInfo *EcVolumeInfo) SetShardSize(id ShardId, size int64) {
  34. ecInfo.ensureShardSizesInitialized()
  35. if index, found := ecInfo.ShardBits.ShardIdToIndex(id); found && index < len(ecInfo.ShardSizes) {
  36. ecInfo.ShardSizes[index] = size
  37. }
  38. }
  39. func (ecInfo *EcVolumeInfo) GetShardSize(id ShardId) (int64, bool) {
  40. if index, found := ecInfo.ShardBits.ShardIdToIndex(id); found && index < len(ecInfo.ShardSizes) {
  41. return ecInfo.ShardSizes[index], true
  42. }
  43. return 0, false
  44. }
  45. func (ecInfo *EcVolumeInfo) GetTotalSize() int64 {
  46. var total int64
  47. for _, size := range ecInfo.ShardSizes {
  48. total += size
  49. }
  50. return total
  51. }
  52. func (ecInfo *EcVolumeInfo) HasShardId(id ShardId) bool {
  53. return ecInfo.ShardBits.HasShardId(id)
  54. }
  55. func (ecInfo *EcVolumeInfo) ShardIds() (ret []ShardId) {
  56. return ecInfo.ShardBits.ShardIds()
  57. }
  58. func (ecInfo *EcVolumeInfo) ShardIdCount() (count int) {
  59. return ecInfo.ShardBits.ShardIdCount()
  60. }
  61. func (ecInfo *EcVolumeInfo) Minus(other *EcVolumeInfo) *EcVolumeInfo {
  62. ret := &EcVolumeInfo{
  63. VolumeId: ecInfo.VolumeId,
  64. Collection: ecInfo.Collection,
  65. ShardBits: ecInfo.ShardBits.Minus(other.ShardBits),
  66. DiskType: ecInfo.DiskType,
  67. DiskId: ecInfo.DiskId,
  68. ExpireAtSec: ecInfo.ExpireAtSec,
  69. }
  70. // Initialize optimized ShardSizes for the result
  71. ret.ensureShardSizesInitialized()
  72. // Copy shard sizes for remaining shards
  73. retIndex := 0
  74. for shardId := ShardId(0); shardId < TotalShardsCount && retIndex < len(ret.ShardSizes); shardId++ {
  75. if ret.ShardBits.HasShardId(shardId) {
  76. if size, exists := ecInfo.GetShardSize(shardId); exists {
  77. ret.ShardSizes[retIndex] = size
  78. }
  79. retIndex++
  80. }
  81. }
  82. return ret
  83. }
  84. func (ecInfo *EcVolumeInfo) ToVolumeEcShardInformationMessage() (ret *master_pb.VolumeEcShardInformationMessage) {
  85. t := &master_pb.VolumeEcShardInformationMessage{
  86. Id: uint32(ecInfo.VolumeId),
  87. EcIndexBits: uint32(ecInfo.ShardBits),
  88. Collection: ecInfo.Collection,
  89. DiskType: ecInfo.DiskType,
  90. ExpireAtSec: ecInfo.ExpireAtSec,
  91. DiskId: ecInfo.DiskId,
  92. }
  93. // Directly set the optimized ShardSizes
  94. t.ShardSizes = make([]int64, len(ecInfo.ShardSizes))
  95. copy(t.ShardSizes, ecInfo.ShardSizes)
  96. return t
  97. }
  98. type ShardBits uint32 // use bits to indicate the shard id, use 32 bits just for possible future extension
  99. func (b ShardBits) AddShardId(id ShardId) ShardBits {
  100. return b | (1 << id)
  101. }
  102. func (b ShardBits) RemoveShardId(id ShardId) ShardBits {
  103. return b &^ (1 << id)
  104. }
  105. func (b ShardBits) HasShardId(id ShardId) bool {
  106. return b&(1<<id) > 0
  107. }
  108. func (b ShardBits) ShardIds() (ret []ShardId) {
  109. for i := ShardId(0); i < TotalShardsCount; i++ {
  110. if b.HasShardId(i) {
  111. ret = append(ret, i)
  112. }
  113. }
  114. return
  115. }
  116. func (b ShardBits) ToUint32Slice() (ret []uint32) {
  117. for i := uint32(0); i < TotalShardsCount; i++ {
  118. if b.HasShardId(ShardId(i)) {
  119. ret = append(ret, i)
  120. }
  121. }
  122. return
  123. }
  124. func (b ShardBits) ShardIdCount() (count int) {
  125. for count = 0; b > 0; count++ {
  126. b &= b - 1
  127. }
  128. return
  129. }
  130. func (b ShardBits) Minus(other ShardBits) ShardBits {
  131. return b &^ other
  132. }
  133. func (b ShardBits) Plus(other ShardBits) ShardBits {
  134. return b | other
  135. }
  136. func (b ShardBits) MinusParityShards() ShardBits {
  137. for i := DataShardsCount; i < TotalShardsCount; i++ {
  138. b = b.RemoveShardId(ShardId(i))
  139. }
  140. return b
  141. }
  142. // ShardIdToIndex converts a shard ID to its index position in the ShardSizes slice
  143. // Returns the index and true if the shard is present, -1 and false if not present
  144. func (b ShardBits) ShardIdToIndex(shardId ShardId) (index int, found bool) {
  145. if !b.HasShardId(shardId) {
  146. return -1, false
  147. }
  148. // Create a mask for bits before the shardId
  149. mask := uint32((1 << shardId) - 1)
  150. // Count set bits before the shardId using efficient bit manipulation
  151. index = bits.OnesCount32(uint32(b) & mask)
  152. return index, true
  153. }
  154. // EachSetIndex iterates over all set shard IDs and calls the provided function for each
  155. // This is highly efficient using bit manipulation - only iterates over actual set bits
  156. func (b ShardBits) EachSetIndex(fn func(shardId ShardId)) {
  157. bitsValue := uint32(b)
  158. for bitsValue != 0 {
  159. // Find the position of the least significant set bit
  160. shardId := ShardId(bits.TrailingZeros32(bitsValue))
  161. fn(shardId)
  162. // Clear the least significant set bit
  163. bitsValue &= bitsValue - 1
  164. }
  165. }
  166. // IndexToShardId converts an index position in ShardSizes slice to the corresponding shard ID
  167. // Returns the shard ID and true if valid index, -1 and false if invalid index
  168. func (b ShardBits) IndexToShardId(index int) (shardId ShardId, found bool) {
  169. if index < 0 {
  170. return 0, false
  171. }
  172. currentIndex := 0
  173. for i := ShardId(0); i < TotalShardsCount; i++ {
  174. if b.HasShardId(i) {
  175. if currentIndex == index {
  176. return i, true
  177. }
  178. currentIndex++
  179. }
  180. }
  181. return 0, false // index out of range
  182. }
  183. // Helper methods for EcVolumeInfo to manage the optimized ShardSizes slice
  184. func (ecInfo *EcVolumeInfo) ensureShardSizesInitialized() {
  185. expectedLength := ecInfo.ShardBits.ShardIdCount()
  186. if ecInfo.ShardSizes == nil {
  187. ecInfo.ShardSizes = make([]int64, expectedLength)
  188. } else if len(ecInfo.ShardSizes) != expectedLength {
  189. // Resize and preserve existing data
  190. ecInfo.resizeShardSizes(ecInfo.ShardBits)
  191. }
  192. }
  193. func (ecInfo *EcVolumeInfo) resizeShardSizes(prevShardBits ShardBits) {
  194. expectedLength := ecInfo.ShardBits.ShardIdCount()
  195. newSizes := make([]int64, expectedLength)
  196. // Copy existing sizes to new positions based on current ShardBits
  197. if len(ecInfo.ShardSizes) > 0 {
  198. newIndex := 0
  199. for shardId := ShardId(0); shardId < TotalShardsCount && newIndex < expectedLength; shardId++ {
  200. if ecInfo.ShardBits.HasShardId(shardId) {
  201. // Try to find the size for this shard in the old array using previous ShardBits
  202. if oldIndex, found := prevShardBits.ShardIdToIndex(shardId); found && oldIndex < len(ecInfo.ShardSizes) {
  203. newSizes[newIndex] = ecInfo.ShardSizes[oldIndex]
  204. }
  205. newIndex++
  206. }
  207. }
  208. }
  209. ecInfo.ShardSizes = newSizes
  210. }