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  }