mirror of
https://github.com/luxfi/session.git
synced 2026-10-30 15:17:14 +00:00
227 lines
4.0 KiB
Go
227 lines
4.0 KiB
Go
// Copyright (C) 2019-2025, Lux Industries Inc. All rights reserved.
|
|
// See the file LICENSE for licensing terms.
|
|
|
|
package storage
|
|
|
|
import (
|
|
"bytes"
|
|
"sort"
|
|
"sync"
|
|
)
|
|
|
|
// MemoryStore is an in-memory implementation of Store.
|
|
// Useful for testing and ephemeral data.
|
|
type MemoryStore struct {
|
|
data map[string][]byte
|
|
mu sync.RWMutex
|
|
closed bool
|
|
}
|
|
|
|
// NewMemoryStore creates a new in-memory store.
|
|
func NewMemoryStore() *MemoryStore {
|
|
return &MemoryStore{
|
|
data: make(map[string][]byte),
|
|
}
|
|
}
|
|
|
|
// Get retrieves a value by key.
|
|
func (m *MemoryStore) Get(key []byte) ([]byte, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
if m.closed {
|
|
return nil, ErrClosed
|
|
}
|
|
|
|
value, ok := m.data[string(key)]
|
|
if !ok {
|
|
return nil, ErrNotFound
|
|
}
|
|
|
|
// Return a copy to prevent mutation
|
|
result := make([]byte, len(value))
|
|
copy(result, value)
|
|
return result, nil
|
|
}
|
|
|
|
// Put stores a value by key.
|
|
func (m *MemoryStore) Put(key, value []byte) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
if m.closed {
|
|
return ErrClosed
|
|
}
|
|
|
|
// Store a copy to prevent mutation
|
|
v := make([]byte, len(value))
|
|
copy(v, value)
|
|
m.data[string(key)] = v
|
|
|
|
return nil
|
|
}
|
|
|
|
// Delete removes a key.
|
|
func (m *MemoryStore) Delete(key []byte) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
if m.closed {
|
|
return ErrClosed
|
|
}
|
|
|
|
delete(m.data, string(key))
|
|
return nil
|
|
}
|
|
|
|
// Has checks if a key exists.
|
|
func (m *MemoryStore) Has(key []byte) (bool, error) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
if m.closed {
|
|
return false, ErrClosed
|
|
}
|
|
|
|
_, ok := m.data[string(key)]
|
|
return ok, nil
|
|
}
|
|
|
|
// Close closes the store.
|
|
func (m *MemoryStore) Close() error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
m.closed = true
|
|
m.data = nil
|
|
return nil
|
|
}
|
|
|
|
// NewBatch creates a new batch.
|
|
func (m *MemoryStore) NewBatch() Batch {
|
|
return &memoryBatch{
|
|
store: m,
|
|
ops: make([]batchOp, 0),
|
|
}
|
|
}
|
|
|
|
// NewIterator creates an iterator over keys in [start, end).
|
|
func (m *MemoryStore) NewIterator(start, end []byte) Iterator {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
|
|
// Collect and sort keys in range
|
|
var keys []string
|
|
for k := range m.data {
|
|
kb := []byte(k)
|
|
if (start == nil || bytes.Compare(kb, start) >= 0) &&
|
|
(end == nil || bytes.Compare(kb, end) < 0) {
|
|
keys = append(keys, k)
|
|
}
|
|
}
|
|
sort.Strings(keys)
|
|
|
|
return &memoryIterator{
|
|
store: m,
|
|
keys: keys,
|
|
index: -1,
|
|
}
|
|
}
|
|
|
|
type batchOp struct {
|
|
key []byte
|
|
value []byte
|
|
delete bool
|
|
}
|
|
|
|
type memoryBatch struct {
|
|
store *MemoryStore
|
|
ops []batchOp
|
|
}
|
|
|
|
func (b *memoryBatch) Put(key, value []byte) error {
|
|
k := make([]byte, len(key))
|
|
v := make([]byte, len(value))
|
|
copy(k, key)
|
|
copy(v, value)
|
|
b.ops = append(b.ops, batchOp{key: k, value: v})
|
|
return nil
|
|
}
|
|
|
|
func (b *memoryBatch) Delete(key []byte) error {
|
|
k := make([]byte, len(key))
|
|
copy(k, key)
|
|
b.ops = append(b.ops, batchOp{key: k, delete: true})
|
|
return nil
|
|
}
|
|
|
|
func (b *memoryBatch) Write() error {
|
|
b.store.mu.Lock()
|
|
defer b.store.mu.Unlock()
|
|
|
|
if b.store.closed {
|
|
return ErrClosed
|
|
}
|
|
|
|
for _, op := range b.ops {
|
|
if op.delete {
|
|
delete(b.store.data, string(op.key))
|
|
} else {
|
|
b.store.data[string(op.key)] = op.value
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (b *memoryBatch) Reset() {
|
|
b.ops = b.ops[:0]
|
|
}
|
|
|
|
func (b *memoryBatch) Size() int {
|
|
return len(b.ops)
|
|
}
|
|
|
|
type memoryIterator struct {
|
|
store *MemoryStore
|
|
keys []string
|
|
index int
|
|
err error
|
|
}
|
|
|
|
func (it *memoryIterator) Next() bool {
|
|
it.index++
|
|
return it.index < len(it.keys)
|
|
}
|
|
|
|
func (it *memoryIterator) Key() []byte {
|
|
if it.index < 0 || it.index >= len(it.keys) {
|
|
return nil
|
|
}
|
|
return []byte(it.keys[it.index])
|
|
}
|
|
|
|
func (it *memoryIterator) Value() []byte {
|
|
if it.index < 0 || it.index >= len(it.keys) {
|
|
return nil
|
|
}
|
|
it.store.mu.RLock()
|
|
defer it.store.mu.RUnlock()
|
|
return it.store.data[it.keys[it.index]]
|
|
}
|
|
|
|
func (it *memoryIterator) Error() error {
|
|
return it.err
|
|
}
|
|
|
|
func (it *memoryIterator) Release() {
|
|
it.keys = nil
|
|
}
|
|
|
|
// Ensure MemoryStore implements all interfaces.
|
|
var (
|
|
_ Store = (*MemoryStore)(nil)
|
|
_ BatchWriter = (*MemoryStore)(nil)
|
|
_ IterableStore = (*MemoryStore)(nil)
|
|
)
|