github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/core/meta/bck.go (about) 1 // Package meta: cluster-level metadata 2 /* 3 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 4 */ 5 package meta 6 7 import ( 8 "fmt" 9 "net/http" 10 "net/url" 11 12 "github.com/NVIDIA/aistore/api/apc" 13 "github.com/NVIDIA/aistore/cmn" 14 "github.com/NVIDIA/aistore/cmn/debug" 15 ) 16 17 type Bck cmn.Bck 18 19 func NewBck(name, provider string, ns cmn.Ns, optProps ...*cmn.Bprops) *Bck { 20 var err error 21 provider, err = cmn.NormalizeProvider(provider) 22 debug.AssertNoErr(err) 23 bck := &Bck{Name: name, Provider: provider, Ns: ns} 24 if len(optProps) > 0 { 25 bck.Props = optProps[0] 26 debug.Assert(bck.Props != nil) 27 } 28 return bck 29 } 30 31 // clone (*meta.Bck | *cmn.Bck) <=> (cmn.Bck | meta.Bck) respectively 32 func (b *Bck) Clone() cmn.Bck { return cmn.Bck(*b) } 33 34 func CloneBck(bck *cmn.Bck) *Bck { 35 b := *bck 36 normp, err := cmn.NormalizeProvider(bck.Provider) 37 debug.Assert(err == nil, bck.Provider) 38 b.Provider = normp 39 return (*Bck)(&b) 40 } 41 42 // cast *meta.Bck => *cmn.Bck 43 func (b *Bck) Bucket() *cmn.Bck { return (*cmn.Bck)(b) } 44 45 // 46 // inline delegations => cmn.Bck 47 // 48 49 func (b *Bck) IsAIS() bool { return (*cmn.Bck)(b).IsAIS() } 50 func (b *Bck) HasProvider() bool { return (*cmn.Bck)(b).HasProvider() } 51 func (b *Bck) IsHTTP() bool { return (*cmn.Bck)(b).IsHTTP() } 52 func (b *Bck) IsCloud() bool { return (*cmn.Bck)(b).IsCloud() } 53 func (b *Bck) IsRemote() bool { return (*cmn.Bck)(b).IsRemote() } 54 func (b *Bck) IsRemoteAIS() bool { return (*cmn.Bck)(b).IsRemoteAIS() } 55 func (b *Bck) IsQuery() bool { return (*cmn.Bck)(b).IsQuery() } 56 func (b *Bck) RemoteBck() *cmn.Bck { return (*cmn.Bck)(b).RemoteBck() } 57 func (b *Bck) Validate() error { return (*cmn.Bck)(b).Validate() } 58 func (b *Bck) MakeUname(name string) string { return (*cmn.Bck)(b).MakeUname(name) } 59 func (b *Bck) Cname(name string) string { return (*cmn.Bck)(b).Cname(name) } 60 func (b *Bck) IsEmpty() bool { return (*cmn.Bck)(b).IsEmpty() } 61 func (b *Bck) HasVersioningMD() bool { return (*cmn.Bck)(b).HasVersioningMD() } 62 63 func (b *Bck) IsRemoteS3() bool { 64 if b.Provider == apc.AWS { 65 return true 66 } 67 backend := b.Backend() 68 return backend != nil && backend.Provider == apc.AWS 69 } 70 71 func (b *Bck) NewQuery() url.Values { return (*cmn.Bck)(b).NewQuery() } 72 func (b *Bck) AddToQuery(q url.Values) url.Values { return (*cmn.Bck)(b).AddToQuery(q) } 73 74 func (b *Bck) Backend() *Bck { backend := (*cmn.Bck)(b).Backend(); return (*Bck)(backend) } 75 76 func (b *Bck) AddUnameToQuery(q url.Values, uparam string) url.Values { 77 bck := (*cmn.Bck)(b) 78 return bck.AddUnameToQuery(q, uparam) 79 } 80 81 const aisBIDmask = uint64(1 << 63) 82 83 func (b *Bck) MaskBID(i int64) uint64 { 84 bck := (*cmn.Bck)(b) 85 if bck.IsAIS() { 86 return uint64(i) | aisBIDmask 87 } 88 return uint64(i) 89 } 90 91 func (b *Bck) unmaskBID() uint64 { 92 if b.Props == nil || b.Props.BID == 0 { 93 return 0 94 } 95 bck := (*cmn.Bck)(b) 96 if bck.IsAIS() { 97 return b.Props.BID ^ aisBIDmask 98 } 99 return b.Props.BID 100 } 101 102 func (b *Bck) String() string { 103 var ( 104 s string 105 bid = b.unmaskBID() 106 ) 107 bck := (*cmn.Bck)(b) 108 if bid == 0 { 109 return bck.String() 110 } 111 if backend := bck.Backend(); backend != nil { 112 s = ", backend=" + backend.String() 113 } 114 return fmt.Sprintf("%s(%#x%s)", bck, bid, s) 115 } 116 117 func (b *Bck) Equal(other *Bck, sameID, sameBackend bool) bool { 118 left, right := (*cmn.Bck)(b), (*cmn.Bck)(other) 119 if left.IsEmpty() || right.IsEmpty() { 120 return false 121 } 122 if !left.Equal(right) { 123 return false 124 } 125 if sameID && b.Props != nil && other.Props != nil && b.Props.BID != other.Props.BID { 126 return false 127 } 128 if !sameBackend { 129 return true 130 } 131 if backleft, backright := left.Backend(), right.Backend(); backleft != nil && backright != nil { 132 return backleft.Equal(backright) 133 } 134 return true 135 } 136 137 // when the bucket is not present in the BMD: 138 // - always returns the corresponding *DoesNotExist error 139 // - Cloud bucket: fills in the props with defaults from config 140 // - AIS bucket: sets the props to nil 141 // - Remote (Cloud or Remote AIS) bucket: caller can type-cast err.(*cmn.ErrRemoteBckNotFound) and proceed 142 func (b *Bck) Init(bowner Bowner) (err error) { 143 if err = b.Validate(); err != nil { 144 return 145 } 146 bmd := bowner.Get() 147 if err = b.init(bmd); err != nil { 148 return 149 } 150 if backend := b.Backend(); backend != nil { 151 if backend.Props == nil { 152 err = backend.init(bmd) 153 } else { 154 p, exists := bmd.Get(backend) 155 if exists { 156 exists = p.BID == backend.Props.BID 157 } 158 if !exists { 159 err = cmn.NewErrRemoteBckNotFound(backend.Bucket()) 160 } else if backend.Props != p { 161 backend.Props = p 162 } 163 } 164 } 165 return 166 } 167 168 // part of lom.init (compare with the above) 169 func (b *Bck) InitFast(bowner Bowner) (err error) { 170 bmd := bowner.Get() 171 if err = b.init(bmd); err != nil { 172 return 173 } 174 if backend := b.Backend(); backend != nil && backend.Props == nil { 175 debug.Assert(apc.IsRemoteProvider(backend.Provider)) 176 err = backend.init(bmd) 177 } 178 return 179 } 180 181 func (b *Bck) InitNoBackend(bowner Bowner) error { return b.init(bowner.Get()) } 182 183 func (b *Bck) init(bmd *BMD) error { 184 switch { 185 case b.Provider == "": // ais: is the default 186 b.Provider = apc.AIS 187 bmd.initBckGlobalNs(b) 188 case apc.IsRemoteProvider(b.Provider): 189 bmd.initBck(b) 190 default: 191 b.Props, _ = bmd.Get(b) 192 } 193 if b.Props != nil { 194 return nil // ok 195 } 196 if b.IsAIS() { 197 return cmn.NewErrBckNotFound(b.Bucket()) 198 } 199 return cmn.NewErrRemoteBckNotFound(b.Bucket()) 200 } 201 202 // to support s3 clients: 203 // find an already existing bucket by name (and nothing else) 204 // returns an error when name cannot be unambiguously resolved to a single bucket 205 func InitByNameOnly(bckName string, bowner Bowner) (bck *Bck, err error, ecode int) { 206 bmd := bowner.Get() 207 all := bmd.getAllByName(bckName) 208 if all == nil { 209 err = cmn.NewErrBckNotFound(&cmn.Bck{Name: bckName}) 210 ecode = http.StatusNotFound 211 } else if len(all) == 1 { 212 bck = &all[0] 213 if bck.Props == nil { 214 err = cmn.NewErrBckNotFound(bck.Bucket()) 215 ecode = http.StatusNotFound 216 } else if backend := bck.Backend(); backend != nil && backend.Props == nil { 217 debug.Assert(apc.IsRemoteProvider(backend.Provider)) 218 err = backend.init(bmd) 219 } 220 } else { 221 err = fmt.Errorf("cannot unambiguously resolve bucket name %q to a single bucket (%v)", 222 bckName, all) 223 ecode = http.StatusUnprocessableEntity 224 } 225 return 226 } 227 228 func (b *Bck) CksumConf() (conf *cmn.CksumConf) { return &b.Props.Cksum } 229 230 func (b *Bck) VersionConf() cmn.VersionConf { 231 if backend := b.Backend(); backend != nil && backend.Props != nil { 232 conf := backend.Props.Versioning 233 conf.ValidateWarmGet = b.Props.Versioning.ValidateWarmGet 234 return conf 235 } 236 return b.Props.Versioning 237 } 238 239 // 240 // access perms 241 // 242 243 func (b *Bck) Allow(bit apc.AccessAttrs) error { return b.checkAccess(bit) } 244 245 func (b *Bck) checkAccess(bit apc.AccessAttrs) (err error) { 246 if b.Props.Access.Has(bit) { 247 return 248 } 249 op := apc.AccessOp(bit) 250 err = cmn.NewBucketAccessDenied(b.String(), op, b.Props.Access) 251 return 252 } 253 254 func (b *Bck) MaxPageSize() int64 { 255 switch b.Provider { 256 case apc.AIS: 257 return apc.MaxPageSizeAIS 258 case apc.AWS: 259 // ref: 260 // - https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-pagination.html#cli-usage-pagination-serverside 261 // - https://docs.openstack.org/swift/latest/api/pagination.html 262 if b == nil || b.Props == nil || b.Props.Extra.AWS.MaxPageSize == 0 { 263 return apc.MaxPageSizeAWS 264 } 265 return b.Props.Extra.AWS.MaxPageSize 266 case apc.GCP: 267 // ref: https://cloud.google.com/storage/docs/json_api/v1/objects/list#parameters 268 return apc.MaxPageSizeGCP 269 case apc.Azure: 270 // ref: https://docs.microsoft.com/en-us/connectors/azureblob/#general-limits 271 return apc.MaxPageSizeAzure 272 default: 273 return 1000 274 } 275 }