github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/cmn/api.go (about) 1 // Package cmn provides common constants, types, and utilities for AIS clients 2 // and AIStore. 3 /* 4 * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved. 5 */ 6 package cmn 7 8 import ( 9 "errors" 10 "fmt" 11 "reflect" 12 "sort" 13 "strings" 14 15 "github.com/NVIDIA/aistore/api/apc" 16 "github.com/NVIDIA/aistore/cmn/cos" 17 "github.com/NVIDIA/aistore/cmn/debug" 18 "github.com/NVIDIA/aistore/cmn/feat" 19 "github.com/NVIDIA/aistore/cmn/nlog" 20 ) 21 22 // Bprops - manageable, user-configurable, and inheritable (from cluster config). 23 // Includes per-bucket user-configurable checksum, version, LRU, erasure-coding, and more. 24 // 25 // At creation time, unless specified via api.CreateBucket, new bucket by default 26 // inherits its properties from the global configuration. 27 // * see api.CreateBucket for details 28 // * for all inheritable props, see DefaultProps below 29 // 30 // Naming convention for setting/getting the particular props is defined as 31 // joining the json tags with dot. Eg. when referring to `EC.Enabled` field 32 // one would need to write `ec.enabled`. For more info refer to `IterFields`. 33 34 const ( 35 PropBucketAccessAttrs = "access" // Bucket access attributes. 36 PropBucketVerEnabled = "versioning.enabled" // Enable/disable object versioning in a bucket. 37 PropBucketCreated = "created" // Bucket creation time. 38 PropBackendBck = "backend_bck" 39 PropBackendBckName = PropBackendBck + ".name" 40 PropBackendBckProvider = PropBackendBck + ".provider" 41 ) 42 43 type ( 44 Bprops struct { 45 BackendBck Bck `json:"backend_bck,omitempty"` // makes remote bucket out of a given ais bucket 46 Extra ExtraProps `json:"extra,omitempty" list:"omitempty"` 47 WritePolicy WritePolicyConf `json:"write_policy"` 48 Provider string `json:"provider" list:"readonly"` // backend provider 49 Renamed string `list:"omit"` // non-empty if the bucket has been renamed 50 Cksum CksumConf `json:"checksum"` // the bucket's checksum 51 EC ECConf `json:"ec"` // erasure coding 52 LRU LRUConf `json:"lru"` // LRU (watermarks and enabled/disabled) 53 Mirror MirrorConf `json:"mirror"` // mirroring 54 Access apc.AccessAttrs `json:"access,string"` // access permissions 55 Features feat.Flags `json:"features,string"` // assorted features from feat.Bucket 56 BID uint64 `json:"bid,string" list:"omit"` // unique ID 57 Created int64 `json:"created,string" list:"readonly"` // creation timestamp 58 Versioning VersionConf `json:"versioning"` // versioning (see "inherit") 59 } 60 61 ExtraProps struct { 62 AWS ExtraPropsAWS `json:"aws,omitempty" list:"omitempty"` 63 HTTP ExtraPropsHTTP `json:"http,omitempty" list:"omitempty"` 64 HDFS ExtraPropsHDFS `json:"hdfs,omitempty" list:"omitempty"` // NOTE: obsolete; rm with meta-version 65 } 66 ExtraToSet struct { // ref. bpropsFilterExtra 67 AWS *ExtraPropsAWSToSet `json:"aws"` 68 HTTP *ExtraPropsHTTPToSet `json:"http"` 69 HDFS *ExtraPropsHDFSToSet `json:"hdfs"` // ditto 70 } 71 72 ExtraPropsAWS struct { 73 CloudRegion string `json:"cloud_region,omitempty"` 74 75 // from https://github.com/aws/aws-sdk-go/blob/main/aws/config.go: 76 // - "An optional endpoint URL (hostname only or fully qualified URI) 77 // that overrides the default generated endpoint." 78 Endpoint string `json:"endpoint,omitempty"` 79 80 // from https://github.com/aws/aws-sdk-go/blob/main/aws/session/session.go: 81 // - "Overrides the config profile the Session should be created from. If not 82 // set the value of the environment variable will be loaded (AWS_PROFILE, 83 // or AWS_DEFAULT_PROFILE if the Shared Config is enabled)." 84 Profile string `json:"profile,omitempty"` 85 86 // Amazon S3: 1000 87 // - https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-pagination.html#cli-usage-pagination-serverside 88 // vs OpenStack Swift: 10,000 89 // - https://docs.openstack.org/swift/latest/api/pagination.html 90 MaxPageSize int64 `json:"max_pagesize,omitempty"` 91 } 92 ExtraPropsAWSToSet struct { 93 CloudRegion *string `json:"cloud_region"` 94 Endpoint *string `json:"endpoint"` 95 Profile *string `json:"profile"` 96 MaxPageSize *int64 `json:"max_pagesize"` 97 } 98 99 ExtraPropsHTTP struct { 100 // Original URL prior to hashing. 101 OrigURLBck string `json:"original_url,omitempty" list:"readonly"` 102 } 103 ExtraPropsHTTPToSet struct { 104 OrigURLBck *string `json:"original_url"` 105 } 106 107 ExtraPropsHDFS struct { 108 // Reference directory. 109 RefDirectory string `json:"ref_directory,omitempty"` 110 } 111 ExtraPropsHDFSToSet struct { 112 RefDirectory *string `json:"ref_directory"` 113 } 114 115 // Once validated, BpropsToSet are copied to Bprops. 116 // The struct may have extra fields that do not exist in Bprops. 117 // Add tag 'copy:"skip"' to ignore those fields when copying values. 118 BpropsToSet struct { 119 BackendBck *BackendBckToSet `json:"backend_bck,omitempty"` 120 Versioning *VersionConfToSet `json:"versioning,omitempty"` 121 Cksum *CksumConfToSet `json:"checksum,omitempty"` 122 LRU *LRUConfToSet `json:"lru,omitempty"` 123 Mirror *MirrorConfToSet `json:"mirror,omitempty"` 124 EC *ECConfToSet `json:"ec,omitempty"` 125 Access *apc.AccessAttrs `json:"access,string,omitempty"` 126 Features *feat.Flags `json:"features,string,omitempty"` 127 WritePolicy *WritePolicyConfToSet `json:"write_policy,omitempty"` 128 Extra *ExtraToSet `json:"extra,omitempty"` 129 Force bool `json:"force,omitempty" copy:"skip" list:"omit"` 130 } 131 132 BackendBckToSet struct { 133 Name *string `json:"name"` 134 Provider *string `json:"provider"` 135 } 136 ) 137 138 ///////////////// 139 // Bprops // 140 ///////////////// 141 142 // By default, created buckets inherit their properties from the cluster (global) configuration. 143 // Global configuration, in turn, is protected versioned, checksummed, and replicated across the entire cluster. 144 // 145 // * Bucket properties can be changed at any time via `api.SetBprops`. 146 // * In addition, `api.CreateBucket` allows to specify (non-default) properties at bucket creation time. 147 // * Inherited defaults include checksum, LRU, etc. configurations - see below. 148 // * By default, LRU is disabled for AIS (`ais://`) buckets. 149 // 150 // See also: 151 // - github.com/NVIDIA/aistore/blob/main/docs/bucket.md#default-bucket-properties 152 // - BpropsToSet (above) 153 // - ais.defaultBckProps() 154 func (bck *Bck) DefaultProps(c *ClusterConfig) *Bprops { 155 lru := c.LRU 156 if bck.IsAIS() { 157 lru.Enabled = false 158 } 159 cksum := c.Cksum 160 if cksum.Type == "" { // tests with empty cluster config 161 cksum.Type = cos.ChecksumXXHash 162 } 163 wp := c.WritePolicy 164 if wp.MD.IsImmediate() { 165 wp.MD = apc.WriteImmediate 166 } 167 if wp.Data.IsImmediate() { 168 wp.Data = apc.WriteImmediate 169 } 170 return &Bprops{ 171 Cksum: cksum, 172 LRU: lru, 173 Mirror: c.Mirror, 174 Versioning: c.Versioning, 175 Access: apc.AccessAll, 176 EC: c.EC, 177 WritePolicy: wp, 178 Features: c.Features, 179 } 180 } 181 182 func (bp *Bprops) SetProvider(provider string) { 183 debug.Assert(apc.IsProvider(provider)) 184 bp.Provider = provider 185 } 186 187 func (bp *Bprops) Clone() *Bprops { 188 to := *bp 189 debug.Assert(bp.Equal(&to)) 190 return &to 191 } 192 193 func (bp *Bprops) Equal(other *Bprops) (eq bool) { 194 src := *bp 195 src.BID = other.BID 196 src.Created = other.Created 197 eq = reflect.DeepEqual(&src, other) 198 return 199 } 200 201 func (bp *Bprops) Validate(targetCnt int) error { 202 debug.Assert(apc.IsProvider(bp.Provider)) 203 if !bp.BackendBck.IsEmpty() { 204 if bp.Provider != apc.AIS { 205 return fmt.Errorf("wrong bucket provider %q: only AIS buckets can have remote backend (%q)", 206 bp.Provider, bp.BackendBck) 207 } 208 if bp.BackendBck.Provider == "" { 209 return fmt.Errorf("backend bucket %q: provider is empty", bp.BackendBck) 210 } 211 if bp.BackendBck.Name == "" { 212 return fmt.Errorf("backend bucket %q name is empty", bp.BackendBck) 213 } 214 if !bp.BackendBck.IsRemote() { 215 return fmt.Errorf("backend bucket %q must be remote", bp.BackendBck) 216 } 217 } 218 219 // run assorted props validators 220 var softErr error 221 for _, pv := range []PropsValidator{&bp.Cksum, &bp.Mirror, &bp.EC, &bp.Extra, &bp.WritePolicy} { 222 var err error 223 if pv == &bp.EC { 224 err = bp.EC.ValidateAsProps(targetCnt) 225 } else if pv == &bp.Extra { 226 err = bp.Extra.ValidateAsProps(bp.Provider) 227 } else { 228 err = pv.ValidateAsProps() 229 } 230 if err != nil { 231 if !IsErrSoft(err) { 232 return err 233 } 234 softErr = err 235 } 236 } 237 if bp.Mirror.Enabled && bp.EC.Enabled { 238 nlog.Warningln("n-way mirroring and EC are both enabled at the same time on the same bucket") 239 } 240 241 // not inheriting cluster-scope features 242 names := bp.Features.Names() 243 for _, n := range names { 244 if !feat.IsBucketScope(n) { 245 bp.Features = bp.Features.ClearName(n) 246 } 247 } 248 return softErr 249 } 250 251 func (bp *Bprops) Apply(propsToSet *BpropsToSet) { 252 err := copyProps(propsToSet, bp, apc.Daemon) 253 debug.AssertNoErr(err) 254 } 255 256 // 257 // BpropsToSet 258 // 259 260 func NewBpropsToSet(nvs cos.StrKVs) (props *BpropsToSet, err error) { 261 props = &BpropsToSet{} 262 for key, val := range nvs { 263 name, value := strings.ToLower(key), val 264 265 // HACK: Some of the fields are present in `Bprops` and not in `BpropsToSet`. 266 // Thus, if user wants to change such field, `unknown field` will be returned. 267 // To make UX more friendly we attempt to set the value in an empty `Bprops` first. 268 if err := UpdateFieldValue(&Bprops{}, name, value); err != nil { 269 return props, err 270 } 271 272 if err := UpdateFieldValue(props, name, value); err != nil { 273 return props, err 274 } 275 } 276 return 277 } 278 279 func (c *ExtraProps) ValidateAsProps(arg ...any) error { 280 provider, ok := arg[0].(string) 281 debug.Assert(ok) 282 if provider == apc.HTTP && c.HTTP.OrigURLBck == "" { 283 return errors.New("original bucket URL must be set for a bucket with HTTP provider") 284 } 285 return nil 286 } 287 288 // 289 // Bucket Summary - result for a given bucket, and all results ------------------------------------------------- 290 // 291 292 type ( 293 BsummResult struct { 294 Bck 295 apc.BsummResult 296 } 297 AllBsummResults []*BsummResult 298 ) 299 300 // interface guard 301 var _ sort.Interface = (*AllBsummResults)(nil) 302 303 func (s AllBsummResults) Len() int { return len(s) } 304 func (s AllBsummResults) Less(i, j int) bool { return s[i].Bck.Less(&s[j].Bck) } 305 func (s AllBsummResults) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 306 307 func (s AllBsummResults) Aggregate(from *BsummResult) AllBsummResults { 308 for _, to := range s { 309 if to.Bck.Equal(&from.Bck) { 310 aggr(from, to) 311 return s 312 } 313 } 314 s = append(s, from) 315 return s 316 } 317 318 // across targets 319 func aggr(from, to *BsummResult) { 320 if from.ObjSize.Min < to.ObjSize.Min { 321 to.ObjSize.Min = from.ObjSize.Min 322 } 323 if from.ObjSize.Max > to.ObjSize.Max { 324 to.ObjSize.Max = from.ObjSize.Max 325 } 326 to.ObjCount.Present += from.ObjCount.Present 327 to.ObjCount.Remote += from.ObjCount.Remote 328 to.TotalSize.OnDisk += from.TotalSize.OnDisk 329 to.TotalSize.PresentObjs += from.TotalSize.PresentObjs 330 to.TotalSize.RemoteObjs += from.TotalSize.RemoteObjs 331 } 332 333 func (s AllBsummResults) Finalize(dsize map[string]uint64, testingEnv bool) { 334 var totalDisksSize uint64 335 for _, tsiz := range dsize { 336 totalDisksSize += tsiz 337 if testingEnv { 338 break 339 } 340 } 341 for _, summ := range s { 342 if summ.ObjCount.Present > 0 { 343 summ.ObjSize.Avg = int64(cos.DivRoundU64(summ.TotalSize.PresentObjs, summ.ObjCount.Present)) 344 } 345 summ.UsedPct = cos.DivRoundU64(summ.TotalSize.OnDisk*100, totalDisksSize) 346 } 347 } 348 349 // 350 // Multi-object (list|range) operations source bucket => dest. bucket --------------------------------------- 351 // 352 353 type ( 354 // ArchiveBckMsg contains parameters to archive mutiple objects from the specified (source) bucket. 355 // Destination bucket may the same as the source or a different one. 356 // -------------------- NOTE on terminology: --------------------- 357 // "archive" is any (.tar, .tgz/.tar.gz, .zip, .tar.lz4) formatted object often also called "shard" 358 // 359 // See also: apc.PutApndArchArgs 360 ArchiveBckMsg struct { 361 ToBck Bck `json:"tobck"` 362 apc.ArchiveMsg 363 } 364 365 // Multi-object copy & transform (see also: TCBMsg) 366 TCObjsMsg struct { 367 ToBck Bck `json:"tobck"` 368 apc.TCObjsMsg 369 } 370 ) 371 372 func (msg *ArchiveBckMsg) Cname() string { return msg.ToBck.Cname(msg.ArchName) }