github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/xact/xs/brename.go (about)

     1  // Package xs is a collection of eXtended actions (xactions), including multi-object
     2  // operations, list-objects, (cluster) rebalance and (target) resilver, ETL, and more.
     3  /*
     4   * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
     5   */
     6  package xs
     7  
     8  import (
     9  	"fmt"
    10  	"sync"
    11  	"time"
    12  
    13  	"github.com/NVIDIA/aistore/api/apc"
    14  	"github.com/NVIDIA/aistore/cmn/cos"
    15  	"github.com/NVIDIA/aistore/cmn/debug"
    16  	"github.com/NVIDIA/aistore/cmn/nlog"
    17  	"github.com/NVIDIA/aistore/core"
    18  	"github.com/NVIDIA/aistore/core/meta"
    19  	"github.com/NVIDIA/aistore/xact"
    20  	"github.com/NVIDIA/aistore/xact/xreg"
    21  )
    22  
    23  // tunables
    24  const (
    25  	bmvAvgWait  = 2 * time.Minute
    26  	bmvMaxWait  = 2 * time.Hour
    27  	bmvMaxSleep = 30 * time.Second
    28  )
    29  
    30  type (
    31  	bckRename struct {
    32  		bckFrom *meta.Bck
    33  		bckTo   *meta.Bck
    34  		rebID   string
    35  		xact.Base
    36  	}
    37  	bmvFactory struct {
    38  		xreg.RenewBase
    39  		xctn  *bckRename
    40  		cargs *xreg.BckRenameArgs
    41  		phase string
    42  	}
    43  	TestBmvFactory = bmvFactory
    44  )
    45  
    46  // interface guard
    47  var (
    48  	_ core.Xact      = (*bckRename)(nil)
    49  	_ xreg.Renewable = (*bmvFactory)(nil)
    50  )
    51  
    52  ////////////////
    53  // bmvFactory //
    54  ////////////////
    55  
    56  func (*bmvFactory) New(args xreg.Args, bck *meta.Bck) xreg.Renewable {
    57  	p := &bmvFactory{RenewBase: xreg.RenewBase{Args: args, Bck: bck}, cargs: args.Custom.(*xreg.BckRenameArgs)}
    58  	return p
    59  }
    60  
    61  func (*bmvFactory) Kind() string     { return apc.ActMoveBck }
    62  func (p *bmvFactory) Get() core.Xact { return p.xctn }
    63  
    64  func (p *bmvFactory) Start() error {
    65  	p.xctn = newBckRename(p.UUID(), p.Kind(), p.cargs.RebID, p.Bck, p.cargs.BckFrom, p.cargs.BckTo)
    66  	return nil
    67  }
    68  
    69  func (p *bmvFactory) WhenPrevIsRunning(prevEntry xreg.Renewable) (wpr xreg.WPR, err error) {
    70  	if p.phase == apc.ActBegin {
    71  		if !prevEntry.Get().Finished() {
    72  			err = fmt.Errorf("%s: cannot(%s=>%s) older rename still in progress",
    73  				p.Kind(), p.cargs.BckFrom, p.cargs.BckTo)
    74  			return
    75  		}
    76  		// TODO: more checks
    77  	}
    78  	prev := prevEntry.(*bmvFactory)
    79  	bckEq := prev.cargs.BckTo.Equal(p.cargs.BckTo, false /*sameID*/, false /* same backend */)
    80  	if prev.phase == apc.ActBegin && p.phase == apc.ActCommit && bckEq {
    81  		prev.phase = apc.ActCommit // transition
    82  		wpr = xreg.WprUse
    83  		return
    84  	}
    85  	err = fmt.Errorf("%s(%s=>%s, phase %s): cannot %s(=>%s)",
    86  		p.Kind(), prev.cargs.BckFrom, prev.cargs.BckTo, prev.phase, p.phase, p.cargs.BckFrom)
    87  	return
    88  }
    89  
    90  ///////////////
    91  // bckRename //
    92  ///////////////
    93  
    94  func newBckRename(uuid, kind, rebID string, bck, bckFrom, bckTo *meta.Bck) (x *bckRename) {
    95  	// NOTE: `bck` = `bckTo` = (the new name) while `bckFrom` is the existing bucket to be renamed
    96  	debug.Assert(bck.Equal(bckTo, false, true), bck.String()+" vs "+bckTo.String())
    97  
    98  	debug.Assert(xact.IsValidRebID(rebID), rebID)
    99  	x = &bckRename{bckFrom: bckFrom, bckTo: bckTo, rebID: rebID}
   100  	x.InitBase(uuid, kind, bck)
   101  	return
   102  }
   103  
   104  // NOTE: assuming that rebalance takes longer than resilvering
   105  func (r *bckRename) Run(wg *sync.WaitGroup) {
   106  	var (
   107  		total time.Duration
   108  		flt   = xreg.Flt{ID: r.rebID, Kind: apc.ActRebalance}
   109  		sleep = cos.ProbingFrequency(bmvAvgWait)
   110  	)
   111  	nlog.Infoln(r.Name())
   112  	wg.Done()
   113  loop:
   114  	for total < bmvMaxWait {
   115  		time.Sleep(sleep)
   116  		total += sleep
   117  		rebStats, err := xreg.GetSnap(flt)
   118  		debug.AssertNoErr(err)
   119  		for _, stat := range rebStats {
   120  			if stat.Finished() || stat.IsAborted() {
   121  				break loop
   122  			}
   123  		}
   124  		if total > bmvAvgWait {
   125  			sleep = min(sleep+sleep/2, bmvMaxSleep)
   126  		}
   127  	}
   128  	if total >= bmvMaxWait {
   129  		r.AddErr(fmt.Errorf("timeout %s", total))
   130  	}
   131  	core.T.BMDVersionFixup(nil, r.bckFrom.Clone()) // piggyback bucket renaming (last step) on getting updated BMD
   132  	r.Finish()
   133  }
   134  
   135  func (r *bckRename) String() string {
   136  	return fmt.Sprintf("%s <= %s", r.Base.String(), r.bckFrom)
   137  }
   138  
   139  func (r *bckRename) Name() string {
   140  	return fmt.Sprintf("%s <= %s", r.Base.Name(), r.bckFrom)
   141  }
   142  
   143  func (r *bckRename) FromTo() (*meta.Bck, *meta.Bck) { return r.bckFrom, r.bckTo }
   144  
   145  func (r *bckRename) Snap() (snap *core.Snap) {
   146  	snap = &core.Snap{}
   147  	r.ToSnap(snap)
   148  
   149  	snap.IdleX = r.IsIdle()
   150  	f, t := r.FromTo()
   151  	snap.SrcBck, snap.DstBck = f.Clone(), t.Clone()
   152  	return
   153  }