github.com/btcsuite/btcd@v0.24.0/blockchain/sizehelper_test.go (about)

     1  // Copyright (c) 2023 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  package blockchain
     5  
     6  import (
     7  	"math"
     8  	"testing"
     9  )
    10  
    11  // calculateEntries returns a number of entries that will make the map allocate
    12  // the given total bytes.  The returned number is always the maximum number of
    13  // entries that will allocate inside the given parameters.
    14  func calculateEntries(totalBytes int, bucketSize int) int {
    15  	// 48 is the number of bytes needed for the map header in a
    16  	// 64 bit system. Refer to hmap in runtime/map.go in the go
    17  	// standard library.
    18  	totalBytes -= 48
    19  
    20  	numBuckets := totalBytes / bucketSize
    21  	B := uint8(math.Log2(float64(numBuckets)))
    22  	if B == 0 {
    23  		// For 0 buckets, the max is the bucket count.
    24  		return bucketCnt
    25  	}
    26  
    27  	return int(loadFactorNum * (bucketShift(B) / loadFactorDen))
    28  }
    29  
    30  func TestCalculateEntries(t *testing.T) {
    31  	for i := 0; i < 10_000_000; i++ {
    32  		// It's not possible to calculate the exact amount of entries since
    33  		// the map will only allocate for 2^N where N is the amount of buckets.
    34  		//
    35  		// So to see if the calculate entries function is working correctly,
    36  		// we get the rough map size for i entries, then calculate the entries
    37  		// for that map size.  If the size is the same, the function is correct.
    38  		roughMapSize := calculateRoughMapSize(i, bucketSize)
    39  		entries := calculateEntries(roughMapSize, bucketSize)
    40  		gotRoughMapSize := calculateRoughMapSize(entries, bucketSize)
    41  
    42  		if roughMapSize != gotRoughMapSize {
    43  			t.Errorf("For hint of %d, expected %v, got %v\n",
    44  				i, roughMapSize, gotRoughMapSize)
    45  		}
    46  
    47  		// Test that the entries returned are the maximum for the given map size.
    48  		// If we increment the entries by one, we should get a bigger map.
    49  		gotRoughMapSizeWrong := calculateRoughMapSize(entries+1, bucketSize)
    50  		if roughMapSize == gotRoughMapSizeWrong {
    51  			t.Errorf("For hint %d incremented by 1, expected %v, got %v\n",
    52  				i, gotRoughMapSizeWrong*2, gotRoughMapSizeWrong)
    53  		}
    54  
    55  		minEntries := calculateMinEntries(roughMapSize, bucketSize)
    56  		gotMinRoughMapSize := calculateRoughMapSize(minEntries, bucketSize)
    57  		if roughMapSize != gotMinRoughMapSize {
    58  			t.Errorf("For hint of %d, expected %v, got %v\n",
    59  				i, roughMapSize, gotMinRoughMapSize)
    60  		}
    61  
    62  		// Can only test if they'll be half the size if the entries aren't 0.
    63  		if minEntries > 0 {
    64  			gotMinRoughMapSizeWrong := calculateRoughMapSize(minEntries-1, bucketSize)
    65  			if gotMinRoughMapSize == gotMinRoughMapSizeWrong {
    66  				t.Errorf("For hint %d decremented by 1, expected %v, got %v\n",
    67  					i, gotRoughMapSizeWrong/2, gotRoughMapSizeWrong)
    68  			}
    69  		}
    70  	}
    71  }