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

     1  // Package xs_test contains xs unit test.
     2  /*
     3   * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package xs_test
     6  
     7  import (
     8  	"errors"
     9  	"fmt"
    10  	"os"
    11  	"sync"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/NVIDIA/aistore/api/apc"
    16  	"github.com/NVIDIA/aistore/cmn"
    17  	"github.com/NVIDIA/aistore/cmn/cos"
    18  	"github.com/NVIDIA/aistore/core"
    19  	"github.com/NVIDIA/aistore/core/meta"
    20  	"github.com/NVIDIA/aistore/core/mock"
    21  	"github.com/NVIDIA/aistore/fs"
    22  	"github.com/NVIDIA/aistore/space"
    23  	"github.com/NVIDIA/aistore/tools/tassert"
    24  	"github.com/NVIDIA/aistore/xact"
    25  	"github.com/NVIDIA/aistore/xact/xreg"
    26  	"github.com/NVIDIA/aistore/xact/xs"
    27  )
    28  
    29  func init() {
    30  	config := cmn.GCO.BeginUpdate()
    31  	config.Log.Level = "3"
    32  	config.ConfigDir = "/tmp/ais-tests"
    33  	config.Timeout.CplaneOperation = cos.Duration(2 * time.Second)
    34  	config.Timeout.MaxKeepalive = cos.Duration(4 * time.Second)
    35  	config.Timeout.MaxHostBusy = cos.Duration(20 * time.Second)
    36  	config.TestFSP.Count = 1
    37  	cmn.GCO.CommitUpdate(config)
    38  
    39  	xreg.Init()
    40  	xs.Xreg(false)
    41  	fs.TestNew(nil)
    42  }
    43  
    44  // Smoke tests for xactions
    45  func TestXactionRenewLRU(t *testing.T) {
    46  	var (
    47  		num    = 10
    48  		xactCh = make(chan xreg.RenewRes, num)
    49  		wg     = &sync.WaitGroup{}
    50  	)
    51  	xreg.TestReset()
    52  
    53  	xreg.RegNonBckXact(&space.TestFactory{})
    54  	defer xreg.AbortAll(nil)
    55  	cos.InitShortID(0)
    56  
    57  	wg.Add(num)
    58  	for range num {
    59  		go func() {
    60  			xactCh <- xreg.RenewLRU(cos.GenUUID())
    61  			wg.Done()
    62  		}()
    63  	}
    64  	wg.Wait()
    65  	close(xactCh)
    66  
    67  	newCnt := 0
    68  	for rns := range xactCh {
    69  		if !rns.IsRunning() {
    70  			newCnt++
    71  		}
    72  	}
    73  	tassert.Errorf(t, newCnt == 1, "expected just one LRU xaction to be created, got %d", newCnt)
    74  }
    75  
    76  func TestXactionRenewPrefetch(t *testing.T) {
    77  	var (
    78  		msg = &apc.PrefetchMsg{}
    79  		bmd = mock.NewBaseBownerMock()
    80  		bck = meta.NewBck(
    81  			"test", apc.GCP, cmn.NsGlobal,
    82  			&cmn.Bprops{Cksum: cmn.CksumConf{Type: cos.ChecksumXXHash}},
    83  		)
    84  		tMock = mock.NewTarget(bmd)
    85  	)
    86  	core.T = tMock
    87  	xreg.TestReset()
    88  	bmd.Add(bck)
    89  
    90  	_ = cos.CreateDir("/tmp/prefetch")
    91  	_, err := fs.Add("/tmp/prefetch", tMock.SID())
    92  	if err != nil {
    93  		fmt.Fprintln(os.Stderr, "ignoring:", err)
    94  	}
    95  	xreg.RegBckXact(&xs.TestXFactory{})
    96  	defer xreg.AbortAll(nil)
    97  	cos.InitShortID(0)
    98  
    99  	ch := make(chan xreg.RenewRes, 10)
   100  	wg := &sync.WaitGroup{}
   101  	wg.Add(10)
   102  	for range 10 {
   103  		go func() {
   104  			defer wg.Done()
   105  			ch <- xreg.RenewPrefetch(cos.GenUUID(), bck, msg)
   106  		}()
   107  	}
   108  
   109  	wg.Wait()
   110  	close(ch)
   111  
   112  	res := make(map[core.Xact]struct{}, 10)
   113  	for rns := range ch {
   114  		if xctn := rns.Entry.Get(); xctn != nil {
   115  			res[xctn] = struct{}{}
   116  		}
   117  	}
   118  
   119  	tassert.Errorf(t, len(res) > 0, "expected xactions to be created")
   120  }
   121  
   122  func TestXactionAbortAll(t *testing.T) {
   123  	var (
   124  		bmd     = mock.NewBaseBownerMock()
   125  		bckFrom = meta.NewBck("test", apc.AIS, cmn.NsGlobal)
   126  		bckTo   = meta.NewBck("test", apc.AIS, cmn.NsGlobal)
   127  		tMock   = mock.NewTarget(bmd)
   128  	)
   129  	core.T = tMock
   130  	xreg.TestReset()
   131  	bmd.Add(bckFrom)
   132  	bmd.Add(bckTo)
   133  
   134  	xreg.RegNonBckXact(&space.TestFactory{})
   135  	xreg.RegBckXact(&xs.TestBmvFactory{})
   136  	cos.InitShortID(0)
   137  
   138  	rnsLRU := xreg.RenewLRU(cos.GenUUID())
   139  	tassert.Errorf(t, !rnsLRU.IsRunning(), "new LRU must be created")
   140  	rnsRen := xreg.RenewBckRename(bckFrom, bckTo, cos.GenUUID(), 123, "phase")
   141  	xactBck := rnsRen.Entry.Get()
   142  	tassert.Errorf(t, rnsRen.Err == nil && xactBck != nil, "Xaction must be created")
   143  
   144  	xreg.AbortAll(errors.New("test-abort-all"))
   145  
   146  	tassert.Errorf(t, rnsLRU.Entry.Get().IsAborted(), "AbortAllGlobal: expected global xaction to be aborted")
   147  	tassert.Errorf(t, xactBck.IsAborted(), "AbortAllGlobal: expected bucket xaction to be aborted")
   148  }
   149  
   150  func TestXactionAbortAllGlobal(t *testing.T) {
   151  	var (
   152  		bmd     = mock.NewBaseBownerMock()
   153  		bckFrom = meta.NewBck("test", apc.AIS, cmn.NsGlobal)
   154  		bckTo   = meta.NewBck("test", apc.AIS, cmn.NsGlobal)
   155  		tMock   = mock.NewTarget(bmd)
   156  	)
   157  	core.T = tMock
   158  	xreg.TestReset()
   159  
   160  	defer xreg.AbortAll(errors.New("test-abort-global"))
   161  
   162  	bmd.Add(bckFrom)
   163  	bmd.Add(bckTo)
   164  
   165  	xreg.RegNonBckXact(&space.TestFactory{})
   166  	xreg.RegBckXact(&xs.TestBmvFactory{})
   167  	cos.InitShortID(0)
   168  
   169  	rnsLRU := xreg.RenewLRU(cos.GenUUID())
   170  	tassert.Errorf(t, !rnsLRU.IsRunning(), "new LRU must be created")
   171  	rnsRen := xreg.RenewBckRename(bckFrom, bckTo, cos.GenUUID(), 123, "phase")
   172  	xactBck := rnsRen.Entry.Get()
   173  	tassert.Errorf(t, rnsRen.Err == nil && xactBck != nil, "Xaction must be created")
   174  
   175  	xreg.AbortAll(errors.New("test-abort-g"), xact.ScopeG, xact.ScopeGB)
   176  
   177  	tassert.Errorf(t, rnsLRU.Entry.Get().IsAborted(), "AbortAllGlobal: expected global xaction to be aborted")
   178  	tassert.Errorf(t, !xactBck.IsAborted(), "AbortAllGlobal: expected bucket xaction to be running: %s", xactBck)
   179  }
   180  
   181  func TestXactionAbortBuckets(t *testing.T) {
   182  	var (
   183  		bmd     = mock.NewBaseBownerMock()
   184  		bckFrom = meta.NewBck("test", apc.AIS, cmn.NsGlobal)
   185  		bckTo   = meta.NewBck("test", apc.AIS, cmn.NsGlobal)
   186  		tMock   = mock.NewTarget(bmd)
   187  	)
   188  	core.T = tMock
   189  	xreg.TestReset()
   190  
   191  	defer xreg.AbortAll(errors.New("abort-buckets"))
   192  
   193  	bmd.Add(bckFrom)
   194  	bmd.Add(bckTo)
   195  
   196  	xreg.RegNonBckXact(&space.TestFactory{})
   197  	xreg.RegBckXact(&xs.TestBmvFactory{})
   198  	cos.InitShortID(0)
   199  
   200  	rnsLRU := xreg.RenewLRU(cos.GenUUID())
   201  	tassert.Errorf(t, !rnsLRU.IsRunning(), "new LRU must be created")
   202  	rns := xreg.RenewBckRename(bckFrom, bckTo, cos.GenUUID(), 123, "phase")
   203  	xactBck := rns.Entry.Get()
   204  	tassert.Errorf(t, rns.Err == nil && xactBck != nil, "Xaction must be created")
   205  
   206  	xreg.AbortAllBuckets(nil, bckFrom)
   207  
   208  	tassert.Errorf(t, !rnsLRU.Entry.Get().IsAborted(), "AbortAllGlobal: expected global xaction to keep running")
   209  	tassert.Errorf(t, xactBck.IsAborted(), "AbortAllGlobal: expected bucket xaction to be aborted")
   210  }
   211  
   212  // TODO: extend this to include all cases of the Query
   213  func TestXactionQueryFinished(t *testing.T) {
   214  	type testConfig struct {
   215  		bckNil           bool
   216  		kindNil          bool
   217  		showActive       bool
   218  		expectedStatsLen int
   219  	}
   220  	var (
   221  		bmd   = mock.NewBaseBownerMock()
   222  		bck1  = meta.NewBck("test1", apc.AIS, cmn.NsGlobal)
   223  		bck2  = meta.NewBck("test2", apc.AIS, cmn.NsGlobal)
   224  		bck3  = meta.NewBck("test3", apc.GCP, cmn.NsGlobal)
   225  		tMock = mock.NewTarget(bmd)
   226  	)
   227  	core.T = tMock
   228  	xreg.TestReset()
   229  
   230  	defer xreg.AbortAll(nil)
   231  
   232  	bmd.Add(bck1)
   233  	bmd.Add(bck2)
   234  	bmd.Add(bck3)
   235  
   236  	xreg.RegBckXact(&xs.TestXFactory{})
   237  	xreg.RegBckXact(&xs.TestBmvFactory{})
   238  	cos.InitShortID(0)
   239  
   240  	rns1 := xreg.RenewBckRename(bck1, bck1, cos.GenUUID(), 123, "phase")
   241  	tassert.Errorf(t, rns1.Err == nil && rns1.Entry.Get() != nil, "Xaction must be created")
   242  	rns2 := xreg.RenewBckRename(bck2, bck2, cos.GenUUID(), 123, "phase")
   243  	tassert.Errorf(t, rns2.Err == nil && rns2.Entry.Get() != nil, "Xaction must be created %v", rns2.Err)
   244  	rns1.Entry.Get().Finish()
   245  
   246  	rns1 = xreg.RenewBckRename(bck1, bck1, cos.GenUUID(), 123, "phase")
   247  	tassert.Errorf(t, rns1.Err == nil && rns1.Entry.Get() != nil, "Xaction must be created")
   248  
   249  	rns3 := xreg.RenewPrefetch(cos.GenUUID(), bck3, &apc.PrefetchMsg{})
   250  	tassert.Fatalf(t, cmn.IsErrRemoteBckNotFound(rns3.Err), "x-prefetch: expected 'cloud bucket does not exist' error")
   251  
   252  	xactBck1 := rns1.Entry.Get()
   253  
   254  	scenarioName := func(tc testConfig) string {
   255  		name := ""
   256  		if tc.bckNil {
   257  			name += "bck:empty"
   258  		} else {
   259  			name += "bck:set"
   260  		}
   261  		if tc.kindNil {
   262  			name += "/kind:empty"
   263  		} else {
   264  			name += "/kind:set"
   265  		}
   266  		if tc.showActive {
   267  			name += "/state:running"
   268  		} else {
   269  			name += "/state:finished"
   270  		}
   271  		return name
   272  	}
   273  
   274  	f := func(t *testing.T, tc testConfig) {
   275  		t.Run(scenarioName(tc), func(t *testing.T) {
   276  			query := xreg.Flt{}
   277  			if !tc.bckNil {
   278  				query.Bck = bck1
   279  			}
   280  			if !tc.kindNil {
   281  				query.Kind = xactBck1.Kind()
   282  			}
   283  			query.OnlyRunning = &tc.showActive
   284  			stats, err := xreg.GetSnap(query)
   285  			tassert.Errorf(t, err == nil, "Error fetching Xact Stats %v for query %v", err, query)
   286  			tassert.Errorf(t, len(stats) == tc.expectedStatsLen, "Length of result: %d != %d", len(stats), tc.expectedStatsLen)
   287  		})
   288  	}
   289  	tests := []testConfig{
   290  		{bckNil: true, kindNil: true, showActive: false, expectedStatsLen: 1},
   291  		{bckNil: true, kindNil: false, showActive: false, expectedStatsLen: 1},
   292  		{bckNil: false, kindNil: true, showActive: false, expectedStatsLen: 1},
   293  		{bckNil: false, kindNil: false, showActive: false, expectedStatsLen: 1},
   294  	}
   295  	for _, test := range tests {
   296  		f(t, test)
   297  	}
   298  }
   299  
   300  func TestBeid(t *testing.T) {
   301  	const div = uint64(100 * time.Millisecond)
   302  	num := 100
   303  	if testing.Short() {
   304  		num = 10
   305  	}
   306  	now := time.Now()
   307  	xreg.PrimeTime.Store(now.UnixNano())
   308  	xreg.MyTime.Store(now.Add(time.Second).UnixNano())
   309  
   310  	var (
   311  		ids  = make(map[string]struct{}, num)
   312  		tags = []string{"tag1", "tag2"}
   313  		cnt  int
   314  	)
   315  	for i := range num {
   316  		beid, _, _ := xreg.GenBEID(div, tags[i%2])
   317  		if _, ok := ids[beid]; ok {
   318  			t.Fatalf("%d: %s duplicated", i, beid)
   319  		}
   320  		ids[beid] = struct{}{}
   321  
   322  		time.Sleep(time.Millisecond)
   323  		id, _, _ := xreg.GenBEID(div, tags[i%2])
   324  		if beid != id {
   325  			cnt++
   326  		}
   327  
   328  		time.Sleep(time.Duration(div))
   329  	}
   330  	if cnt > 0 {
   331  		fmt.Printf("Warning: failed to reproduce %d time%s out of %d\n", cnt, cos.Plural(cnt), num)
   332  	}
   333  }