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.

164 lines
4.8 KiB

9 years ago
9 years ago
  1. package topology
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "net/url"
  6. "time"
  7. "github.com/chrislusf/seaweedfs/weed/glog"
  8. "github.com/chrislusf/seaweedfs/weed/storage"
  9. "github.com/chrislusf/seaweedfs/weed/util"
  10. )
  11. func batchVacuumVolumeCheck(vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList, garbageThreshold string) bool {
  12. ch := make(chan bool, locationlist.Length())
  13. for index, dn := range locationlist.list {
  14. go func(index int, url string, vid storage.VolumeId) {
  15. //glog.V(0).Infoln(index, "Check vacuuming", vid, "on", dn.Url())
  16. if e, ret := vacuumVolume_Check(url, vid, garbageThreshold); e != nil {
  17. //glog.V(0).Infoln(index, "Error when checking vacuuming", vid, "on", url, e)
  18. ch <- false
  19. } else {
  20. //glog.V(0).Infoln(index, "Checked vacuuming", vid, "on", url, "needVacuum", ret)
  21. ch <- ret
  22. }
  23. }(index, dn.Url(), vid)
  24. }
  25. isCheckSuccess := true
  26. for _ = range locationlist.list {
  27. select {
  28. case canVacuum := <-ch:
  29. isCheckSuccess = isCheckSuccess && canVacuum
  30. case <-time.After(30 * time.Minute):
  31. isCheckSuccess = false
  32. break
  33. }
  34. }
  35. return isCheckSuccess
  36. }
  37. func batchVacuumVolumeCompact(vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList) bool {
  38. vl.removeFromWritable(vid)
  39. ch := make(chan bool, locationlist.Length())
  40. for index, dn := range locationlist.list {
  41. go func(index int, url string, vid storage.VolumeId) {
  42. glog.V(0).Infoln(index, "Start vacuuming", vid, "on", url)
  43. if e := vacuumVolume_Compact(url, vid); e != nil {
  44. glog.V(0).Infoln(index, "Error when vacuuming", vid, "on", url, e)
  45. ch <- false
  46. } else {
  47. glog.V(0).Infoln(index, "Complete vacuuming", vid, "on", url)
  48. ch <- true
  49. }
  50. }(index, dn.Url(), vid)
  51. }
  52. isVacuumSuccess := true
  53. for _ = range locationlist.list {
  54. select {
  55. case _ = <-ch:
  56. case <-time.After(30 * time.Minute):
  57. isVacuumSuccess = false
  58. break
  59. }
  60. }
  61. return isVacuumSuccess
  62. }
  63. func batchVacuumVolumeCommit(vl *VolumeLayout, vid storage.VolumeId, locationlist *VolumeLocationList) bool {
  64. isCommitSuccess := true
  65. for _, dn := range locationlist.list {
  66. glog.V(0).Infoln("Start Commiting vacuum", vid, "on", dn.Url())
  67. if e := vacuumVolume_Commit(dn.Url(), vid); e != nil {
  68. glog.V(0).Infoln("Error when committing vacuum", vid, "on", dn.Url(), e)
  69. isCommitSuccess = false
  70. } else {
  71. glog.V(0).Infoln("Complete Commiting vacuum", vid, "on", dn.Url())
  72. }
  73. if isCommitSuccess {
  74. vl.SetVolumeAvailable(dn, vid)
  75. }
  76. }
  77. return isCommitSuccess
  78. }
  79. func (t *Topology) Vacuum(garbageThreshold string) int {
  80. glog.V(0).Infof("Start vacuum on demand with threshold:%s", garbageThreshold)
  81. for _, col := range t.collectionMap.Items() {
  82. c := col.(*Collection)
  83. for _, vl := range c.storageType2VolumeLayout.Items() {
  84. if vl != nil {
  85. volumeLayout := vl.(*VolumeLayout)
  86. writableSet := make(map[storage.VolumeId]bool)
  87. for _, id := range volumeLayout.writables {
  88. writableSet[id] = true
  89. }
  90. for vid, locationlist := range volumeLayout.vid2location {
  91. if _, isWritable := writableSet[vid]; !isWritable {
  92. continue
  93. }
  94. glog.V(0).Infof("check vacuum on collection:%s volume:%d", c.Name, vid)
  95. if batchVacuumVolumeCheck(volumeLayout, vid, locationlist, garbageThreshold) {
  96. if batchVacuumVolumeCompact(volumeLayout, vid, locationlist) {
  97. batchVacuumVolumeCommit(volumeLayout, vid, locationlist)
  98. }
  99. }
  100. }
  101. }
  102. }
  103. }
  104. return 0
  105. }
  106. type VacuumVolumeResult struct {
  107. Result bool
  108. Error string
  109. }
  110. func vacuumVolume_Check(urlLocation string, vid storage.VolumeId, garbageThreshold string) (error, bool) {
  111. values := make(url.Values)
  112. values.Add("volume", vid.String())
  113. values.Add("garbageThreshold", garbageThreshold)
  114. jsonBlob, err := util.Post("http://"+urlLocation+"/admin/vacuum/check", values)
  115. if err != nil {
  116. glog.V(0).Infoln("parameters:", values)
  117. return err, false
  118. }
  119. var ret VacuumVolumeResult
  120. if err := json.Unmarshal(jsonBlob, &ret); err != nil {
  121. return err, false
  122. }
  123. if ret.Error != "" {
  124. return errors.New(ret.Error), false
  125. }
  126. return nil, ret.Result
  127. }
  128. func vacuumVolume_Compact(urlLocation string, vid storage.VolumeId) error {
  129. values := make(url.Values)
  130. values.Add("volume", vid.String())
  131. jsonBlob, err := util.Post("http://"+urlLocation+"/admin/vacuum/compact", values)
  132. if err != nil {
  133. return err
  134. }
  135. var ret VacuumVolumeResult
  136. if err := json.Unmarshal(jsonBlob, &ret); err != nil {
  137. return err
  138. }
  139. if ret.Error != "" {
  140. return errors.New(ret.Error)
  141. }
  142. return nil
  143. }
  144. func vacuumVolume_Commit(urlLocation string, vid storage.VolumeId) error {
  145. values := make(url.Values)
  146. values.Add("volume", vid.String())
  147. jsonBlob, err := util.Post("http://"+urlLocation+"/admin/vacuum/commit", values)
  148. if err != nil {
  149. return err
  150. }
  151. var ret VacuumVolumeResult
  152. if err := json.Unmarshal(jsonBlob, &ret); err != nil {
  153. return err
  154. }
  155. if ret.Error != "" {
  156. return errors.New(ret.Error)
  157. }
  158. return nil
  159. }