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 }