Skip to content

Commit

Permalink
refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
alphadose committed Sep 15, 2022
1 parent ad35641 commit c1f7647
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 123 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ jobs:

- name: Test
run: |
go test tests/e2e_test.go
go test *.go
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
[![Main Actions Status](https://github.com/alphadose/haxmap/workflows/Go/badge.svg)](https://github.com/alphadose/haxmap/actions)
[![Go Report Card](https://goreportcard.com/badge/github.com/alphadose/haxmap)](https://goreportcard.com/report/github.com/alphadose/haxmap)
[![License](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE.md)
> A blazing fast concurrent hashmap
> A lightning fast concurrent hashmap
The hashing algorithm used was [xxHash](https://github.com/Cyan4973/xxHash) and the hashmap's buckets were implemented using [Harris lock-free list](https://www.cl.cam.ac.uk/research/srg/netos/papers/2001-caslists.pdf)

Expand Down
2 changes: 1 addition & 1 deletion benchmarks/map_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ const (
mapSize = 256
)

func setupHaxMap() *haxmap.HashMap[uintptr, uintptr] {
func setupHaxMap() *haxmap.Map[uintptr, uintptr] {
m := haxmap.New[uintptr, uintptr](mapSize)
for i := uintptr(0); i < epochs; i++ {
m.Set(i, i)
Expand Down
49 changes: 32 additions & 17 deletions tests/e2e_test.go → e2e_test.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package test
package haxmap

import (
"fmt"
Expand All @@ -8,23 +8,21 @@ import (
"sync/atomic"
"testing"
"time"

"github.com/alphadose/haxmap"
)

type Animal struct {
name string
}

func TestMapCreation(t *testing.T) {
m := haxmap.New[int, int]()
m := New[int, int]()
if m.Len() != 0 {
t.Errorf("new map should be empty but has %d items.", m.Len())
}
}

func TestOverwrite(t *testing.T) {
m := haxmap.New[uint, string]()
m := New[uint, string]()
key := uint(1)
cat := "cat"
tiger := "tiger"
Expand All @@ -46,7 +44,7 @@ func TestOverwrite(t *testing.T) {
}

func TestSet(t *testing.T) {
m := haxmap.New[int, string](4)
m := New[int, string](4)

m.Set(4, "cat")
m.Set(3, "cat")
Expand All @@ -59,7 +57,7 @@ func TestSet(t *testing.T) {
}

func TestGet(t *testing.T) {
m := haxmap.New[string, string]()
m := New[string, string]()
cat := "cat"
key := "animal"

Expand All @@ -86,18 +84,18 @@ func TestGet(t *testing.T) {
}

func TestGrow(t *testing.T) {
m := haxmap.New[uint, uint]()
m := New[uint, uint]()
m.Grow(63)
d := m.Datamap.Load()
d := m.metadata.Load()
log := int(math.Log2(64))
expectedSize := uintptr(strconv.IntSize - log)
if d.Keyshifts != expectedSize {
if d.keyshifts != expectedSize {
t.Errorf("Grow operation did not result in correct internal map data structure, Dump -> %#v", d)
}
}

func TestDelete(t *testing.T) {
m := haxmap.New[int, *Animal]()
m := New[int, *Animal]()

cat := &Animal{"cat"}
tiger := &Animal{"tiger"}
Expand Down Expand Up @@ -132,7 +130,7 @@ func TestDelete(t *testing.T) {
}

func TestIterator(t *testing.T) {
m := haxmap.New[int, *Animal]()
m := New[int, *Animal]()

m.ForEach(func(i int, a *Animal) bool {
t.Errorf("map should be empty but got key -> %d and value -> %#v.", i, a)
Expand Down Expand Up @@ -161,7 +159,7 @@ func TestIterator(t *testing.T) {
func TestMapParallel(t *testing.T) {
max := 10
dur := 2 * time.Second
m := haxmap.New[int, int]()
m := New[int, int]()
do := func(t *testing.T, max int, d time.Duration, fn func(*testing.T, int)) <-chan error {
t.Helper()
done := make(chan error)
Expand Down Expand Up @@ -229,19 +227,19 @@ func TestMapParallel(t *testing.T) {
}

func TestMapConcurrentWrites(t *testing.T) {
blocks := haxmap.New[string, struct{}]()
blocks := New[string, struct{}]()

var wg sync.WaitGroup
for i := 0; i < 100; i++ {

wg.Add(1)
go func(blocks *haxmap.HashMap[string, struct{}], i int) {
go func(blocks *Map[string, struct{}], i int) {
defer wg.Done()

blocks.Set(strconv.Itoa(i), struct{}{})

wg.Add(1)
go func(blocks *haxmap.HashMap[string, struct{}], i int) {
go func(blocks *Map[string, struct{}], i int) {
defer wg.Done()

blocks.Get(strconv.Itoa(i))
Expand All @@ -254,7 +252,7 @@ func TestMapConcurrentWrites(t *testing.T) {

// Collision test case when hash key is 0 in value for all entries
func TestHash0Collision(t *testing.T) {
m := haxmap.New[string, int]()
m := New[string, int]()
staticHasher := func(key string) uintptr {
return 0
}
Expand All @@ -270,3 +268,20 @@ func TestHash0Collision(t *testing.T) {
t.Error("2 not found")
}
}

// test map freezing issue
// https://github.com/alphadose/haxmap/issues/7
// https://github.com/alphadose/haxmap/issues/8
// Update:- Solved now
func TestInfiniteLoop(t *testing.T) {
t.Run("infinite loop", func(b *testing.T) {
m := New[int, int](512)
for i := 0; i < 112050; i++ {
if i > 112024 {
m.Set(i, i) // set debug point here and step into until .inject
} else {
m.Set(i, i)
}
}
})
}
2 changes: 1 addition & 1 deletion hash.go
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ var (
}
)

func (m *HashMap[K, V]) setDefaultHasher() {
func (m *Map[K, V]) setDefaultHasher() {
// default hash functions
switch any(*new(K)).(type) {
case string:
Expand Down
5 changes: 1 addition & 4 deletions list.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,10 +106,7 @@ func (self *element[K, V]) search(c uintptr, key K) (*element[K, V], *element[K,

// remove removes the current node
func (self *element[K, V]) remove() {
for {
if self.add(marked) {
return
}
for !self.add(marked) {
}
}

Expand Down
Loading

0 comments on commit c1f7647

Please sign in to comment.