needle_write_test.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. package needle
  2. import (
  3. "bytes"
  4. "os"
  5. "testing"
  6. "time"
  7. "github.com/seaweedfs/seaweedfs/weed/storage/backend"
  8. "github.com/seaweedfs/seaweedfs/weed/storage/types"
  9. )
  10. func TestAppend(t *testing.T) {
  11. n := &Needle{
  12. Cookie: types.Cookie(123), // Cookie Cookie `comment:"random number to mitigate brute force lookups"`
  13. Id: types.NeedleId(123), // Id NeedleId `comment:"needle id"`
  14. Size: 8, // Size uint32 `comment:"sum of DataSize,Data,NameSize,Name,MimeSize,Mime"`
  15. DataSize: 4, // DataSize uint32 `comment:"Data size"` //version2
  16. Data: []byte("abcd"), // Data []byte `comment:"The actual file data"`
  17. Flags: 0, // Flags byte `comment:"boolean flags"` //version2
  18. NameSize: 0, // NameSize uint8 //version2
  19. Name: nil, // Name []byte `comment:"maximum 256 characters"` //version2
  20. MimeSize: 0, // MimeSize uint8 //version2
  21. Mime: nil, // Mime []byte `comment:"maximum 256 characters"` //version2
  22. PairsSize: 0, // PairsSize uint16 //version2
  23. Pairs: nil, // Pairs []byte `comment:"additional name value pairs, json format, maximum 6
  24. LastModified: 123, // LastModified uint64 //only store LastModifiedBytesLength bytes, which is 5 bytes
  25. Ttl: nil, // Ttl *TTL
  26. Checksum: 123, // Checksum CRC `comment:"CRC32 to check integrity"`
  27. AppendAtNs: 123, // AppendAtNs uint64 `comment:"append timestamp in nano seconds"` //version3
  28. Padding: nil, // Padding []byte `comment:"Aligned to 8 bytes"`
  29. }
  30. tempFile, err := os.CreateTemp("", ".dat")
  31. if err != nil {
  32. t.Errorf("Fail TempFile. %v", err)
  33. return
  34. }
  35. /*
  36. uint8 : 0 to 255
  37. uint16 : 0 to 65535
  38. uint32 : 0 to 4294967295
  39. uint64 : 0 to 18446744073709551615
  40. int8 : -128 to 127
  41. int16 : -32768 to 32767
  42. int32 : -2147483648 to 2147483647
  43. int64 : -9223372036854775808 to 9223372036854775807
  44. */
  45. fileSize := int64(4294967296) + 10000
  46. tempFile.Truncate(fileSize)
  47. defer func() {
  48. tempFile.Close()
  49. os.Remove(tempFile.Name())
  50. }()
  51. datBackend := backend.NewDiskFile(tempFile)
  52. defer datBackend.Close()
  53. offset, _, _, _ := n.Append(datBackend, GetCurrentVersion())
  54. if offset != uint64(fileSize) {
  55. t.Errorf("Fail to Append Needle.")
  56. }
  57. }
  58. func versionString(v Version) string {
  59. switch v {
  60. case Version1:
  61. return "Version1"
  62. case Version2:
  63. return "Version2"
  64. case Version3:
  65. return "Version3"
  66. default:
  67. return "UnknownVersion"
  68. }
  69. }
  70. func TestWriteNeedle_CompatibilityWithLegacy(t *testing.T) {
  71. versions := []Version{Version1, Version2, Version3}
  72. for _, version := range versions {
  73. t.Run(versionString(version), func(t *testing.T) {
  74. n := &Needle{
  75. Cookie: 0x12345678,
  76. Id: 0x1122334455667788,
  77. Data: []byte("hello world"),
  78. Flags: 0xFF,
  79. Name: []byte("filename.txt"),
  80. Mime: []byte("text/plain"),
  81. LastModified: 0x1234567890,
  82. Ttl: nil, // Add TTL if needed
  83. Pairs: []byte("key=value"),
  84. PairsSize: 9,
  85. Checksum: 0xCAFEBABE,
  86. AppendAtNs: 0xDEADBEEF,
  87. }
  88. // Legacy
  89. legacyBuf := &bytes.Buffer{}
  90. _, _, err := n.LegacyPrepareWriteBuffer(version, legacyBuf)
  91. if err != nil {
  92. t.Fatalf("LegacyPrepareWriteBuffer failed: %v", err)
  93. }
  94. // New
  95. newBuf := &bytes.Buffer{}
  96. offset := uint64(0)
  97. switch version {
  98. case Version1:
  99. _, _, err = writeNeedleV1(n, offset, newBuf)
  100. case Version2:
  101. _, _, err = writeNeedleV2(n, offset, newBuf)
  102. case Version3:
  103. _, _, err = writeNeedleV3(n, offset, newBuf)
  104. }
  105. if err != nil {
  106. t.Fatalf("writeNeedleV%d failed: %v", version, err)
  107. }
  108. if !bytes.Equal(legacyBuf.Bytes(), newBuf.Bytes()) {
  109. t.Errorf("Data layout mismatch for version %d\nLegacy: %x\nNew: %x", version, legacyBuf.Bytes(), newBuf.Bytes())
  110. }
  111. })
  112. }
  113. }
  114. type mockBackendWriter struct {
  115. buf *bytes.Buffer
  116. }
  117. func (m *mockBackendWriter) WriteAt(p []byte, off int64) (n int, err error) {
  118. return m.buf.Write(p)
  119. }
  120. func (m *mockBackendWriter) GetStat() (int64, time.Time, error) {
  121. return 0, time.Time{}, nil
  122. }
  123. func (m *mockBackendWriter) Truncate(size int64) error {
  124. return nil
  125. }
  126. func (m *mockBackendWriter) Name() string {
  127. return "mock"
  128. }
  129. func (m *mockBackendWriter) Close() error {
  130. return nil
  131. }
  132. func (m *mockBackendWriter) Sync() error {
  133. return nil
  134. }
  135. func (m *mockBackendWriter) ReadAt(p []byte, off int64) (n int, err error) {
  136. // Not used in this test
  137. return 0, nil
  138. }