github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/core/ct.go (about)

     1  // Package core provides core metadata and in-cluster API
     2  /*
     3   * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package core
     6  
     7  import (
     8  	"io"
     9  	"os"
    10  
    11  	"github.com/NVIDIA/aistore/cmn"
    12  	"github.com/NVIDIA/aistore/cmn/cos"
    13  	"github.com/NVIDIA/aistore/core/meta"
    14  	"github.com/NVIDIA/aistore/fs"
    15  )
    16  
    17  //////////////////////////////
    18  // ais on-disk content type //
    19  //////////////////////////////
    20  
    21  type CT struct {
    22  	fqn         string
    23  	objName     string
    24  	contentType string
    25  	hrwFQN      string
    26  	bck         *meta.Bck
    27  	mi          *fs.Mountpath
    28  	uname       string
    29  	digest      uint64
    30  	size        int64
    31  	mtime       int64
    32  }
    33  
    34  // interface guard
    35  var _ fs.PartsFQN = (*CT)(nil)
    36  
    37  func (ct *CT) FQN() string              { return ct.fqn }
    38  func (ct *CT) ObjectName() string       { return ct.objName }
    39  func (ct *CT) ContentType() string      { return ct.contentType }
    40  func (ct *CT) Bck() *meta.Bck           { return ct.bck }
    41  func (ct *CT) Bucket() *cmn.Bck         { return (*cmn.Bck)(ct.bck) }
    42  func (ct *CT) Mountpath() *fs.Mountpath { return ct.mi }
    43  func (ct *CT) SizeBytes() int64         { return ct.size }
    44  func (ct *CT) MtimeUnix() int64         { return ct.mtime }
    45  func (ct *CT) Digest() uint64           { return ct.digest }
    46  
    47  func (ct *CT) LoadFromFS() error {
    48  	st, err := os.Stat(ct.FQN())
    49  	if err != nil {
    50  		return err
    51  	}
    52  	ct.size = st.Size()
    53  	ct.mtime = st.ModTime().UnixNano()
    54  	return nil
    55  }
    56  
    57  func (ct *CT) Uname() string {
    58  	if ct.uname == "" {
    59  		ct.uname = ct.bck.MakeUname(ct.objName)
    60  	}
    61  	return ct.uname
    62  }
    63  
    64  func (ct *CT) CacheIdx() int      { return fs.LcacheIdx(ct.digest) }
    65  func (ct *CT) getLomLocker() *nlc { return &g.locker[ct.CacheIdx()] }
    66  
    67  func (ct *CT) Lock(exclusive bool) {
    68  	nlc := ct.getLomLocker()
    69  	nlc.Lock(ct.Uname(), exclusive)
    70  }
    71  
    72  func (ct *CT) Unlock(exclusive bool) {
    73  	nlc := ct.getLomLocker()
    74  	nlc.Unlock(ct.Uname(), exclusive)
    75  }
    76  
    77  // e.g.: generate workfile FQN from object FQN:
    78  //  ct, err := NewCTFromFQN(fqn, nil)
    79  //  if err != nil { ... }
    80  //  fqn := ct.Make(fs.WorkfileType)
    81  //
    82  // e.g.: generate EC metafile FQN from bucket name, backend provider and object name:
    83  //  ct, err := NewCTFromBO(bckName, bckProvider, objName, nil)
    84  //  if err != nil { ... }
    85  //  fqn := ct.Make(fs.ECMetaType)
    86  
    87  func NewCTFromFQN(fqn string, b meta.Bowner) (ct *CT, err error) {
    88  	var (
    89  		hrwFQN string
    90  		parsed fs.ParsedFQN
    91  	)
    92  	if hrwFQN, err = ResolveFQN(fqn, &parsed); err != nil {
    93  		return nil, err
    94  	}
    95  	ct = &CT{
    96  		fqn:         fqn,
    97  		objName:     parsed.ObjName,
    98  		contentType: parsed.ContentType,
    99  		hrwFQN:      hrwFQN,
   100  		bck:         meta.CloneBck(&parsed.Bck),
   101  		mi:          parsed.Mountpath,
   102  		digest:      parsed.Digest,
   103  	}
   104  	if b != nil {
   105  		err = ct.bck.InitFast(b)
   106  	}
   107  	return ct, err
   108  }
   109  
   110  func NewCTFromBO(bck *cmn.Bck, objName string, b meta.Bowner, ctType ...string) (ct *CT, err error) {
   111  	ct = &CT{objName: objName, bck: meta.CloneBck(bck)}
   112  	if b != nil {
   113  		if err = ct.bck.Init(b); err != nil {
   114  			return
   115  		}
   116  	}
   117  	var digest uint64
   118  	ct.mi, digest, err = fs.Hrw(ct.bck.MakeUname(objName))
   119  	if err != nil {
   120  		return
   121  	}
   122  	ct.digest = digest
   123  	if len(ctType) == 0 {
   124  		ct.contentType = fs.ObjectType
   125  	} else {
   126  		ct.contentType = ctType[0]
   127  	}
   128  	ct.fqn = fs.CSM.Gen(ct, ct.contentType, "")
   129  	return
   130  }
   131  
   132  // Construct CT from LOM and change ContentType and FQN
   133  func NewCTFromLOM(lom *LOM, ctType string) *CT {
   134  	return &CT{
   135  		fqn:         fs.CSM.Gen(lom, ctType, ""),
   136  		objName:     lom.ObjName,
   137  		contentType: ctType,
   138  		bck:         lom.Bck(),
   139  		mi:          lom.mi,
   140  		digest:      lom.digest,
   141  	}
   142  }
   143  
   144  // Clone CT and change ContentType and FQN
   145  func (ct *CT) Clone(ctType string) *CT {
   146  	return &CT{
   147  		fqn:         fs.CSM.Gen(ct, ctType, ""),
   148  		objName:     ct.objName,
   149  		contentType: ctType,
   150  		bck:         ct.bck,
   151  		mi:          ct.mi,
   152  		digest:      ct.digest,
   153  	}
   154  }
   155  
   156  func (ct *CT) Make(toType string, pref ...string /*optional prefix*/) string {
   157  	var prefix string
   158  	cos.Assert(toType != "")
   159  
   160  	if len(pref) > 0 {
   161  		prefix = pref[0]
   162  	}
   163  	return fs.CSM.Gen(ct, toType, prefix)
   164  }
   165  
   166  // Save CT to local drives. If workFQN is set, it saves in two steps: first,
   167  // save to workFQN; second, rename workFQN to ct.FQN. If unset, it writes
   168  // directly to ct.FQN
   169  func (ct *CT) Write(reader io.Reader, size int64, workFQN ...string) (err error) {
   170  	bdir := ct.mi.MakePathBck(ct.Bucket())
   171  	if err := cos.Stat(bdir); err != nil {
   172  		return err
   173  	}
   174  	buf, slab := g.pmm.Alloc()
   175  	if len(workFQN) == 0 {
   176  		_, err = cos.SaveReader(ct.fqn, reader, buf, cos.ChecksumNone, size)
   177  	} else {
   178  		_, err = cos.SaveReaderSafe(workFQN[0], ct.fqn, reader, buf, cos.ChecksumNone, size)
   179  	}
   180  	slab.Free(buf)
   181  	return err
   182  }