chrislu
3 years ago
3 changed files with 174 additions and 165 deletions
-
165weed/storage/needle/needle_read.go
-
174weed/storage/needle/needle_write.go
-
0weed/storage/needle/needle_write_test.go
@ -0,0 +1,174 @@ |
|||||
|
package needle |
||||
|
|
||||
|
import ( |
||||
|
"bytes" |
||||
|
"fmt" |
||||
|
"github.com/chrislusf/seaweedfs/weed/glog" |
||||
|
"github.com/chrislusf/seaweedfs/weed/storage/backend" |
||||
|
. "github.com/chrislusf/seaweedfs/weed/storage/types" |
||||
|
"github.com/chrislusf/seaweedfs/weed/util" |
||||
|
"math" |
||||
|
"sync" |
||||
|
) |
||||
|
|
||||
|
var bufPool = sync.Pool{ |
||||
|
New: func() interface{} { |
||||
|
return new(bytes.Buffer) |
||||
|
}, |
||||
|
} |
||||
|
|
||||
|
func (n *Needle) prepareWriteBuffer(version Version, writeBytes *bytes.Buffer) (Size, int64, error) { |
||||
|
writeBytes.Reset() |
||||
|
switch version { |
||||
|
case Version1: |
||||
|
header := make([]byte, NeedleHeaderSize) |
||||
|
CookieToBytes(header[0:CookieSize], n.Cookie) |
||||
|
NeedleIdToBytes(header[CookieSize:CookieSize+NeedleIdSize], n.Id) |
||||
|
n.Size = Size(len(n.Data)) |
||||
|
SizeToBytes(header[CookieSize+NeedleIdSize:CookieSize+NeedleIdSize+SizeSize], n.Size) |
||||
|
size := n.Size |
||||
|
actualSize := NeedleHeaderSize + int64(n.Size) |
||||
|
writeBytes.Write(header) |
||||
|
writeBytes.Write(n.Data) |
||||
|
padding := PaddingLength(n.Size, version) |
||||
|
util.Uint32toBytes(header[0:NeedleChecksumSize], n.Checksum.Value()) |
||||
|
writeBytes.Write(header[0 : NeedleChecksumSize+padding]) |
||||
|
return size, actualSize, nil |
||||
|
case Version2, Version3: |
||||
|
header := make([]byte, NeedleHeaderSize+TimestampSize) // adding timestamp to reuse it and avoid extra allocation
|
||||
|
CookieToBytes(header[0:CookieSize], n.Cookie) |
||||
|
NeedleIdToBytes(header[CookieSize:CookieSize+NeedleIdSize], n.Id) |
||||
|
if len(n.Name) >= math.MaxUint8 { |
||||
|
n.NameSize = math.MaxUint8 |
||||
|
} else { |
||||
|
n.NameSize = uint8(len(n.Name)) |
||||
|
} |
||||
|
n.DataSize, n.MimeSize = uint32(len(n.Data)), uint8(len(n.Mime)) |
||||
|
if n.DataSize > 0 { |
||||
|
n.Size = 4 + Size(n.DataSize) + 1 |
||||
|
if n.HasName() { |
||||
|
n.Size = n.Size + 1 + Size(n.NameSize) |
||||
|
} |
||||
|
if n.HasMime() { |
||||
|
n.Size = n.Size + 1 + Size(n.MimeSize) |
||||
|
} |
||||
|
if n.HasLastModifiedDate() { |
||||
|
n.Size = n.Size + LastModifiedBytesLength |
||||
|
} |
||||
|
if n.HasTtl() { |
||||
|
n.Size = n.Size + TtlBytesLength |
||||
|
} |
||||
|
if n.HasPairs() { |
||||
|
n.Size += 2 + Size(n.PairsSize) |
||||
|
} |
||||
|
} else { |
||||
|
n.Size = 0 |
||||
|
} |
||||
|
SizeToBytes(header[CookieSize+NeedleIdSize:CookieSize+NeedleIdSize+SizeSize], n.Size) |
||||
|
writeBytes.Write(header[0:NeedleHeaderSize]) |
||||
|
if n.DataSize > 0 { |
||||
|
util.Uint32toBytes(header[0:4], n.DataSize) |
||||
|
writeBytes.Write(header[0:4]) |
||||
|
writeBytes.Write(n.Data) |
||||
|
util.Uint8toBytes(header[0:1], n.Flags) |
||||
|
writeBytes.Write(header[0:1]) |
||||
|
if n.HasName() { |
||||
|
util.Uint8toBytes(header[0:1], n.NameSize) |
||||
|
writeBytes.Write(header[0:1]) |
||||
|
writeBytes.Write(n.Name[:n.NameSize]) |
||||
|
} |
||||
|
if n.HasMime() { |
||||
|
util.Uint8toBytes(header[0:1], n.MimeSize) |
||||
|
writeBytes.Write(header[0:1]) |
||||
|
writeBytes.Write(n.Mime) |
||||
|
} |
||||
|
if n.HasLastModifiedDate() { |
||||
|
util.Uint64toBytes(header[0:8], n.LastModified) |
||||
|
writeBytes.Write(header[8-LastModifiedBytesLength : 8]) |
||||
|
} |
||||
|
if n.HasTtl() && n.Ttl != nil { |
||||
|
n.Ttl.ToBytes(header[0:TtlBytesLength]) |
||||
|
writeBytes.Write(header[0:TtlBytesLength]) |
||||
|
} |
||||
|
if n.HasPairs() { |
||||
|
util.Uint16toBytes(header[0:2], n.PairsSize) |
||||
|
writeBytes.Write(header[0:2]) |
||||
|
writeBytes.Write(n.Pairs) |
||||
|
} |
||||
|
} |
||||
|
padding := PaddingLength(n.Size, version) |
||||
|
util.Uint32toBytes(header[0:NeedleChecksumSize], n.Checksum.Value()) |
||||
|
if version == Version2 { |
||||
|
writeBytes.Write(header[0 : NeedleChecksumSize+padding]) |
||||
|
} else { |
||||
|
// version3
|
||||
|
util.Uint64toBytes(header[NeedleChecksumSize:NeedleChecksumSize+TimestampSize], n.AppendAtNs) |
||||
|
writeBytes.Write(header[0 : NeedleChecksumSize+TimestampSize+padding]) |
||||
|
} |
||||
|
|
||||
|
return Size(n.DataSize), GetActualSize(n.Size, version), nil |
||||
|
} |
||||
|
|
||||
|
return 0, 0, fmt.Errorf("Unsupported Version! (%d)", version) |
||||
|
} |
||||
|
|
||||
|
func (n *Needle) Append(w backend.BackendStorageFile, version Version) (offset uint64, size Size, actualSize int64, err error) { |
||||
|
|
||||
|
if end, _, e := w.GetStat(); e == nil { |
||||
|
defer func(w backend.BackendStorageFile, off int64) { |
||||
|
if err != nil { |
||||
|
if te := w.Truncate(end); te != nil { |
||||
|
glog.V(0).Infof("Failed to truncate %s back to %d with error: %v", w.Name(), end, te) |
||||
|
} |
||||
|
} |
||||
|
}(w, end) |
||||
|
offset = uint64(end) |
||||
|
} else { |
||||
|
err = fmt.Errorf("Cannot Read Current Volume Position: %v", e) |
||||
|
return |
||||
|
} |
||||
|
if offset >= MaxPossibleVolumeSize && n.Size.IsValid() { |
||||
|
err = fmt.Errorf("Volume Size %d Exeededs %d", offset, MaxPossibleVolumeSize) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
bytesBuffer := bufPool.Get().(*bytes.Buffer) |
||||
|
defer bufPool.Put(bytesBuffer) |
||||
|
|
||||
|
size, actualSize, err = n.prepareWriteBuffer(version, bytesBuffer) |
||||
|
|
||||
|
if err == nil { |
||||
|
_, err = w.WriteAt(bytesBuffer.Bytes(), int64(offset)) |
||||
|
} |
||||
|
|
||||
|
return offset, size, actualSize, err |
||||
|
} |
||||
|
|
||||
|
func WriteNeedleBlob(w backend.BackendStorageFile, dataSlice []byte, size Size, appendAtNs uint64, version Version) (offset uint64, err error) { |
||||
|
|
||||
|
if end, _, e := w.GetStat(); e == nil { |
||||
|
defer func(w backend.BackendStorageFile, off int64) { |
||||
|
if err != nil { |
||||
|
if te := w.Truncate(end); te != nil { |
||||
|
glog.V(0).Infof("Failed to truncate %s back to %d with error: %v", w.Name(), end, te) |
||||
|
} |
||||
|
} |
||||
|
}(w, end) |
||||
|
offset = uint64(end) |
||||
|
} else { |
||||
|
err = fmt.Errorf("Cannot Read Current Volume Position: %v", e) |
||||
|
return |
||||
|
} |
||||
|
|
||||
|
if version == Version3 { |
||||
|
tsOffset := NeedleHeaderSize + size + NeedleChecksumSize |
||||
|
util.Uint64toBytes(dataSlice[tsOffset:tsOffset+TimestampSize], appendAtNs) |
||||
|
} |
||||
|
|
||||
|
if err == nil { |
||||
|
_, err = w.WriteAt(dataSlice, int64(offset)) |
||||
|
} |
||||
|
|
||||
|
return |
||||
|
|
||||
|
} |
Write
Preview
Loading…
Cancel
Save
Reference in new issue