store_replicate.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. package topology
  2. import (
  3. "encoding/json"
  4. "errors"
  5. "fmt"
  6. "net/http"
  7. "net/url"
  8. "strconv"
  9. "strings"
  10. "github.com/chrislusf/seaweedfs/weed/glog"
  11. "github.com/chrislusf/seaweedfs/weed/operation"
  12. "github.com/chrislusf/seaweedfs/weed/security"
  13. "github.com/chrislusf/seaweedfs/weed/storage"
  14. "github.com/chrislusf/seaweedfs/weed/storage/needle"
  15. "github.com/chrislusf/seaweedfs/weed/util"
  16. )
  17. func ReplicatedWrite(masterNode string, s *storage.Store,
  18. volumeId needle.VolumeId, n *needle.Needle,
  19. r *http.Request) (size uint32, isUnchanged bool, err error) {
  20. //check JWT
  21. jwt := security.GetJwt(r)
  22. var remoteLocations []operation.Location
  23. if r.FormValue("type") != "replicate" {
  24. remoteLocations, err = getWritableRemoteReplications(s, volumeId, masterNode)
  25. if err != nil {
  26. glog.V(0).Infoln(err)
  27. return
  28. }
  29. }
  30. size, isUnchanged, err = s.WriteVolumeNeedle(volumeId, n)
  31. if err != nil {
  32. err = fmt.Errorf("failed to write to local disk: %v", err)
  33. glog.V(0).Infoln(err)
  34. return
  35. }
  36. if len(remoteLocations) > 0 { //send to other replica locations
  37. if err = distributedOperation(remoteLocations, s, func(location operation.Location) error {
  38. u := url.URL{
  39. Scheme: "http",
  40. Host: location.Url,
  41. Path: r.URL.Path,
  42. }
  43. q := url.Values{
  44. "type": {"replicate"},
  45. "ttl": {n.Ttl.String()},
  46. }
  47. if n.LastModified > 0 {
  48. q.Set("ts", strconv.FormatUint(n.LastModified, 10))
  49. }
  50. if n.IsChunkedManifest() {
  51. q.Set("cm", "true")
  52. }
  53. u.RawQuery = q.Encode()
  54. pairMap := make(map[string]string)
  55. if n.HasPairs() {
  56. tmpMap := make(map[string]string)
  57. err := json.Unmarshal(n.Pairs, &tmpMap)
  58. if err != nil {
  59. glog.V(0).Infoln("Unmarshal pairs error:", err)
  60. }
  61. for k, v := range tmpMap {
  62. pairMap[needle.PairNamePrefix+k] = v
  63. }
  64. }
  65. // volume server do not know about encryption
  66. _, err := operation.UploadData(u.String(), string(n.Name), false, n.Data, n.IsGzipped(), string(n.Mime), pairMap, jwt)
  67. return err
  68. }); err != nil {
  69. size = 0
  70. err = fmt.Errorf("failed to write to replicas for volume %d: %v", volumeId, err)
  71. glog.V(0).Infoln(err)
  72. }
  73. }
  74. return
  75. }
  76. func ReplicatedDelete(masterNode string, store *storage.Store,
  77. volumeId needle.VolumeId, n *needle.Needle,
  78. r *http.Request) (size uint32, err error) {
  79. //check JWT
  80. jwt := security.GetJwt(r)
  81. var remoteLocations []operation.Location
  82. if r.FormValue("type") != "replicate" {
  83. remoteLocations, err = getWritableRemoteReplications(store, volumeId, masterNode)
  84. if err != nil {
  85. glog.V(0).Infoln(err)
  86. return
  87. }
  88. }
  89. size, err = store.DeleteVolumeNeedle(volumeId, n)
  90. if err != nil {
  91. glog.V(0).Infoln("delete error:", err)
  92. return
  93. }
  94. if len(remoteLocations) > 0 { //send to other replica locations
  95. if err = distributedOperation(remoteLocations, store, func(location operation.Location) error {
  96. return util.Delete("http://"+location.Url+r.URL.Path+"?type=replicate", string(jwt))
  97. }); err != nil {
  98. size = 0
  99. }
  100. }
  101. return
  102. }
  103. type DistributedOperationResult map[string]error
  104. func (dr DistributedOperationResult) Error() error {
  105. var errs []string
  106. for k, v := range dr {
  107. if v != nil {
  108. errs = append(errs, fmt.Sprintf("[%s]: %v", k, v))
  109. }
  110. }
  111. if len(errs) == 0 {
  112. return nil
  113. }
  114. return errors.New(strings.Join(errs, "\n"))
  115. }
  116. type RemoteResult struct {
  117. Host string
  118. Error error
  119. }
  120. func distributedOperation(locations []operation.Location, store *storage.Store, op func(location operation.Location) error) error {
  121. length := len(locations)
  122. results := make(chan RemoteResult)
  123. for _, location := range locations {
  124. go func(location operation.Location, results chan RemoteResult) {
  125. results <- RemoteResult{location.Url, op(location)}
  126. }(location, results)
  127. }
  128. ret := DistributedOperationResult(make(map[string]error))
  129. for i := 0; i < length; i++ {
  130. result := <-results
  131. ret[result.Host] = result.Error
  132. }
  133. return ret.Error()
  134. }
  135. func getWritableRemoteReplications(s *storage.Store, volumeId needle.VolumeId, masterNode string) (
  136. remoteLocations []operation.Location, err error) {
  137. copyCount := s.GetVolume(volumeId).ReplicaPlacement.GetCopyCount()
  138. if copyCount > 1 {
  139. if lookupResult, lookupErr := operation.Lookup(masterNode, volumeId.String()); lookupErr == nil {
  140. if len(lookupResult.Locations) < copyCount {
  141. err = fmt.Errorf("replicating opetations [%d] is less than volume %d replication copy count [%d]",
  142. len(lookupResult.Locations), volumeId, copyCount)
  143. return
  144. }
  145. selfUrl := s.Ip + ":" + strconv.Itoa(s.Port)
  146. for _, location := range lookupResult.Locations {
  147. if location.Url != selfUrl {
  148. remoteLocations = append(remoteLocations, location)
  149. }
  150. }
  151. } else {
  152. err = fmt.Errorf("failed to lookup for %d: %v", volumeId, lookupErr)
  153. return
  154. }
  155. }
  156. return
  157. }