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.

318 lines
7.2 KiB

5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
6 years ago
5 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
6 years ago
5 years ago
5 years ago
  1. package storage
  2. import (
  3. "fmt"
  4. "github.com/chrislusf/seaweedfs/weed/stats"
  5. "io/ioutil"
  6. "os"
  7. "path/filepath"
  8. "strings"
  9. "sync"
  10. "time"
  11. "github.com/chrislusf/seaweedfs/weed/glog"
  12. "github.com/chrislusf/seaweedfs/weed/storage/erasure_coding"
  13. "github.com/chrislusf/seaweedfs/weed/storage/needle"
  14. )
  15. type DiskLocation struct {
  16. Directory string
  17. MaxVolumeCount int
  18. MinFreeSpacePercent float32
  19. volumes map[needle.VolumeId]*Volume
  20. volumesLock sync.RWMutex
  21. // erasure coding
  22. ecVolumes map[needle.VolumeId]*erasure_coding.EcVolume
  23. ecVolumesLock sync.RWMutex
  24. }
  25. func NewDiskLocation(dir string, maxVolumeCount int, minFreeSpacePercent float32) *DiskLocation {
  26. location := &DiskLocation{Directory: dir, MaxVolumeCount: maxVolumeCount, MinFreeSpacePercent: minFreeSpacePercent}
  27. location.volumes = make(map[needle.VolumeId]*Volume)
  28. location.ecVolumes = make(map[needle.VolumeId]*erasure_coding.EcVolume)
  29. go location.CheckDiskSpace()
  30. return location
  31. }
  32. func (l *DiskLocation) volumeIdFromPath(dir os.FileInfo) (needle.VolumeId, string, error) {
  33. name := dir.Name()
  34. if !dir.IsDir() && strings.HasSuffix(name, ".idx") {
  35. base := name[:len(name)-len(".idx")]
  36. collection, volumeId, err := parseCollectionVolumeId(base)
  37. return volumeId, collection, err
  38. }
  39. return 0, "", fmt.Errorf("Path is not a volume: %s", name)
  40. }
  41. func parseCollectionVolumeId(base string) (collection string, vid needle.VolumeId, err error) {
  42. i := strings.LastIndex(base, "_")
  43. if i > 0 {
  44. collection, base = base[0:i], base[i+1:]
  45. }
  46. vol, err := needle.NewVolumeId(base)
  47. return collection, vol, err
  48. }
  49. func (l *DiskLocation) loadExistingVolume(fileInfo os.FileInfo, needleMapKind NeedleMapType) bool {
  50. name := fileInfo.Name()
  51. if !fileInfo.IsDir() && strings.HasSuffix(name, ".idx") {
  52. vid, collection, err := l.volumeIdFromPath(fileInfo)
  53. if err != nil {
  54. glog.Warningf("get volume id failed, %s, err : %s", name, err)
  55. return false
  56. }
  57. // void loading one volume more than once
  58. l.volumesLock.RLock()
  59. _, found := l.volumes[vid]
  60. l.volumesLock.RUnlock()
  61. if found {
  62. glog.V(1).Infof("loaded volume, %v", vid)
  63. return true
  64. }
  65. v, e := NewVolume(l.Directory, collection, vid, needleMapKind, nil, nil, 0, 0)
  66. if e != nil {
  67. glog.V(0).Infof("new volume %s error %s", name, e)
  68. return false
  69. }
  70. l.volumesLock.Lock()
  71. l.volumes[vid] = v
  72. l.volumesLock.Unlock()
  73. size, _, _ := v.FileStat()
  74. glog.V(0).Infof("data file %s, replicaPlacement=%s v=%d size=%d ttl=%s",
  75. l.Directory+"/"+name, v.ReplicaPlacement, v.Version(), size, v.Ttl.String())
  76. return true
  77. }
  78. return false
  79. }
  80. func (l *DiskLocation) concurrentLoadingVolumes(needleMapKind NeedleMapType, concurrency int) {
  81. task_queue := make(chan os.FileInfo, 10*concurrency)
  82. go func() {
  83. if dirs, err := ioutil.ReadDir(l.Directory); err == nil {
  84. for _, dir := range dirs {
  85. task_queue <- dir
  86. }
  87. }
  88. close(task_queue)
  89. }()
  90. var wg sync.WaitGroup
  91. for workerNum := 0; workerNum < concurrency; workerNum++ {
  92. wg.Add(1)
  93. go func() {
  94. defer wg.Done()
  95. for dir := range task_queue {
  96. _ = l.loadExistingVolume(dir, needleMapKind)
  97. }
  98. }()
  99. }
  100. wg.Wait()
  101. }
  102. func (l *DiskLocation) loadExistingVolumes(needleMapKind NeedleMapType) {
  103. l.concurrentLoadingVolumes(needleMapKind, 10)
  104. glog.V(0).Infof("Store started on dir: %s with %d volumes max %d", l.Directory, len(l.volumes), l.MaxVolumeCount)
  105. l.loadAllEcShards()
  106. glog.V(0).Infof("Store started on dir: %s with %d ec shards", l.Directory, len(l.ecVolumes))
  107. }
  108. func (l *DiskLocation) DeleteCollectionFromDiskLocation(collection string) (e error) {
  109. l.volumesLock.Lock()
  110. delVolsMap := l.unmountVolumeByCollection(collection)
  111. l.volumesLock.Unlock()
  112. l.ecVolumesLock.Lock()
  113. delEcVolsMap := l.unmountEcVolumeByCollection(collection)
  114. l.ecVolumesLock.Unlock()
  115. errChain := make(chan error, 2)
  116. var wg sync.WaitGroup
  117. wg.Add(2)
  118. go func() {
  119. for _, v := range delVolsMap {
  120. if err := v.Destroy(); err != nil {
  121. errChain <- err
  122. }
  123. }
  124. wg.Done()
  125. }()
  126. go func() {
  127. for _, v := range delEcVolsMap {
  128. v.Destroy()
  129. }
  130. wg.Done()
  131. }()
  132. go func() {
  133. wg.Wait()
  134. close(errChain)
  135. }()
  136. errBuilder := strings.Builder{}
  137. for err := range errChain {
  138. errBuilder.WriteString(err.Error())
  139. errBuilder.WriteString("; ")
  140. }
  141. if errBuilder.Len() > 0 {
  142. e = fmt.Errorf(errBuilder.String())
  143. }
  144. return
  145. }
  146. func (l *DiskLocation) deleteVolumeById(vid needle.VolumeId) (found bool, e error) {
  147. v, ok := l.volumes[vid]
  148. if !ok {
  149. return
  150. }
  151. e = v.Destroy()
  152. if e != nil {
  153. return
  154. }
  155. found = true
  156. delete(l.volumes, vid)
  157. return
  158. }
  159. func (l *DiskLocation) LoadVolume(vid needle.VolumeId, needleMapKind NeedleMapType) bool {
  160. if fileInfo, found := l.LocateVolume(vid); found {
  161. return l.loadExistingVolume(fileInfo, needleMapKind)
  162. }
  163. return false
  164. }
  165. func (l *DiskLocation) DeleteVolume(vid needle.VolumeId) error {
  166. l.volumesLock.Lock()
  167. defer l.volumesLock.Unlock()
  168. _, ok := l.volumes[vid]
  169. if !ok {
  170. return fmt.Errorf("Volume not found, VolumeId: %d", vid)
  171. }
  172. _, err := l.deleteVolumeById(vid)
  173. return err
  174. }
  175. func (l *DiskLocation) UnloadVolume(vid needle.VolumeId) error {
  176. l.volumesLock.Lock()
  177. defer l.volumesLock.Unlock()
  178. v, ok := l.volumes[vid]
  179. if !ok {
  180. return fmt.Errorf("Volume not loaded, VolumeId: %d", vid)
  181. }
  182. v.Close()
  183. delete(l.volumes, vid)
  184. return nil
  185. }
  186. func (l *DiskLocation) unmountVolumeByCollection(collectionName string) map[needle.VolumeId]*Volume {
  187. deltaVols := make(map[needle.VolumeId]*Volume, 0)
  188. for k, v := range l.volumes {
  189. if v.Collection == collectionName && !v.isCompacting {
  190. deltaVols[k] = v
  191. }
  192. }
  193. for k := range deltaVols {
  194. delete(l.volumes, k)
  195. }
  196. return deltaVols
  197. }
  198. func (l *DiskLocation) SetVolume(vid needle.VolumeId, volume *Volume) {
  199. l.volumesLock.Lock()
  200. defer l.volumesLock.Unlock()
  201. l.volumes[vid] = volume
  202. }
  203. func (l *DiskLocation) FindVolume(vid needle.VolumeId) (*Volume, bool) {
  204. l.volumesLock.RLock()
  205. defer l.volumesLock.RUnlock()
  206. v, ok := l.volumes[vid]
  207. return v, ok
  208. }
  209. func (l *DiskLocation) VolumesLen() int {
  210. l.volumesLock.RLock()
  211. defer l.volumesLock.RUnlock()
  212. return len(l.volumes)
  213. }
  214. func (l *DiskLocation) Close() {
  215. l.volumesLock.Lock()
  216. for _, v := range l.volumes {
  217. v.Close()
  218. }
  219. l.volumesLock.Unlock()
  220. l.ecVolumesLock.Lock()
  221. for _, ecVolume := range l.ecVolumes {
  222. ecVolume.Close()
  223. }
  224. l.ecVolumesLock.Unlock()
  225. return
  226. }
  227. func (l *DiskLocation) LocateVolume(vid needle.VolumeId) (os.FileInfo, bool) {
  228. if fileInfos, err := ioutil.ReadDir(l.Directory); err == nil {
  229. for _, fileInfo := range fileInfos {
  230. volId, _, err := l.volumeIdFromPath(fileInfo)
  231. if vid == volId && err == nil {
  232. return fileInfo, true
  233. }
  234. }
  235. }
  236. return nil, false
  237. }
  238. func (l *DiskLocation) UnUsedSpace(volumeSizeLimit uint64) (unUsedSpace uint64) {
  239. l.volumesLock.RLock()
  240. defer l.volumesLock.RUnlock()
  241. for _, vol := range l.volumes {
  242. if vol.IsReadOnly() {
  243. continue
  244. }
  245. datSize, idxSize, _ := vol.FileStat()
  246. unUsedSpace += volumeSizeLimit - (datSize + idxSize)
  247. }
  248. return
  249. }
  250. func (l *DiskLocation) CheckDiskSpace() {
  251. lastStat := false
  252. t := time.NewTicker(time.Minute)
  253. for _ = range t.C {
  254. if dir, e := filepath.Abs(l.Directory); e == nil {
  255. s := stats.NewDiskStatus(dir)
  256. if (s.PercentFree < l.MinFreeSpacePercent) != lastStat {
  257. lastStat = !lastStat
  258. for _, v := range l.volumes {
  259. v.SetLowDiskSpace(lastStat)
  260. }
  261. }
  262. }
  263. }
  264. }