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  }