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.

134 lines
3.5 KiB

7 years ago
7 years ago
  1. package filesys
  2. import (
  3. "fmt"
  4. "bytes"
  5. "time"
  6. "context"
  7. "github.com/chrislusf/seaweedfs/weed/pb/filer_pb"
  8. "github.com/chrislusf/seaweedfs/weed/operation"
  9. "github.com/chrislusf/seaweedfs/weed/glog"
  10. )
  11. type ContinuousDirtyPages struct {
  12. hasData bool
  13. Offset int64
  14. Size int64
  15. Data []byte
  16. f *File
  17. }
  18. func newDirtyPages(file *File) *ContinuousDirtyPages {
  19. return &ContinuousDirtyPages{
  20. Data: make([]byte, file.wfs.chunkSizeLimit),
  21. f: file,
  22. }
  23. }
  24. func (pages *ContinuousDirtyPages) AddPage(ctx context.Context, offset int64, data []byte) (chunk *filer_pb.FileChunk, err error) {
  25. if len(data) > len(pages.Data) {
  26. // this is more than what we can hold.
  27. panic("not prepared if buffer is smaller than each system write!")
  28. }
  29. if offset < pages.Offset || offset >= pages.Offset+int64(len(pages.Data)) ||
  30. pages.Offset+int64(len(pages.Data)) < offset+int64(len(data)) {
  31. // if the data is out of range,
  32. // or buffer is full if adding new data,
  33. // flush current buffer and add new data
  34. // println("offset", offset, "size", len(data), "existing offset", pages.Offset, "size", pages.Size)
  35. if chunk, err = pages.saveToStorage(ctx); err == nil {
  36. if chunk != nil {
  37. glog.V(4).Infof("%s/%s add save [%d,%d)", pages.f.dir.Path, pages.f.Name, chunk.Offset, chunk.Offset+int64(chunk.Size))
  38. }
  39. } else {
  40. glog.V(0).Infof("%s/%s add save [%d,%d): %v", pages.f.dir.Path, pages.f.Name, chunk.Offset, chunk.Offset+int64(chunk.Size), err)
  41. return
  42. }
  43. pages.Offset = offset
  44. pages.Size = int64(len(data))
  45. copy(pages.Data, data)
  46. return
  47. }
  48. copy(pages.Data[offset-pages.Offset:], data)
  49. pages.Size = max(pages.Size, offset+int64(len(data))-pages.Offset)
  50. return
  51. }
  52. func (pages *ContinuousDirtyPages) FlushToStorage(ctx context.Context) (chunk *filer_pb.FileChunk, err error) {
  53. if pages.Size == 0 {
  54. return nil, nil
  55. }
  56. if chunk, err = pages.saveToStorage(ctx); err == nil {
  57. pages.Size = 0
  58. if chunk != nil {
  59. glog.V(4).Infof("%s/%s flush [%d,%d)", pages.f.dir.Path, pages.f.Name, chunk.Offset, chunk.Offset+int64(chunk.Size))
  60. }
  61. }
  62. return
  63. }
  64. func (pages *ContinuousDirtyPages) saveToStorage(ctx context.Context) (*filer_pb.FileChunk, error) {
  65. if pages.Size == 0 {
  66. return nil, nil
  67. }
  68. var fileId, host string
  69. if err := pages.f.wfs.withFilerClient(func(client filer_pb.SeaweedFilerClient) error {
  70. request := &filer_pb.AssignVolumeRequest{
  71. Count: 1,
  72. Replication: pages.f.wfs.replication,
  73. Collection: pages.f.wfs.collection,
  74. }
  75. resp, err := client.AssignVolume(ctx, request)
  76. if err != nil {
  77. glog.V(0).Infof("assign volume failure %v: %v", request, err)
  78. return err
  79. }
  80. fileId, host = resp.FileId, resp.Url
  81. return nil
  82. }); err != nil {
  83. return nil, fmt.Errorf("filer assign volume: %v", err)
  84. }
  85. fileUrl := fmt.Sprintf("http://%s/%s", host, fileId)
  86. bufReader := bytes.NewReader(pages.Data[:pages.Size])
  87. uploadResult, err := operation.Upload(fileUrl, pages.f.Name, bufReader, false, "application/octet-stream", nil, "")
  88. if err != nil {
  89. glog.V(0).Infof("upload data %v to %s: %v", pages.f.Name, fileUrl, err)
  90. return nil, fmt.Errorf("upload data: %v", err)
  91. }
  92. if uploadResult.Error != "" {
  93. glog.V(0).Infof("upload failure %v to %s: %v", pages.f.Name, fileUrl, err)
  94. return nil, fmt.Errorf("upload result: %v", uploadResult.Error)
  95. }
  96. return &filer_pb.FileChunk{
  97. FileId: fileId,
  98. Offset: pages.Offset,
  99. Size: uint64(pages.Size),
  100. Mtime: time.Now().UnixNano(),
  101. }, nil
  102. }
  103. func max(x, y int64) int64 {
  104. if x > y {
  105. return x
  106. }
  107. return y
  108. }