Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions sei-db/db_engine/pebbledb/pebblecache/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package pebblecache

import "github.com/sei-protocol/sei-chain/sei-db/db_engine/types"

// Cache describes a cache capable of being used by a FlatKV store.
type Cache interface {

// Get returns the value for the given key, or (nil, false) if not found.
Get(
// The entry to fetch.
key []byte,
// If true, the LRU queue will be updated. If false, the LRU queue will not be updated.
// Useful for when an operation is performed multiple times in close succession on the same key,
// since it requires non-zero overhead to do so with little benefit.
updateLru bool,
) ([]byte, bool, error)

// Perform a batch read operation. Given a map of keys to read, performs the reads and updates the
// map with the results.
//
// It is not thread safe to read or mutate the map while this method is running.
BatchGet(keys map[string]types.BatchGetResult) error

// Set sets the value for the given key.
Set(key []byte, value []byte)

// Delete deletes the value for the given key.
Delete(key []byte)

// BatchSet applies the given updates to the cache.
BatchSet(updates []CacheUpdate) error
}

// CacheUpdate describes a single key-value mutation to apply to the cache.
type CacheUpdate struct {
// The key to update.
Key []byte
// The value to set. If nil, the key will be deleted.
Value []byte
}

// IsDelete returns true if the update is a delete operation.
func (u *CacheUpdate) IsDelete() bool {
return u.Value == nil
}
83 changes: 83 additions & 0 deletions sei-db/db_engine/pebbledb/pebblecache/lru_queue.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package pebblecache

import "container/list"

// Implements a queue-like abstraction with LRU semantics. Not thread safe.
type lruQueue struct {
order *list.List
entries map[string]*list.Element
totalSize uint64
}

type lruQueueEntry struct {
key string
size uint64
}

// Create a new LRU queue.
func newLRUQueue() *lruQueue {
return &lruQueue{
order: list.New(),
entries: make(map[string]*list.Element),
}
}

// Add a new entry to the LRU queue. Can also be used to update an existing value with a new weight.
func (lru *lruQueue) Push(
// the key in the cache that was recently interacted with
key []byte,
// the size of the key + value
size uint64,
) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Push() accepts negative values

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed type to uint64

if elem, ok := lru.entries[string(key)]; ok {
entry := elem.Value.(*lruQueueEntry)
lru.totalSize += size - entry.size
entry.size = size
lru.order.MoveToBack(elem)
return
}

keyStr := string(key)
elem := lru.order.PushBack(&lruQueueEntry{
key: keyStr,
size: size,
})
lru.entries[keyStr] = elem
lru.totalSize += size
}

// Signal that an entry has been interated with, moving it to the back of the queue
// (i.e. making it so it doesn't get popped soon).
func (lru *lruQueue) Touch(key []byte) {
elem, ok := lru.entries[string(key)]
if !ok {
return
}
lru.order.MoveToBack(elem)
}

// Returns the total size of all entries in the LRU queue.
func (lru *lruQueue) GetTotalSize() uint64 {
return lru.totalSize
}

// Returns a count of the number of entries in the LRU queue, where each entry counts for 1 regardless of size.
func (lru *lruQueue) GetCount() uint64 {
return uint64(len(lru.entries))
}

// Pops a single element out of the queue. The element removed is the entry least recently passed to Update().
// Returns the key in string form to avoid copying the key an additional time.
// Panics if the queue is empty.
func (lru *lruQueue) PopLeastRecentlyUsed() string {
elem := lru.order.Front()
if elem == nil {
panic("cannot pop from empty LRU queue")
}

lru.order.Remove(elem)
entry := elem.Value.(*lruQueueEntry)
delete(lru.entries, entry.key)
lru.totalSize -= entry.size
return entry.key
}
Loading
Loading