timeboundmap

A Map data structure with expiration cleanup

Benchmark

goos: darwin
goarch: amd64
pkg: github.com/ulyyyyyy/timeboundmap
cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz

BenchmarkTimeBoundMap_Set-8   	 1000000	      1444 ns/op
BenchmarkTimeBoundMap_Get-8   	 1522558	      1130 ns/op

Example

package timeboundmap

import (
	"fmt"
	"math/rand"
	"sync"
	"sync/atomic"
	"testing"
	"time"
)

var r = rand.New(rand.NewSource(time.Now().Unix()))

func randStr() string {
	bs := make([]byte, 16)
	r.Read(bs)
	return fmt.Sprintf("%x", bs)
}

func BenchmarkCounter(b *testing.B) {
	b.StopTimer()

	// tbm := New(30 * time.Minute)
	tbm := New(30*time.Minute, WithSegmentSize(16*12))
	// tbm := New(30*time.Minute, WithSegmentSize(16*12*10))

	testData := make(map[string]int64, b.N)
	keys := make([]string, b.N)
	for i := range keys {
		keys[i] = randStr()
		testData[keys[i]] = r.Int63n(int64(i) + 100)
	}
	fnRandKey := func() string {
		return keys[r.Intn(len(keys))]
	}

	var wg sync.WaitGroup
	wg.Add(b.N)

	b.StartTimer()

	for i := 0; i < b.N; i++ {
		key := fnRandKey()
		go func(key string) {
			defer wg.Done()
			tbm.GetToDoWithLock(key, func(value interface{}, ok bool) {
				if !ok {
					cv := testData[key] + 1
					tbm.UnsafeSet(key, &cv, 10*time.Minute)
				} else {
					cv := value.(*int64)
					atomic.AddInt64(cv, 1)
				}
			})
		}(key)
	}

	wg.Wait()

	b.StopTimer()

	var count int64
	for k, v := range tbm.Snapshot() {
		testVal := testData[k.(string)]
		count += atomic.LoadInt64(v.(*int64)) - testVal
	}
	if count != int64(b.N) {
		b.FailNow()
	}

	// goos: darwin
	// goarch: amd64
	// pkg: github.com/ulyyyyyy/timeboundmap
	// cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
	// BenchmarkCounter
	// BenchmarkCounter-8   	 2316027	       742.3 ns/op
}

GitHub

View Github