github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/bench/tools/aisloader/namegetter/objnamegetter.go (about)

     1  // Package namegetter is utility to generate filenames for aisloader PUT requests
     2  /*
     3  * Copyright (c) 2018-2023, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package namegetter
     6  
     7  import (
     8  	"math/rand"
     9  	"sync"
    10  
    11  	"github.com/NVIDIA/aistore/cmn/cos"
    12  )
    13  
    14  type (
    15  	ObjectNameGetter interface {
    16  		ObjName() string
    17  		AddObjName(objName string)
    18  		Init(names []string, rnd *rand.Rand)
    19  		Names() []string
    20  		Len() int
    21  	}
    22  	RandomNameGetter struct {
    23  		rnd *rand.Rand
    24  		BaseNameGetter
    25  	}
    26  	RandomUniqueNameGetter struct {
    27  		BaseNameGetter
    28  		rnd     *rand.Rand
    29  		bitmask []uint64
    30  		used    int
    31  	}
    32  	RandomUniqueIterNameGetter struct {
    33  		BaseNameGetter
    34  		rnd     *rand.Rand
    35  		bitmask []uint64
    36  		used    int
    37  	}
    38  	PermutationUniqueNameGetter struct {
    39  		BaseNameGetter
    40  		rnd     *rand.Rand
    41  		perm    []int
    42  		permidx int
    43  	}
    44  	PermutationUniqueImprovedNameGetter struct {
    45  		BaseNameGetter
    46  		rnd       *rand.Rand
    47  		perm      []int
    48  		permNext  []int
    49  		permidx   int
    50  		nextReady sync.WaitGroup
    51  	}
    52  	BaseNameGetter struct {
    53  		names []string
    54  	}
    55  )
    56  
    57  // RandomNameGetter //
    58  
    59  func (rung *RandomNameGetter) Init(names []string, rnd *rand.Rand) {
    60  	rung.names = names
    61  	rung.rnd = rnd
    62  }
    63  
    64  func (rung *RandomNameGetter) AddObjName(objName string) {
    65  	rung.names = append(rung.names, objName)
    66  }
    67  
    68  func (rung *RandomNameGetter) ObjName() string {
    69  	idx := rung.rnd.Intn(len(rung.names))
    70  	return rung.names[idx]
    71  }
    72  
    73  // RandomUniqueNameGetter //
    74  
    75  func (rung *RandomUniqueNameGetter) Init(names []string, rnd *rand.Rand) {
    76  	rung.names = names
    77  	rung.rnd = rnd
    78  
    79  	lenBitmask := len(names) / 64
    80  	if len(names)%64 != 0 {
    81  		lenBitmask++
    82  	}
    83  
    84  	rung.bitmask = make([]uint64, lenBitmask)
    85  }
    86  
    87  func (rung *RandomUniqueNameGetter) AddObjName(objName string) {
    88  	if len(rung.names)%64 == 0 {
    89  		rung.bitmask = append(rung.bitmask, uint64(0))
    90  	}
    91  	rung.names = append(rung.names, objName)
    92  }
    93  
    94  func (rung *RandomUniqueNameGetter) ObjName() string {
    95  	if rung.used == len(rung.names) {
    96  		for i := range rung.bitmask {
    97  			rung.bitmask[i] = 0
    98  		}
    99  		rung.used = 0
   100  	}
   101  
   102  	for {
   103  		idx := rung.rnd.Intn(len(rung.names))
   104  		bitmaskID := idx / 64
   105  		bitmaskBit := uint64(1) << uint64(idx%64)
   106  		if rung.bitmask[bitmaskID]&bitmaskBit == 0 {
   107  			rung.used++
   108  			rung.bitmask[bitmaskID] |= bitmaskBit
   109  			return rung.names[idx]
   110  		}
   111  	}
   112  }
   113  
   114  // RandomUniqueIterNameGetter //
   115  
   116  func (ruing *RandomUniqueIterNameGetter) Init(names []string, rnd *rand.Rand) {
   117  	ruing.names = names
   118  	ruing.rnd = rnd
   119  
   120  	lenBitmask := len(names) / 64
   121  	if len(names)%64 != 0 {
   122  		lenBitmask++
   123  	}
   124  
   125  	ruing.bitmask = make([]uint64, lenBitmask)
   126  }
   127  
   128  func (ruing *RandomUniqueIterNameGetter) AddObjName(objName string) {
   129  	if len(ruing.names)%64 == 0 {
   130  		ruing.bitmask = append(ruing.bitmask, uint64(0))
   131  	}
   132  	ruing.names = append(ruing.names, objName)
   133  }
   134  
   135  func (ruing *RandomUniqueIterNameGetter) ObjName() string {
   136  	if ruing.used == len(ruing.names) {
   137  		for i := range ruing.bitmask {
   138  			ruing.bitmask[i] = 0
   139  		}
   140  		ruing.used = 0
   141  	}
   142  
   143  	namesLen := len(ruing.names)
   144  	idx := ruing.rnd.Intn(namesLen)
   145  
   146  	for {
   147  		bitmaskID := idx / 64
   148  		bitmaskBit := uint64(1) << uint64(idx%64)
   149  		if ruing.bitmask[bitmaskID]&bitmaskBit == 0 {
   150  			ruing.bitmask[bitmaskID] |= bitmaskBit
   151  			ruing.used++
   152  			return ruing.names[idx]
   153  		}
   154  		idx = (idx + 1) % namesLen
   155  	}
   156  }
   157  
   158  // PermutationUniqueNameGetter //
   159  
   160  func (pung *PermutationUniqueNameGetter) Init(names []string, rnd *rand.Rand) {
   161  	pung.names = names
   162  	pung.rnd = rnd
   163  	pung.perm = pung.rnd.Perm(len(names))
   164  }
   165  
   166  func (*PermutationUniqueNameGetter) AddObjName(string) {
   167  	cos.AssertMsg(false, "can't add object once PermutationUniqueNameGetter is initialized")
   168  }
   169  
   170  func (pung *PermutationUniqueNameGetter) ObjName() string {
   171  	if pung.permidx == len(pung.names) {
   172  		pung.permidx = 0
   173  		pung.perm = pung.rnd.Perm(len(pung.names))
   174  	}
   175  	objName := pung.names[pung.perm[pung.permidx]]
   176  	pung.permidx++
   177  	return objName
   178  }
   179  
   180  // PermutationUniqueImprovedNameGetter //
   181  
   182  func (pung *PermutationUniqueImprovedNameGetter) Init(names []string, rnd *rand.Rand) {
   183  	pung.nextReady.Wait() // in case someone called Init twice, wait until initializing pung.permNext in ObjName() has finished
   184  	pung.names = names
   185  	pung.rnd = rnd
   186  	pung.perm = pung.rnd.Perm(len(names))
   187  	pung.permNext = pung.rnd.Perm(len(names))
   188  }
   189  
   190  func (*PermutationUniqueImprovedNameGetter) AddObjName(string) {
   191  	cos.AssertMsg(false, "can't add object once PermutationUniqueImprovedNameGetter is initialized")
   192  }
   193  
   194  func (pung *PermutationUniqueImprovedNameGetter) ObjName() string {
   195  	if pung.permidx == len(pung.names) {
   196  		pung.nextReady.Wait()
   197  		pung.perm, pung.permNext = pung.permNext, pung.perm
   198  		pung.permidx = 0
   199  
   200  		pung.nextReady.Add(1)
   201  		go func() {
   202  			pung.permNext = pung.rnd.Perm(len(pung.names))
   203  			pung.nextReady.Done()
   204  		}()
   205  	}
   206  	objName := pung.names[pung.perm[pung.permidx]]
   207  	pung.permidx++
   208  	return objName
   209  }
   210  
   211  // BaseNameGetter //
   212  
   213  func (bng *BaseNameGetter) Names() []string {
   214  	return bng.names
   215  }
   216  
   217  func (bng *BaseNameGetter) Len() int {
   218  	if bng == nil || bng.names == nil {
   219  		return 0
   220  	}
   221  	return len(bng.names)
   222  }