disk_location_ec.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. package storage
  2. import (
  3. "fmt"
  4. "golang.org/x/exp/slices"
  5. "os"
  6. "path"
  7. "regexp"
  8. "strconv"
  9. "github.com/seaweedfs/seaweedfs/weed/storage/erasure_coding"
  10. "github.com/seaweedfs/seaweedfs/weed/storage/needle"
  11. )
  12. var (
  13. re = regexp.MustCompile(`\.ec[0-9][0-9]`)
  14. )
  15. func (l *DiskLocation) FindEcVolume(vid needle.VolumeId) (*erasure_coding.EcVolume, bool) {
  16. l.ecVolumesLock.RLock()
  17. defer l.ecVolumesLock.RUnlock()
  18. ecVolume, ok := l.ecVolumes[vid]
  19. if ok {
  20. return ecVolume, true
  21. }
  22. return nil, false
  23. }
  24. func (l *DiskLocation) DestroyEcVolume(vid needle.VolumeId) {
  25. l.ecVolumesLock.Lock()
  26. defer l.ecVolumesLock.Unlock()
  27. ecVolume, found := l.ecVolumes[vid]
  28. if found {
  29. ecVolume.Destroy()
  30. delete(l.ecVolumes, vid)
  31. }
  32. }
  33. func (l *DiskLocation) CollectEcShards(vid needle.VolumeId, shardFileNames []string) (ecVolume *erasure_coding.EcVolume, found bool) {
  34. l.ecVolumesLock.RLock()
  35. defer l.ecVolumesLock.RUnlock()
  36. ecVolume, found = l.ecVolumes[vid]
  37. if !found {
  38. return
  39. }
  40. for _, ecShard := range ecVolume.Shards {
  41. if ecShard.ShardId < erasure_coding.ShardId(len(shardFileNames)) {
  42. shardFileNames[ecShard.ShardId] = erasure_coding.EcShardFileName(ecVolume.Collection, l.Directory, int(ecVolume.VolumeId)) + erasure_coding.ToExt(int(ecShard.ShardId))
  43. }
  44. }
  45. return
  46. }
  47. func (l *DiskLocation) FindEcShard(vid needle.VolumeId, shardId erasure_coding.ShardId) (*erasure_coding.EcVolumeShard, bool) {
  48. l.ecVolumesLock.RLock()
  49. defer l.ecVolumesLock.RUnlock()
  50. ecVolume, ok := l.ecVolumes[vid]
  51. if !ok {
  52. return nil, false
  53. }
  54. for _, ecShard := range ecVolume.Shards {
  55. if ecShard.ShardId == shardId {
  56. return ecShard, true
  57. }
  58. }
  59. return nil, false
  60. }
  61. func (l *DiskLocation) LoadEcShard(collection string, vid needle.VolumeId, shardId erasure_coding.ShardId) (err error) {
  62. ecVolumeShard, err := erasure_coding.NewEcVolumeShard(l.DiskType, l.Directory, collection, vid, shardId)
  63. if err != nil {
  64. if err == os.ErrNotExist {
  65. return os.ErrNotExist
  66. }
  67. return fmt.Errorf("failed to create ec shard %d.%d: %v", vid, shardId, err)
  68. }
  69. l.ecVolumesLock.Lock()
  70. defer l.ecVolumesLock.Unlock()
  71. ecVolume, found := l.ecVolumes[vid]
  72. if !found {
  73. ecVolume, err = erasure_coding.NewEcVolume(l.DiskType, l.Directory, l.IdxDirectory, collection, vid)
  74. if err != nil {
  75. return fmt.Errorf("failed to create ec volume %d: %v", vid, err)
  76. }
  77. l.ecVolumes[vid] = ecVolume
  78. }
  79. ecVolume.AddEcVolumeShard(ecVolumeShard)
  80. return nil
  81. }
  82. func (l *DiskLocation) UnloadEcShard(vid needle.VolumeId, shardId erasure_coding.ShardId) bool {
  83. l.ecVolumesLock.Lock()
  84. defer l.ecVolumesLock.Unlock()
  85. ecVolume, found := l.ecVolumes[vid]
  86. if !found {
  87. return false
  88. }
  89. if _, deleted := ecVolume.DeleteEcVolumeShard(shardId); deleted {
  90. if len(ecVolume.Shards) == 0 {
  91. delete(l.ecVolumes, vid)
  92. ecVolume.Close()
  93. }
  94. return true
  95. }
  96. return true
  97. }
  98. func (l *DiskLocation) loadEcShards(shards []string, collection string, vid needle.VolumeId) (err error) {
  99. for _, shard := range shards {
  100. shardId, err := strconv.ParseInt(path.Ext(shard)[3:], 10, 64)
  101. if err != nil {
  102. return fmt.Errorf("failed to parse ec shard name %v: %v", shard, err)
  103. }
  104. err = l.LoadEcShard(collection, vid, erasure_coding.ShardId(shardId))
  105. if err != nil {
  106. return fmt.Errorf("failed to load ec shard %v: %v", shard, err)
  107. }
  108. }
  109. return nil
  110. }
  111. func (l *DiskLocation) loadAllEcShards() (err error) {
  112. dirEntries, err := os.ReadDir(l.Directory)
  113. if err != nil {
  114. return fmt.Errorf("load all ec shards in dir %s: %v", l.Directory, err)
  115. }
  116. if l.IdxDirectory != l.Directory {
  117. indexDirEntries, err := os.ReadDir(l.IdxDirectory)
  118. if err != nil {
  119. return fmt.Errorf("load all ec shards in dir %s: %v", l.IdxDirectory, err)
  120. }
  121. dirEntries = append(dirEntries, indexDirEntries...)
  122. }
  123. slices.SortFunc(dirEntries, func(a, b os.DirEntry) bool {
  124. return a.Name() < b.Name()
  125. })
  126. var sameVolumeShards []string
  127. var prevVolumeId needle.VolumeId
  128. for _, fileInfo := range dirEntries {
  129. if fileInfo.IsDir() {
  130. continue
  131. }
  132. ext := path.Ext(fileInfo.Name())
  133. name := fileInfo.Name()
  134. baseName := name[:len(name)-len(ext)]
  135. collection, volumeId, err := parseCollectionVolumeId(baseName)
  136. if err != nil {
  137. continue
  138. }
  139. if re.MatchString(ext) {
  140. if prevVolumeId == 0 || volumeId == prevVolumeId {
  141. sameVolumeShards = append(sameVolumeShards, fileInfo.Name())
  142. } else {
  143. sameVolumeShards = []string{fileInfo.Name()}
  144. }
  145. prevVolumeId = volumeId
  146. continue
  147. }
  148. if ext == ".ecx" && volumeId == prevVolumeId {
  149. if err = l.loadEcShards(sameVolumeShards, collection, volumeId); err != nil {
  150. return fmt.Errorf("loadEcShards collection:%v volumeId:%d : %v", collection, volumeId, err)
  151. }
  152. prevVolumeId = volumeId
  153. continue
  154. }
  155. }
  156. return nil
  157. }
  158. func (l *DiskLocation) deleteEcVolumeById(vid needle.VolumeId) (e error) {
  159. ecVolume, ok := l.ecVolumes[vid]
  160. if !ok {
  161. return
  162. }
  163. ecVolume.Destroy()
  164. delete(l.ecVolumes, vid)
  165. return
  166. }
  167. func (l *DiskLocation) unmountEcVolumeByCollection(collectionName string) map[needle.VolumeId]*erasure_coding.EcVolume {
  168. deltaVols := make(map[needle.VolumeId]*erasure_coding.EcVolume, 0)
  169. for k, v := range l.ecVolumes {
  170. if v.Collection == collectionName {
  171. deltaVols[k] = v
  172. }
  173. }
  174. for k, _ := range deltaVols {
  175. delete(l.ecVolumes, k)
  176. }
  177. return deltaVols
  178. }
  179. func (l *DiskLocation) EcVolumesLen() int {
  180. l.ecVolumesLock.RLock()
  181. defer l.ecVolumesLock.RUnlock()
  182. return len(l.ecVolumes)
  183. }