github.com/rohankumardubey/proxyfs@v0.0.0-20210108201508-653efa9ab00e/inode/dir_stress_test.go (about)

     1  package inode
     2  
     3  import (
     4  	"fmt"
     5  	"sync"
     6  	"testing"
     7  	"time"
     8  
     9  	"github.com/swiftstack/ProxyFS/headhunter"
    10  	"github.com/swiftstack/ProxyFS/trackedlock"
    11  )
    12  
    13  const (
    14  	testDirStressBasenamePrefix = "__TestDirStress_" // To be appended with Nonce + "_" + ThreadIndex + "_" + LinkIndex (for this Thread)
    15  
    16  	testDirStressDelayBetweenLinkAndUnlink time.Duration = 1 * time.Microsecond
    17  	testDirStressDelayBetweenThreadStarts  time.Duration = 1 * time.Microsecond
    18  
    19  	testDirStressNumIterations        uint64 = 3
    20  	testDirStressNumLinksPerIteration uint64 = 3
    21  	testDirStressNumThreads           uint64 = 30
    22  
    23  	testDirStressVolumeName = "TestVolume"
    24  )
    25  
    26  type testDirStressGlobalsStruct struct {
    27  	trackedlock.Mutex // Used to emulate the exclusive lock used in package fs on RootDirInodeNumber
    28  	nonce             uint64
    29  	waitGroup         sync.WaitGroup
    30  	err               []error
    31  }
    32  
    33  var testDirStressGlobals = &testDirStressGlobalsStruct{}
    34  
    35  func TestDirStressWhileStarved(t *testing.T) {
    36  	testDirStress(t, true)
    37  }
    38  
    39  func TestDirStressWhileNotStarved(t *testing.T) {
    40  	testDirStress(t, false)
    41  }
    42  
    43  func testDirStress(t *testing.T, starvationMode bool) {
    44  	var (
    45  		err                    error
    46  		headhunterVolumeHandle headhunter.VolumeHandle
    47  		threadIndex            uint64
    48  	)
    49  
    50  	testSetup(t, starvationMode)
    51  
    52  	headhunterVolumeHandle, err = headhunter.FetchVolumeHandle(testDirStressVolumeName)
    53  	if nil != err {
    54  		t.Fatalf("headhunter.FetchVolumeHandle(\"%s\") failed: %v", testDirStressVolumeName, err)
    55  	}
    56  
    57  	testDirStressGlobals.nonce = headhunterVolumeHandle.FetchNonce()
    58  
    59  	testDirStressGlobals.waitGroup.Add(int(testDirStressNumThreads))
    60  
    61  	testDirStressGlobals.err = make([]error, testDirStressNumThreads)
    62  
    63  	for threadIndex = uint64(0); threadIndex < testDirStressNumThreads; threadIndex++ {
    64  		time.Sleep(testDirStressDelayBetweenThreadStarts)
    65  
    66  		go testDirStressThread(threadIndex)
    67  	}
    68  
    69  	testDirStressGlobals.waitGroup.Wait()
    70  
    71  	for _, err = range testDirStressGlobals.err {
    72  		if nil != err {
    73  			t.Fatal(err)
    74  		}
    75  	}
    76  
    77  	testTeardown(t)
    78  }
    79  
    80  func testDirStressThread(threadIndex uint64) {
    81  	var (
    82  		basename        string
    83  		err             error
    84  		fileInodeNumber InodeNumber
    85  		iteration       uint64
    86  		linkIndex       uint64
    87  		volumeHandle    VolumeHandle
    88  	)
    89  
    90  	defer testDirStressGlobals.waitGroup.Done()
    91  
    92  	volumeHandle, err = FetchVolumeHandle(testDirStressVolumeName)
    93  	if nil != err {
    94  		testDirStressGlobals.Lock()
    95  		testDirStressGlobals.err[threadIndex] = fmt.Errorf("FetchVolumeHandle(\"%s\") failed: %v", testDirStressVolumeName, err)
    96  		testDirStressGlobals.Unlock()
    97  		return
    98  	}
    99  
   100  	for iteration = uint64(0); iteration < testDirStressNumIterations; iteration++ {
   101  		fileInodeNumber, err = volumeHandle.CreateFile(PosixModePerm, InodeUserID(0), InodeGroupID(0))
   102  		if nil != err {
   103  			testDirStressGlobals.Lock()
   104  			testDirStressGlobals.err[threadIndex] = fmt.Errorf("volumeHandle.CreateFile(PosixModePerm, InodeUserID(0), InodeGroupID(0)) failed: %v", err)
   105  			testDirStressGlobals.Unlock()
   106  			return
   107  		}
   108  
   109  		for linkIndex = uint64(0); linkIndex < testDirStressNumLinksPerIteration; linkIndex++ {
   110  			basename = fmt.Sprintf("%s%016X_%016X_%016X", testDirStressBasenamePrefix, testDirStressGlobals.nonce, threadIndex, linkIndex)
   111  
   112  			testDirStressGlobals.Lock()
   113  			err = volumeHandle.Link(RootDirInodeNumber, basename, fileInodeNumber, false)
   114  			if nil != err {
   115  				testDirStressGlobals.err[threadIndex] = fmt.Errorf("volumeHandle.Link(RootDirInodeNumber, \"%s\", fileInodeNumber, false) failed: %v", basename, err)
   116  				testDirStressGlobals.Unlock()
   117  				return
   118  			}
   119  			testDirStressGlobals.Unlock()
   120  
   121  			time.Sleep(testDirStressDelayBetweenLinkAndUnlink)
   122  
   123  			testDirStressGlobals.Lock()
   124  			err = volumeHandle.Unlink(RootDirInodeNumber, basename, false)
   125  			if nil != err {
   126  				testDirStressGlobals.err[threadIndex] = fmt.Errorf("volumeHandle.Unlink(RootDirInodeNumber, \"%s\", false) failed: %v", basename, err)
   127  				testDirStressGlobals.Unlock()
   128  				return
   129  			}
   130  			testDirStressGlobals.Unlock()
   131  		}
   132  
   133  		err = volumeHandle.Destroy(fileInodeNumber)
   134  		if nil != err {
   135  			testDirStressGlobals.Lock()
   136  			testDirStressGlobals.err[threadIndex] = fmt.Errorf("volumeHandle.Destroy(fileInodeNumber) failed: %v", err)
   137  			testDirStressGlobals.Unlock()
   138  			return
   139  		}
   140  	}
   141  
   142  	testDirStressGlobals.Lock()
   143  	testDirStressGlobals.err[threadIndex] = nil
   144  	testDirStressGlobals.Unlock()
   145  }