github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/ais/s3/xattr.go (about) 1 // Package s3 provides Amazon S3 compatibility layer 2 /* 3 * Copyright (c) 2022-2023, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package s3 6 7 import ( 8 "fmt" 9 "net/http" 10 "sort" 11 12 "github.com/NVIDIA/aistore/cmn/cos" 13 "github.com/NVIDIA/aistore/cmn/debug" 14 "github.com/NVIDIA/aistore/core" 15 "github.com/NVIDIA/aistore/fs" 16 ) 17 18 const mptXattrID = "user.ais.s3-multipart" 19 20 const iniCapParts = 8 21 22 func OffsetSorted(lom *core.LOM, partNum int32) (off, size int64, status int, err error) { 23 var mpt *mpt 24 if mpt, err = loadMptXattr(lom.FQN); err != nil { 25 return 26 } 27 if mpt == nil { 28 return -1, 0, http.StatusNotFound, fmt.Errorf("%s: multipart state not found", lom) 29 } 30 31 off, size, err = mpt._offSorted(lom.Cname(), partNum) 32 return 33 } 34 35 func loadMptXattr(fqn string) (out *mpt, err error) { 36 b, err := fs.GetXattr(fqn, mptXattrID) 37 if err == nil { 38 out = &mpt{} 39 err = out.unpack(b) 40 return 41 } 42 if cos.IsErrXattrNotFound(err) { 43 err = nil 44 } 45 return 46 } 47 48 func storeMptXattr(fqn string, mpt *mpt) (err error) { 49 sort.Slice(mpt.parts, func(i, j int) bool { 50 return mpt.parts[i].Num < mpt.parts[j].Num 51 }) 52 b := mpt.pack() 53 return fs.SetXattr(fqn, mptXattrID, b) 54 } 55 56 ///////// 57 // mpt // 58 ///////// 59 60 func (mpt *mpt) _offSorted(name string, num int32) (off, size int64, err error) { 61 var prev = int32(-1) 62 for _, part := range mpt.parts { 63 debug.Assert(part.Num > prev) // must ascend 64 if part.Num == num { 65 size = part.Size 66 return 67 } 68 off += part.Size 69 prev = part.Num 70 } 71 return 0, 0, fmt.Errorf("invalid part number %d (%s has %d)", num, name, prev) 72 } 73 74 func (mpt *mpt) packedSize() (size int) { 75 for _, part := range mpt.parts { 76 size += cos.SizeofI64 // num 77 size += cos.SizeofLen + len(part.MD5) 78 size += cos.SizeofI64 // part.Size 79 } 80 return 81 } 82 83 func (mpt *mpt) pack() []byte { 84 packer := cos.NewPacker(nil, mpt.packedSize()) 85 for _, part := range mpt.parts { 86 packer.WriteInt32(part.Num) 87 packer.WriteString(part.MD5) 88 packer.WriteInt64(part.Size) 89 } 90 return packer.Bytes() 91 } 92 93 func (mpt *mpt) unpack(b []byte) (err error) { 94 unpacker := cos.NewUnpacker(b) 95 debug.Assert(mpt.parts == nil) 96 mpt.parts = make([]*MptPart, 0, iniCapParts) 97 for unpacker.Len() > 0 { 98 part := &MptPart{} 99 if part.Num, err = unpacker.ReadInt32(); err != nil { 100 break 101 } 102 if part.MD5, err = unpacker.ReadString(); err != nil { 103 break 104 } 105 if part.Size, err = unpacker.ReadInt64(); err != nil { 106 break 107 } 108 mpt.parts = append(mpt.parts, part) 109 } 110 return 111 } 112 113 func (mpt *mpt) getPart(num int32) *MptPart { 114 for _, part := range mpt.parts { 115 if part.Num == num { 116 return part 117 } 118 } 119 return nil 120 }