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.

109 lines
3.3 KiB

  1. package needle
  2. import (
  3. "fmt"
  4. "github.com/seaweedfs/seaweedfs/weed/glog"
  5. "github.com/seaweedfs/seaweedfs/weed/storage/backend"
  6. . "github.com/seaweedfs/seaweedfs/weed/storage/types"
  7. "github.com/seaweedfs/seaweedfs/weed/util"
  8. "io"
  9. )
  10. // ReadNeedleDataInto uses a needle without n.Data to read the content into an io.Writer
  11. func (n *Needle) ReadNeedleDataInto(r backend.BackendStorageFile, volumeOffset int64, buf []byte, writer io.Writer, needleOffset int64, size int64) (err error) {
  12. crc := CRC(0)
  13. for x := needleOffset; x < needleOffset+size; x += int64(len(buf)) {
  14. count, err := n.ReadNeedleData(r, volumeOffset, buf, x)
  15. toWrite := min(int64(count), needleOffset+size-x)
  16. if toWrite > 0 {
  17. crc = crc.Update(buf[0:toWrite])
  18. if _, err = writer.Write(buf[0:toWrite]); err != nil {
  19. return fmt.Errorf("ReadNeedleData write: %v", err)
  20. }
  21. }
  22. if err != nil {
  23. if err == io.EOF {
  24. err = nil
  25. break
  26. }
  27. return fmt.Errorf("ReadNeedleData: %v", err)
  28. }
  29. if count <= 0 {
  30. break
  31. }
  32. }
  33. if needleOffset == 0 && size == int64(n.DataSize) && (n.Checksum != crc && uint32(n.Checksum) != crc.Value()) {
  34. // the crc.Value() function is to be deprecated. this double checking is for backward compatible.
  35. return fmt.Errorf("ReadNeedleData checksum %v expected %v", crc, n.Checksum)
  36. }
  37. return nil
  38. }
  39. // ReadNeedleData uses a needle without n.Data to read the content
  40. // volumeOffset: the offset within the volume
  41. // needleOffset: the offset within the needle Data
  42. func (n *Needle) ReadNeedleData(r backend.BackendStorageFile, volumeOffset int64, data []byte, needleOffset int64) (count int, err error) {
  43. sizeToRead := min(int64(len(data)), int64(n.DataSize)-needleOffset)
  44. if sizeToRead <= 0 {
  45. return 0, io.EOF
  46. }
  47. startOffset := volumeOffset + NeedleHeaderSize + DataSizeSize + needleOffset
  48. count, err = r.ReadAt(data[:sizeToRead], startOffset)
  49. if err != nil {
  50. fileSize, _, _ := r.GetStat()
  51. glog.Errorf("%s read %d %d size %d at offset %d fileSize %d: %v", r.Name(), n.Id, needleOffset, sizeToRead, volumeOffset, fileSize, err)
  52. }
  53. return
  54. }
  55. // ReadNeedleMeta fills all metadata except the n.Data
  56. func (n *Needle) ReadNeedleMeta(r backend.BackendStorageFile, offset int64, size Size, version Version) (err error) {
  57. bytes := make([]byte, NeedleHeaderSize+DataSizeSize)
  58. count, err := r.ReadAt(bytes, offset)
  59. if count != NeedleHeaderSize+DataSizeSize || err != nil {
  60. return err
  61. }
  62. n.ParseNeedleHeader(bytes)
  63. if n.Size != size {
  64. if OffsetSize == 4 && offset < int64(MaxPossibleVolumeSize) {
  65. return ErrorSizeMismatch
  66. }
  67. }
  68. n.DataSize = util.BytesToUint32(bytes[NeedleHeaderSize : NeedleHeaderSize+DataSizeSize])
  69. startOffset := offset + NeedleHeaderSize + DataSizeSize + int64(n.DataSize)
  70. dataSize := GetActualSize(size, version)
  71. stopOffset := offset + dataSize
  72. metaSize := stopOffset - startOffset
  73. metaSlice := make([]byte, int(metaSize))
  74. count, err = r.ReadAt(metaSlice, startOffset)
  75. if err != nil && int64(count) == metaSize {
  76. err = nil
  77. }
  78. if err != nil {
  79. return err
  80. }
  81. var index int
  82. index, err = n.readNeedleDataVersion2NonData(metaSlice)
  83. n.Checksum = CRC(util.BytesToUint32(metaSlice[index : index+NeedleChecksumSize]))
  84. if version == Version3 {
  85. n.AppendAtNs = util.BytesToUint64(metaSlice[index+NeedleChecksumSize : index+NeedleChecksumSize+TimestampSize])
  86. }
  87. return err
  88. }
  89. func min(x, y int64) int64 {
  90. if x < y {
  91. return x
  92. }
  93. return y
  94. }