storj.io/minio@v0.0.0-20230509071714-0cbc90f649b1/cmd/fs-tree-walk-pool_test.go (about)

     1  /*
     2   * MinIO Cloud Storage, (C) 2016 MinIO, Inc.
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package cmd
    18  
    19  import (
    20  	"testing"
    21  	"time"
    22  )
    23  
    24  // Test if tree walker go-routine is removed from the pool after timeout
    25  // and that is available in the pool before the timeout.
    26  func TestTreeWalkPoolBasic(t *testing.T) {
    27  	// Create a treeWalkPool
    28  	tw := NewTreeWalkPool(1 * time.Second)
    29  
    30  	// Create sample params
    31  	params := listParams{
    32  		bucket: "test-bucket",
    33  	}
    34  
    35  	// Add a treeWalk to the pool
    36  	resultCh := make(chan TreeWalkResult)
    37  	endWalkCh := make(chan struct{})
    38  	tw.Set(params, resultCh, endWalkCh)
    39  
    40  	// Wait for treeWalkPool timeout to happen
    41  	<-time.After(2 * time.Second)
    42  	if c1, _ := tw.Release(params); c1 != nil {
    43  		t.Error("treeWalk go-routine must have been freed")
    44  	}
    45  
    46  	// Add the treeWalk back to the pool
    47  	tw.Set(params, resultCh, endWalkCh)
    48  
    49  	// Release the treeWalk before timeout
    50  	select {
    51  	case <-time.After(1 * time.Second):
    52  		break
    53  	default:
    54  		if c1, _ := tw.Release(params); c1 == nil {
    55  			t.Error("treeWalk go-routine got freed before timeout")
    56  		}
    57  	}
    58  }
    59  
    60  // Test if multiple tree walkers for the same listParams are managed as expected by the pool.
    61  func TestManyWalksSameParam(t *testing.T) {
    62  	// Create a treeWalkPool.
    63  	tw := NewTreeWalkPool(5 * time.Second)
    64  
    65  	// Create sample params.
    66  	params := listParams{
    67  		bucket: "test-bucket",
    68  	}
    69  
    70  	select {
    71  	// This timeout is an upper-bound. This is started
    72  	// before the first treeWalk go-routine's timeout period starts.
    73  	case <-time.After(5 * time.Second):
    74  		break
    75  	default:
    76  		// Create many treeWalk go-routines for the same params.
    77  		for i := 0; i < treeWalkSameEntryLimit; i++ {
    78  			resultCh := make(chan TreeWalkResult)
    79  			endWalkCh := make(chan struct{})
    80  			tw.Set(params, resultCh, endWalkCh)
    81  		}
    82  
    83  		tw.mu.Lock()
    84  		if walks, ok := tw.pool[params]; ok {
    85  			if len(walks) != treeWalkSameEntryLimit {
    86  				t.Error("There aren't as many walks as were Set")
    87  			}
    88  		}
    89  		tw.mu.Unlock()
    90  		for i := 0; i < treeWalkSameEntryLimit; i++ {
    91  			tw.mu.Lock()
    92  			if walks, ok := tw.pool[params]; ok {
    93  				// Before ith Release we should have n-i treeWalk go-routines.
    94  				if treeWalkSameEntryLimit-i != len(walks) {
    95  					t.Error("There aren't as many walks as were Set")
    96  				}
    97  			}
    98  			tw.mu.Unlock()
    99  			tw.Release(params)
   100  		}
   101  	}
   102  }
   103  
   104  // Test if multiple tree walkers for the same listParams are managed as expected by the pool
   105  // but that treeWalkSameEntryLimit is respected.
   106  func TestManyWalksSameParamPrune(t *testing.T) {
   107  	// Create a treeWalkPool.
   108  	tw := NewTreeWalkPool(5 * time.Second)
   109  
   110  	// Create sample params.
   111  	params := listParams{
   112  		bucket: "test-bucket",
   113  	}
   114  
   115  	select {
   116  	// This timeout is an upper-bound. This is started
   117  	// before the first treeWalk go-routine's timeout period starts.
   118  	case <-time.After(5 * time.Second):
   119  		break
   120  	default:
   121  		// Create many treeWalk go-routines for the same params.
   122  		for i := 0; i < treeWalkSameEntryLimit*4; i++ {
   123  			resultCh := make(chan TreeWalkResult)
   124  			endWalkCh := make(chan struct{})
   125  			tw.Set(params, resultCh, endWalkCh)
   126  		}
   127  
   128  		tw.mu.Lock()
   129  		if walks, ok := tw.pool[params]; ok {
   130  			if len(walks) != treeWalkSameEntryLimit {
   131  				t.Error("There aren't as many walks as were Set")
   132  			}
   133  		}
   134  		tw.mu.Unlock()
   135  		for i := 0; i < treeWalkSameEntryLimit; i++ {
   136  			tw.mu.Lock()
   137  			if walks, ok := tw.pool[params]; ok {
   138  				// Before ith Release we should have n-i treeWalk go-routines.
   139  				if treeWalkSameEntryLimit-i != len(walks) {
   140  					t.Error("There aren't as many walks as were Set")
   141  				}
   142  			}
   143  			tw.mu.Unlock()
   144  			tw.Release(params)
   145  		}
   146  	}
   147  }