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  }