You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

200 lines
4.8 KiB

6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
6 years ago
  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) FindEcShard(vid needle.VolumeId, shardId erasure_coding.ShardId) (*erasure_coding.EcVolumeShard, bool) {
  34. l.ecVolumesLock.RLock()
  35. defer l.ecVolumesLock.RUnlock()
  36. ecVolume, ok := l.ecVolumes[vid]
  37. if !ok {
  38. return nil, false
  39. }
  40. for _, ecShard := range ecVolume.Shards {
  41. if ecShard.ShardId == shardId {
  42. return ecShard, true
  43. }
  44. }
  45. return nil, false
  46. }
  47. func (l *DiskLocation) LoadEcShard(collection string, vid needle.VolumeId, shardId erasure_coding.ShardId) (err error) {
  48. ecVolumeShard, err := erasure_coding.NewEcVolumeShard(l.DiskType, l.Directory, collection, vid, shardId)
  49. if err != nil {
  50. if err == os.ErrNotExist {
  51. return os.ErrNotExist
  52. }
  53. return fmt.Errorf("failed to create ec shard %d.%d: %v", vid, shardId, err)
  54. }
  55. l.ecVolumesLock.Lock()
  56. defer l.ecVolumesLock.Unlock()
  57. ecVolume, found := l.ecVolumes[vid]
  58. if !found {
  59. ecVolume, err = erasure_coding.NewEcVolume(l.DiskType, l.Directory, l.IdxDirectory, collection, vid)
  60. if err != nil {
  61. return fmt.Errorf("failed to create ec volume %d: %v", vid, err)
  62. }
  63. l.ecVolumes[vid] = ecVolume
  64. }
  65. ecVolume.AddEcVolumeShard(ecVolumeShard)
  66. return nil
  67. }
  68. func (l *DiskLocation) UnloadEcShard(vid needle.VolumeId, shardId erasure_coding.ShardId) bool {
  69. l.ecVolumesLock.Lock()
  70. defer l.ecVolumesLock.Unlock()
  71. ecVolume, found := l.ecVolumes[vid]
  72. if !found {
  73. return false
  74. }
  75. if _, deleted := ecVolume.DeleteEcVolumeShard(shardId); deleted {
  76. if len(ecVolume.Shards) == 0 {
  77. delete(l.ecVolumes, vid)
  78. ecVolume.Close()
  79. }
  80. return true
  81. }
  82. return true
  83. }
  84. func (l *DiskLocation) loadEcShards(shards []string, collection string, vid needle.VolumeId) (err error) {
  85. for _, shard := range shards {
  86. shardId, err := strconv.ParseInt(path.Ext(shard)[3:], 10, 64)
  87. if err != nil {
  88. return fmt.Errorf("failed to parse ec shard name %v: %v", shard, err)
  89. }
  90. err = l.LoadEcShard(collection, vid, erasure_coding.ShardId(shardId))
  91. if err != nil {
  92. return fmt.Errorf("failed to load ec shard %v: %v", shard, err)
  93. }
  94. }
  95. return nil
  96. }
  97. func (l *DiskLocation) loadAllEcShards() (err error) {
  98. dirEntries, err := os.ReadDir(l.Directory)
  99. if err != nil {
  100. return fmt.Errorf("load all ec shards in dir %s: %v", l.Directory, err)
  101. }
  102. if l.IdxDirectory != l.Directory {
  103. indexDirEntries, err := os.ReadDir(l.IdxDirectory)
  104. if err != nil {
  105. return fmt.Errorf("load all ec shards in dir %s: %v", l.IdxDirectory, err)
  106. }
  107. dirEntries = append(dirEntries, indexDirEntries...)
  108. }
  109. slices.SortFunc(dirEntries, func(a, b os.DirEntry) bool {
  110. return a.Name() < b.Name()
  111. })
  112. var sameVolumeShards []string
  113. var prevVolumeId needle.VolumeId
  114. for _, fileInfo := range dirEntries {
  115. if fileInfo.IsDir() {
  116. continue
  117. }
  118. ext := path.Ext(fileInfo.Name())
  119. name := fileInfo.Name()
  120. baseName := name[:len(name)-len(ext)]
  121. collection, volumeId, err := parseCollectionVolumeId(baseName)
  122. if err != nil {
  123. continue
  124. }
  125. if re.MatchString(ext) {
  126. if prevVolumeId == 0 || volumeId == prevVolumeId {
  127. sameVolumeShards = append(sameVolumeShards, fileInfo.Name())
  128. } else {
  129. sameVolumeShards = []string{fileInfo.Name()}
  130. }
  131. prevVolumeId = volumeId
  132. continue
  133. }
  134. if ext == ".ecx" && volumeId == prevVolumeId {
  135. if err = l.loadEcShards(sameVolumeShards, collection, volumeId); err != nil {
  136. return fmt.Errorf("loadEcShards collection:%v volumeId:%d : %v", collection, volumeId, err)
  137. }
  138. prevVolumeId = volumeId
  139. continue
  140. }
  141. }
  142. return nil
  143. }
  144. func (l *DiskLocation) deleteEcVolumeById(vid needle.VolumeId) (e error) {
  145. ecVolume, ok := l.ecVolumes[vid]
  146. if !ok {
  147. return
  148. }
  149. ecVolume.Destroy()
  150. delete(l.ecVolumes, vid)
  151. return
  152. }
  153. func (l *DiskLocation) unmountEcVolumeByCollection(collectionName string) map[needle.VolumeId]*erasure_coding.EcVolume {
  154. deltaVols := make(map[needle.VolumeId]*erasure_coding.EcVolume, 0)
  155. for k, v := range l.ecVolumes {
  156. if v.Collection == collectionName {
  157. deltaVols[k] = v
  158. }
  159. }
  160. for k, _ := range deltaVols {
  161. delete(l.ecVolumes, k)
  162. }
  163. return deltaVols
  164. }
  165. func (l *DiskLocation) EcVolumesLen() int {
  166. l.ecVolumesLock.RLock()
  167. defer l.ecVolumesLock.RUnlock()
  168. return len(l.ecVolumes)
  169. }