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.

148 lines
4.8 KiB

  1. package replication
  2. import (
  3. "code.google.com/p/weed-fs/go/glog"
  4. "code.google.com/p/weed-fs/go/storage"
  5. "code.google.com/p/weed-fs/go/topology"
  6. "fmt"
  7. "math/rand"
  8. "sync"
  9. )
  10. /*
  11. This package is created to resolve these replica placement issues:
  12. 1. growth factor for each replica level, e.g., add 10 volumes for 1 copy, 20 volumes for 2 copies, 30 volumes for 3 copies
  13. 2. in time of tight storage, how to reduce replica level
  14. 3. optimizing for hot data on faster disk, cold data on cheaper storage,
  15. 4. volume allocation for each bucket
  16. */
  17. type VolumeGrowth struct {
  18. accessLock sync.Mutex
  19. }
  20. func NewDefaultVolumeGrowth() *VolumeGrowth {
  21. return &VolumeGrowth{}
  22. }
  23. // one replication type may need rp.GetCopyCount() actual volumes
  24. // given copyCount, how many logical volumes to create
  25. func (vg *VolumeGrowth) findVolumeCount(copyCount int) (count int) {
  26. switch copyCount {
  27. case 1:
  28. count = 7
  29. case 2:
  30. count = 6
  31. case 3:
  32. count = 3
  33. default:
  34. count = 1
  35. }
  36. return
  37. }
  38. func (vg *VolumeGrowth) AutomaticGrowByType(collection string, rp *storage.ReplicaPlacement, preferredDataCenter string, topo *topology.Topology) (count int, err error) {
  39. count, err = vg.GrowByCountAndType(vg.findVolumeCount(rp.GetCopyCount()), collection, rp, preferredDataCenter, topo)
  40. if count > 0 && count%rp.GetCopyCount() == 0 {
  41. return count, nil
  42. }
  43. return count, err
  44. }
  45. func (vg *VolumeGrowth) GrowByCountAndType(targetCount int, collection string, rp *storage.ReplicaPlacement, preferredDataCenter string, topo *topology.Topology) (counter int, err error) {
  46. vg.accessLock.Lock()
  47. defer vg.accessLock.Unlock()
  48. for i := 0; i < targetCount; i++ {
  49. if c, e := vg.findAndGrow(topo, preferredDataCenter, collection, rp); e == nil {
  50. counter += c
  51. } else {
  52. return counter, e
  53. }
  54. }
  55. return
  56. }
  57. func (vg *VolumeGrowth) findAndGrow(topo *topology.Topology, preferredDataCenter string, collection string, rp *storage.ReplicaPlacement) (int, error) {
  58. servers, e := vg.findEmptySlotsForOneVolume(topo, preferredDataCenter, rp)
  59. if e != nil {
  60. return 0, e
  61. }
  62. vid := topo.NextVolumeId()
  63. err := vg.grow(topo, vid, collection, rp, servers...)
  64. return len(servers), err
  65. }
  66. func (vg *VolumeGrowth) findEmptySlotsForOneVolume(topo *topology.Topology, preferredDataCenter string, rp *storage.ReplicaPlacement) (servers []*topology.DataNode, err error) {
  67. //find main datacenter and other data centers
  68. mainDataCenter, otherDataCenters, dc_err := topo.RandomlyPickNodes(rp.DiffDataCenterCount+1, func(node topology.Node) error {
  69. if preferredDataCenter != "" && node.IsDataCenter() && node.Id() != topology.NodeId(preferredDataCenter) {
  70. return fmt.Errorf("Not matching preferred:%s", preferredDataCenter)
  71. }
  72. if node.FreeSpace() < rp.DiffRackCount+rp.SameRackCount+1 {
  73. return fmt.Errorf("Free:%d < Expected:%d", node.FreeSpace(), rp.DiffRackCount+rp.SameRackCount+1)
  74. }
  75. return nil
  76. })
  77. if dc_err != nil {
  78. return nil, dc_err
  79. }
  80. //find main rack and other racks
  81. mainRack, otherRacks, rack_err := mainDataCenter.(*topology.DataCenter).RandomlyPickNodes(rp.DiffRackCount+1, func(node topology.Node) error {
  82. if node.FreeSpace() < rp.SameRackCount+1 {
  83. return fmt.Errorf("Free:%d < Expected:%d", node.FreeSpace(), rp.SameRackCount+1)
  84. }
  85. return nil
  86. })
  87. if rack_err != nil {
  88. return nil, rack_err
  89. }
  90. //find main rack and other racks
  91. mainServer, otherServers, server_err := mainRack.(*topology.Rack).RandomlyPickNodes(rp.SameRackCount+1, func(node topology.Node) error {
  92. if node.FreeSpace() < 1 {
  93. return fmt.Errorf("Free:%d < Expected:%d", node.FreeSpace(), 1)
  94. }
  95. return nil
  96. })
  97. if server_err != nil {
  98. return nil, server_err
  99. }
  100. servers = append(servers, mainServer.(*topology.DataNode))
  101. for _, server := range otherServers {
  102. servers = append(servers, server.(*topology.DataNode))
  103. }
  104. for _, rack := range otherRacks {
  105. r := rand.Intn(rack.FreeSpace())
  106. if server, e := rack.ReserveOneVolume(r); e == nil {
  107. servers = append(servers, server)
  108. } else {
  109. return servers, e
  110. }
  111. }
  112. for _, datacenter := range otherDataCenters {
  113. r := rand.Intn(datacenter.FreeSpace())
  114. if server, e := datacenter.ReserveOneVolume(r); e == nil {
  115. servers = append(servers, server)
  116. } else {
  117. return servers, e
  118. }
  119. }
  120. return
  121. }
  122. func (vg *VolumeGrowth) grow(topo *topology.Topology, vid storage.VolumeId, collection string, rp *storage.ReplicaPlacement, servers ...*topology.DataNode) error {
  123. for _, server := range servers {
  124. if err := AllocateVolume(server, vid, collection, rp); err == nil {
  125. vi := storage.VolumeInfo{Id: vid, Size: 0, Collection: collection, ReplicaPlacement: rp, Version: storage.CurrentVersion}
  126. server.AddOrUpdateVolume(vi)
  127. topo.RegisterVolumeLayout(&vi, server)
  128. glog.V(0).Infoln("Created Volume", vid, "on", server)
  129. } else {
  130. glog.V(0).Infoln("Failed to assign", vid, "to", servers, "error", err)
  131. return fmt.Errorf("Failed to assign %s: %s", vid.String(), err.Error())
  132. }
  133. }
  134. return nil
  135. }