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.

141 lines
3.2 KiB

  1. package storage
  2. import (
  3. "fmt"
  4. "io/ioutil"
  5. "path"
  6. "regexp"
  7. "sort"
  8. "strconv"
  9. "github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"
  10. "github.com/chrislusf/seaweedfs/weed/storage/needle"
  11. )
  12. var (
  13. re = regexp.MustCompile("\\.ec[0-9][0-9]")
  14. )
  15. func (l *DiskLocation) FindEcShard(vid needle.VolumeId, shardId erasure_coding.ShardId) (*erasure_coding.EcVolumeShard, bool) {
  16. l.ecShardsLock.RLock()
  17. defer l.ecShardsLock.RUnlock()
  18. ecShards, ok := l.ecShards[vid]
  19. if !ok {
  20. return nil, false
  21. }
  22. for _, ecShard := range ecShards {
  23. if ecShard.ShardId == shardId {
  24. return ecShard, true
  25. }
  26. }
  27. return nil, false
  28. }
  29. func (l *DiskLocation) LoadEcShard(collection string, vid needle.VolumeId, shardId erasure_coding.ShardId) (err error) {
  30. ecVolumeShard, err := erasure_coding.NewEcVolumeShard(l.Directory, collection, vid, shardId)
  31. if err != nil {
  32. return fmt.Errorf("failed to create ec shard %d.%d: %v", vid, shardId, err)
  33. }
  34. l.ecShardsLock.Lock()
  35. l.ecShards[vid] = append(l.ecShards[vid], ecVolumeShard)
  36. l.ecShardsLock.Unlock()
  37. return nil
  38. }
  39. func (l *DiskLocation) UnloadEcShard(vid needle.VolumeId, shardId erasure_coding.ShardId) bool {
  40. l.ecShardsLock.Lock()
  41. defer l.ecShardsLock.Unlock()
  42. vidShards, found := l.ecShards[vid]
  43. if !found {
  44. return false
  45. }
  46. shardIndex := -1
  47. for i, shard := range vidShards {
  48. if shard.ShardId == shardId {
  49. shardIndex = i
  50. break
  51. }
  52. }
  53. if shardIndex < 0 {
  54. return false
  55. }
  56. if len(vidShards) == 1 {
  57. delete(l.ecShards, vid)
  58. return true
  59. }
  60. l.ecShards[vid] = append(vidShards[:shardIndex], vidShards[shardIndex+1:]...)
  61. return true
  62. }
  63. func (l *DiskLocation) loadEcShards(shards []string, collection string, vid needle.VolumeId) (err error) {
  64. for _, shard := range shards {
  65. shardId, err := strconv.ParseInt(path.Ext(shard)[3:], 10, 64)
  66. if err != nil {
  67. return fmt.Errorf("failed to parse ec shard name %v: %v", shard, err)
  68. }
  69. err = l.LoadEcShard(collection, vid, erasure_coding.ShardId(shardId))
  70. if err != nil {
  71. return fmt.Errorf("failed to load ec shard %v: %v", shard, err)
  72. }
  73. }
  74. return nil
  75. }
  76. func (l *DiskLocation) loadAllEcShards() (err error) {
  77. fileInfos, err := ioutil.ReadDir(l.Directory)
  78. if err != nil {
  79. return fmt.Errorf("load all ec shards in dir %s: %v", l.Directory, err)
  80. }
  81. sort.Slice(fileInfos, func(i, j int) bool {
  82. return fileInfos[i].Name() < fileInfos[j].Name()
  83. })
  84. var sameVolumeShards []string
  85. var prevVolumeId needle.VolumeId
  86. for _, fileInfo := range fileInfos {
  87. if fileInfo.IsDir() {
  88. continue
  89. }
  90. ext := path.Ext(fileInfo.Name())
  91. name := fileInfo.Name()
  92. baseName := name[:len(name)-len(ext)]
  93. collection, volumeId, err := parseCollectionVolumeId(baseName)
  94. if err != nil {
  95. continue
  96. }
  97. if re.MatchString(ext) {
  98. if prevVolumeId == 0 || volumeId == prevVolumeId {
  99. sameVolumeShards = append(sameVolumeShards, fileInfo.Name())
  100. } else {
  101. sameVolumeShards = []string{fileInfo.Name()}
  102. }
  103. prevVolumeId = volumeId
  104. continue
  105. }
  106. if ext == ".ecx" && volumeId == prevVolumeId {
  107. if err = l.loadEcShards(sameVolumeShards, collection, volumeId); err != nil {
  108. return fmt.Errorf("loadEcShards collection:%v volumeId:%d : %v", collection, volumeId, err)
  109. }
  110. prevVolumeId = volumeId
  111. continue
  112. }
  113. }
  114. return nil
  115. }