-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcmap.go
More file actions
103 lines (88 loc) · 2.69 KB
/
Copy pathcmap.go
File metadata and controls
103 lines (88 loc) · 2.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
// Package cmap implements an in-memory concurrent hash map.
// It supports efficient insertion, deletion, and retrival of entries by key.
package cmap
import (
"github.com/cespare/xxhash/v2"
"github.com/holmberd/go-cmap/internal/buffer"
)
var (
defaultChunkPool = NewChunkPool(DefaultChunkPoolConfig())
ErrBufferCorrupted = buffer.ErrBufferCorrupted
ErrKeyTooLarge = buffer.ErrKeyTooLarge
ErrValueTooLarge = buffer.ErrValueTooLarge
ErrKeyEmpty = buffer.ErrKeyEmpty
)
const (
bucketCount = 512 // Must be a power of two for unbiased modulo.
)
func bucketIndex(n uint64) uint64 {
// Faster modulo via bitwise AND; requires bucketCount to be a power of two.
return n & (bucketCount - 1)
}
// CMap represents a concurrent-safe map.
type CMap[P buffer.ChunkPooler] struct {
buckets [bucketCount]bucket[P]
}
func new[P buffer.ChunkPooler](pool P, config buffer.Config) (*CMap[P], error) {
if err := config.Validate(pool); err != nil {
return nil, err
}
c := &CMap[P]{}
for i := range c.buckets[:] {
c.buckets[i].Init(pool, config)
}
return c, nil
}
// New creates a new concurrent map.
func New() (*CMap[*ChunkPool], error) {
return new(defaultChunkPool, buffer.DefaultConfig(defaultChunkPool))
}
// Custom creates a new concurrent map with custom chunk pool and config.
func Custom[P buffer.ChunkPooler](pool P, config Config) (*CMap[P], error) {
bConfig := buffer.DefaultConfig(pool)
bConfig.P = config.P
bConfig.CompactDeadRatio = config.CompactDeadRatio
return new(pool, bConfig)
}
// Insert adds or updates an entry.
func (c *CMap[P]) Insert(key, value []byte) (updated bool, err error) {
h := xxhash.Sum64(key)
return c.buckets[bucketIndex(h)].Insert(key, value, h)
}
// Get retrieves an entry by its key.
// The ok result indicates whether the key was found in the map.
func (c *CMap[P]) Get(key []byte) (value []byte, ok bool, err error) {
h := xxhash.Sum64(key)
k, v, found, err := c.buckets[bucketIndex(h)].Get(h)
if string(k) != string(key) {
return nil, false, nil
}
return v, found, err
}
// Has returns whether the key exist in the map.
func (c *CMap[P]) Has(key []byte) bool {
h := xxhash.Sum64(key)
return c.buckets[bucketIndex(h)].Has(h)
}
// Delete removes an entry from the map by its key.
func (c *CMap[P]) Delete(key []byte) (ok bool, err error) {
h := xxhash.Sum64(key)
return c.buckets[bucketIndex(h)].Delete(h)
}
// Clear clears the map.
func (c *CMap[P]) Clear() {
c.buckets = [bucketCount]bucket[P]{}
}
// Len returns the number of entries in the map.
func (c *CMap[P]) Len() int {
n := 0
for i := range c.buckets {
n += c.buckets[i].Len()
}
return n
}
func (c *CMap[P]) UpdateStats(s *Stats) {
for i := range c.buckets {
c.buckets[i].UpdateStats(s)
}
}