diff --git a/storage/spanstore/downsampling_writer.go b/storage/spanstore/downsampling_writer.go index b01f8c38dca..aa581845ea5 100644 --- a/storage/spanstore/downsampling_writer.go +++ b/storage/spanstore/downsampling_writer.go @@ -18,6 +18,7 @@ import ( "hash" "hash/fnv" "math" + "math/big" "sync" "github.com/uber/jaeger-lib/metrics" @@ -96,7 +97,6 @@ type Sampler struct { // NewSampler creates SamplingExecutor func NewSampler(ratio float64, hashSalt string) Sampler { - threshold := uint64(ratio * float64(math.MaxUint64)) if hashSalt == "" { hashSalt = defaultHashSalt } @@ -112,12 +112,21 @@ func NewSampler(ratio float64, hashSalt string) Sampler { }, } return Sampler{ - threshold: threshold, + threshold: calculateThreshold(ratio), hasherPool: pool, lengthOfSalt: len(hashSaltBytes), } } +func calculateThreshold(ratio float64) uint64 { + // Use big.Float and big.Int to calculate threshold because directly convert + // math.MaxUint64 to float64 will cause digits/bits to be cut off if the converted value + // doesn't fit into bits that are used to store digits for float64 in Golang + boundary := new(big.Float).SetInt(new(big.Int).SetUint64(math.MaxUint64)) + res, _ := boundary.Mul(boundary, big.NewFloat(ratio)).Uint64() + return res +} + // ShouldSample decides if a span should be sampled func (s *Sampler) ShouldSample(span *model.Span) bool { hasherInstance := s.hasherPool.Get().(*hasher) diff --git a/storage/spanstore/downsampling_writer_test.go b/storage/spanstore/downsampling_writer_test.go index bdf1848168d..e1463d00da5 100644 --- a/storage/spanstore/downsampling_writer_test.go +++ b/storage/spanstore/downsampling_writer_test.go @@ -16,6 +16,7 @@ package spanstore import ( "errors" + "math" "testing" "github.com/stretchr/testify/assert" @@ -80,3 +81,8 @@ func TestDownSamplingWriter_hashBytes(t *testing.T) { // Same traceID should always be hashed to same uint64 in DownSamplingWriter. assert.Equal(t, h.hashBytes(), h.hashBytes()) } + +func TestDownsamplingWriter_calculateThreshold(t *testing.T) { + var maxUint64 uint64 = math.MaxUint64 + assert.Equal(t, maxUint64, calculateThreshold(1.0)) +}