github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/reb/utils.go (about)

     1  // Package reb provides global cluster-wide rebalance upon adding/removing storage nodes.
     2  /*
     3   * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package reb
     6  
     7  import (
     8  	"fmt"
     9  	"strconv"
    10  	"time"
    11  
    12  	"github.com/NVIDIA/aistore/cmn"
    13  	"github.com/NVIDIA/aistore/cmn/cos"
    14  	"github.com/NVIDIA/aistore/cmn/nlog"
    15  	"github.com/NVIDIA/aistore/core"
    16  	"github.com/NVIDIA/aistore/core/meta"
    17  	"github.com/NVIDIA/aistore/transport"
    18  	"github.com/NVIDIA/aistore/xact/xs"
    19  )
    20  
    21  func (reb *Reb) RebID() int64           { return reb.rebID.Load() }
    22  func (reb *Reb) FilterAdd(uname []byte) { reb.filterGFN.Insert(uname) }
    23  
    24  // (limited usage; compare with `abortAndBroadcast` below)
    25  func (reb *Reb) AbortLocal(olderSmapV int64, err error) {
    26  	if xreb := reb.xctn(); xreb != nil {
    27  		// double-check
    28  		smap := reb.smap.Load()
    29  		if smap.Version == olderSmapV {
    30  			if xreb.Abort(err) {
    31  				nlog.Warningf("%v - aborted", err)
    32  			}
    33  		}
    34  	}
    35  }
    36  
    37  func (reb *Reb) xctn() *xs.Rebalance        { return reb.xreb.Load() }
    38  func (reb *Reb) setXact(xctn *xs.Rebalance) { reb.xreb.Store(xctn) }
    39  
    40  func (reb *Reb) logHdr(rebID int64, smap *meta.Smap, initializing ...bool) string {
    41  	smapv := "v<???>"
    42  	if smap != nil {
    43  		smapv = "v" + strconv.FormatInt(smap.Version, 10)
    44  	}
    45  	s := fmt.Sprintf("%s[g%d,%s", core.T, rebID, smapv)
    46  	if len(initializing) > 0 {
    47  		return s + "]"
    48  	}
    49  	stage := stages[reb.stages.stage.Load()]
    50  	return fmt.Sprintf("%s,%s]", s, stage)
    51  }
    52  
    53  func (reb *Reb) warnID(remoteID int64, tid string) (s string) {
    54  	const warn = "t[%s] runs %s g[%d] (local g[%d])"
    55  	if id := reb.RebID(); id < remoteID {
    56  		s = fmt.Sprintf(warn, tid, "newer", remoteID, id)
    57  	} else {
    58  		s = fmt.Sprintf(warn, tid, "older", remoteID, id)
    59  	}
    60  	return
    61  }
    62  
    63  func (reb *Reb) _waitForSmap() (smap *meta.Smap, err error) {
    64  	smap = reb.smap.Load()
    65  	if smap != nil {
    66  		return
    67  	}
    68  	var (
    69  		config = cmn.GCO.Get()
    70  		sleep  = cmn.Rom.CplaneOperation()
    71  		maxwt  = config.Rebalance.DestRetryTime.D()
    72  		curwt  time.Duration
    73  	)
    74  	maxwt = min(maxwt, config.Timeout.SendFile.D()/3)
    75  	nlog.Warningf("%s: waiting to start...", core.T)
    76  	time.Sleep(sleep)
    77  	for curwt < maxwt {
    78  		smap = reb.smap.Load()
    79  		if smap != nil {
    80  			return
    81  		}
    82  		time.Sleep(sleep)
    83  		curwt += sleep
    84  	}
    85  	return nil, fmt.Errorf("%s: timed out waiting for usable Smap", core.T)
    86  }
    87  
    88  // Rebalance moves to the next stage:
    89  // - update internal stage
    90  // - send notification to all other targets that this one is in a new stage
    91  func (reb *Reb) changeStage(newStage uint32) {
    92  	// first, set own stage
    93  	reb.stages.stage.Store(newStage)
    94  	var (
    95  		req = stageNtfn{
    96  			daemonID: core.T.SID(), stage: newStage, rebID: reb.rebID.Load(),
    97  		}
    98  		hdr = transport.ObjHdr{}
    99  	)
   100  	hdr.Opaque = reb.encodeStageNtfn(&req)
   101  	// second, notify all
   102  	if err := reb.pushes.Send(&transport.Obj{Hdr: hdr}, nil); err != nil {
   103  		nlog.Warningf("Failed to broadcast ack %s: %v", stages[newStage], err)
   104  	}
   105  }
   106  
   107  // Aborts global rebalance and notifies all other targets.
   108  // (compare with `Abort` above)
   109  func (reb *Reb) abortAndBroadcast(err error) {
   110  	xreb := reb.xctn()
   111  	if xreb == nil || !xreb.Abort(err) {
   112  		return
   113  	}
   114  	nlog.InfoDepth(1, xreb.Name(), "abort-and-bcast", err)
   115  
   116  	var (
   117  		req = stageNtfn{
   118  			daemonID: core.T.SID(),
   119  			rebID:    reb.RebID(),
   120  			stage:    rebStageAbort,
   121  		}
   122  		hdr = transport.ObjHdr{}
   123  	)
   124  	hdr.Opaque = reb.encodeStageNtfn(&req)
   125  	if err := reb.pushes.Send(&transport.Obj{Hdr: hdr}, nil); err != nil {
   126  		nlog.Errorf("Failed to broadcast abort notification: %v", err)
   127  	}
   128  }
   129  
   130  // Returns if the target is quiescent: transport queue is empty, or xaction
   131  // has already aborted or finished.
   132  func (reb *Reb) isQuiescent() bool {
   133  	// Finished or aborted xaction = no traffic
   134  	xctn := reb.xctn()
   135  	if xctn == nil || xctn.IsAborted() || xctn.Finished() {
   136  		return true
   137  	}
   138  
   139  	// Check for both regular and EC transport queues are empty
   140  	return reb.inQueue.Load() == 0 && reb.onAir.Load() == 0
   141  }
   142  
   143  /////////////
   144  // lomAcks TODO: lomAck.q[lom.Uname()] = lom.Bprops().BID and, subsequently, LIF => LOM reinit
   145  /////////////
   146  
   147  func (reb *Reb) lomAcks() *[cos.MultiSyncMapCount]*lomAcks { return &reb.lomacks }
   148  
   149  func (reb *Reb) addLomAck(lom *core.LOM) {
   150  	lomAck := reb.lomAcks()[lom.CacheIdx()]
   151  	lomAck.mu.Lock()
   152  	lomAck.q[lom.Uname()] = lom
   153  	lomAck.mu.Unlock()
   154  }
   155  
   156  func (reb *Reb) delLomAck(lom *core.LOM, rebID int64, freeLOM bool) {
   157  	if rebID != 0 && rebID != reb.rebID.Load() {
   158  		return
   159  	}
   160  	lomAck := reb.lomAcks()[lom.CacheIdx()]
   161  	lomAck.mu.Lock()
   162  	if rebID == 0 || rebID == reb.rebID.Load() {
   163  		if lomOrig, ok := lomAck.q[lom.Uname()]; ok {
   164  			delete(lomAck.q, lom.Uname())
   165  			if freeLOM {
   166  				// counting acknowledged migrations (as initiator)
   167  				xreb := reb.xctn()
   168  				xreb.ObjsAdd(1, lomOrig.SizeBytes())
   169  
   170  				core.FreeLOM(lomOrig)
   171  			}
   172  		}
   173  	}
   174  	lomAck.mu.Unlock()
   175  }