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.

346 lines
8.4 KiB

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