github.com/phuslu/lru@v1.0.16-0.20240421170520-46288a2fd47c/bytes_cache.go (about) 1 // Copyright 2023-2024 Phus Lu. All rights reserved. 2 3 package lru 4 5 import ( 6 "unsafe" 7 ) 8 9 // BytesCache implements Bytes Cache with least recent used eviction policy. 10 type BytesCache struct { 11 shards []bytesshard 12 mask uint32 13 } 14 15 // NewBytesCache creates bytes cache with size capacity. 16 func NewBytesCache(shards uint8, shardsize uint32) *BytesCache { 17 c := new(BytesCache) 18 19 c.mask = nextPowOf2(uint32(shards)) - 1 20 c.shards = make([]bytesshard, c.mask+1) 21 22 for i := uint32(0); i <= c.mask; i++ { 23 c.shards[i].Init(shardsize) 24 } 25 26 return c 27 } 28 29 // Get returns value for key. 30 func (c *BytesCache) Get(key []byte) (value []byte, ok bool) { 31 hash := uint32(wyhash_HashBytes(key, 0)) 32 // return c.shards[hash&c.mask].Get(hash, key) 33 return (*bytesshard)(unsafe.Add(unsafe.Pointer(&c.shards[0]), uintptr(hash&c.mask)*unsafe.Sizeof(c.shards[0]))).Get(hash, key) 34 } 35 36 // Peek returns value, but does not modify its recency. 37 func (c *BytesCache) Peek(key []byte) (value []byte, ok bool) { 38 hash := uint32(wyhash_HashBytes(key, 0)) 39 // return c.shards[hash&c.mask].Peek(hash, key) 40 return (*bytesshard)(unsafe.Add(unsafe.Pointer(&c.shards[0]), uintptr(hash&c.mask)*unsafe.Sizeof(c.shards[0]))).Peek(hash, key) 41 } 42 43 // Set inserts key value pair and returns previous value. 44 func (c *BytesCache) Set(key []byte, value []byte) (prev []byte, replaced bool) { 45 hash := uint32(wyhash_HashBytes(key, 0)) 46 // return c.shards[hash&c.mask].Set(hash, key, value) 47 return (*bytesshard)(unsafe.Add(unsafe.Pointer(&c.shards[0]), uintptr(hash&c.mask)*unsafe.Sizeof(c.shards[0]))).Set(hash, key, value) 48 } 49 50 // SetIfAbsent inserts key value pair and returns previous value, if key is absent in the cache. 51 func (c *BytesCache) SetIfAbsent(key []byte, value []byte) (prev []byte, replaced bool) { 52 hash := uint32(wyhash_HashBytes(key, 0)) 53 // return c.shards[hash&c.mask].SetIfAbsent(hash, key, value) 54 return (*bytesshard)(unsafe.Add(unsafe.Pointer(&c.shards[0]), uintptr(hash&c.mask)*unsafe.Sizeof(c.shards[0]))).SetIfAbsent(hash, key, value) 55 } 56 57 // Delete method deletes value associated with key and returns deleted value (or empty value if key was not in cache). 58 func (c *BytesCache) Delete(key []byte) (prev []byte) { 59 hash := uint32(wyhash_HashBytes(key, 0)) 60 // return c.shards[hash&c.mask].Delete(hash, key) 61 return (*bytesshard)(unsafe.Add(unsafe.Pointer(&c.shards[0]), uintptr(hash&c.mask)*unsafe.Sizeof(c.shards[0]))).Delete(hash, key) 62 } 63 64 // Len returns number of cached nodes. 65 func (c *BytesCache) Len() int { 66 var n uint32 67 for i := uint32(0); i <= c.mask; i++ { 68 n += c.shards[i].Len() 69 } 70 return int(n) 71 } 72 73 // AppendKeys appends all keys to keys and return the keys. 74 func (c *BytesCache) AppendKeys(keys [][]byte) [][]byte { 75 for i := uint32(0); i <= c.mask; i++ { 76 keys = c.shards[i].AppendKeys(keys) 77 } 78 return keys 79 } 80 81 // Stats returns cache stats. 82 func (c *BytesCache) Stats() (stats Stats) { 83 for i := uint32(0); i <= c.mask; i++ { 84 s := &c.shards[i] 85 s.mu.Lock() 86 stats.EntriesCount += uint64(s.table_length) 87 stats.GetCalls += s.stats_getcalls 88 stats.SetCalls += s.stats_setcalls 89 stats.Misses += s.stats_misses 90 s.mu.Unlock() 91 } 92 return 93 } 94 95 func wyhash_HashBytes(data []byte, seed uint64) uint64 { 96 if len(data) == 0 { 97 return seed 98 } 99 return wyhash_hash(*(*string)(unsafe.Pointer(&data)), seed) 100 }