Loading documentation...
Loading documentation...
Loading documentation...
The core synapse package provides a high-performance, generic similarity-based cache with intelligent sharding.
Import Path: github.com/kolosys/synapse
Synapse is more than a traditional key-value cache. It supports similarity-based lookups, allowing you to find entries with keys that are "close enough" to your query when exact matches don't exist.
Synapse distributes entries across multiple shards to reduce lock contention and improve concurrent performance:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Cache[K, V] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā ā
ā ā Shard 0 ā ā Shard 1 ā ā Shard 2 ā ā Shard N ā ā
ā āāāāāāāāāāā⤠āāāāāāāāāāā⤠āāāāāāāāāāā⤠āāāāāāāāāāā⤠ā
ā ā RWMutex ā ā RWMutex ā ā RWMutex ā ā RWMutex ā ā
ā ā data map ā ā data map ā ā data map ā ā data map ā ā
ā ā keys []K ā ā keys []K ā ā keys []K ā ā keys []K ā ā
ā ā eviction ā ā eviction ā ā eviction ā ā eviction ā ā
ā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāEach shard operates independently with:
sync.RWMutex for thread-safe accessKeys are distributed to shards using FNV-1a hashing:
// Simplified key-to-shard mapping
hash := fnv.New64a()
hash.Write([]byte(keyToString(key)))
shardIndex := hash.Sum64() % uint64(numShards)This ensures even distribution across shards for most key patterns.
The main cache type, generic over key type K (must be comparable) and value type V (any type):
type Cache[K comparable, V any] struct {
shards []*Shard[K, V]
similarity SimilarityFunc[K]
threshold float64
options *Options
}Create a cache with functional options:
cache := synapse.New[string, string](
synapse.WithShards(16),
synapse.WithMaxSize(10000),
synapse.WithThreshold(0.8),
synapse.WithTTL(5 * time.Minute),
synapse.WithEviction(eviction.NewLRU(10000)),
)Each cache entry contains the value and metadata:
type Entry[K comparable, V any] struct {
Key K
Value V
CreatedAt time.Time
AccessedAt time.Time
AccessCount uint64
ExpiresAt time.Time
Metadata map[string]any
Namespace string
}The cache automatically manages:
CreatedAt - Set when the entry is createdAccessedAt - Updated on each accessAccessCount - Incremented on each accessExpiresAt - Set based on TTL configurationA function type for computing similarity between keys:
type SimilarityFunc[K comparable] func(a, b K) float64Must return a score between 0.0 (completely different) and 1.0 (identical).
Store a key-value pair:
err := cache.Set(ctx, "key", "value")
if err != nil {
// Handle context cancellation
}Behavior:
Retrieve a value by exact key match:
value, found := cache.Get(ctx, "key")
if found {
fmt.Println(value)
}Behavior:
Find the most similar key above the threshold:
value, matchedKey, score, found := cache.GetSimilar(ctx, "query")
if found {
fmt.Printf("Found %v at key %v (score: %.2f)
", value, matchedKey, score)
}Behavior:
Remove an entry:
deleted := cache.Delete(ctx, "key")
if deleted {
fmt.Println("Entry removed")
}Get total entry count:
count := cache.Len()Sums the count across all shards.
Set the number of shards (1-256):
synapse.WithShards(32)More shards reduce lock contention but increase memory overhead. Default: 16.
Set the maximum total entries:
synapse.WithMaxSize(10000)Distributed across shards: maxSizePerShard = maxSize / numShards. Default: 1000.
Set the minimum similarity score for matches:
synapse.WithThreshold(0.8) // 80% similarity requiredMust be between 0.0 and 1.0. Default: 0.8.
Set the eviction policy:
synapse.WithEviction(eviction.NewLRU(10000))Default: nil (FIFO fallback).
Set time-to-live for entries:
synapse.WithTTL(5 * time.Minute)Default: 0 (no expiration).
Enable statistics tracking:
synapse.WithStats(true)Default: false.
Partition entries by namespace:
tenant1Ctx := synapse.WithNamespace(ctx, "tenant-1")
tenant2Ctx := synapse.WithNamespace(ctx, "tenant-2")
// Same key, different namespaces
cache.Set(tenant1Ctx, "config", "tenant1-config")
cache.Set(tenant2Ctx, "config", "tenant2-config")
// Each tenant sees only their data
value, _ := cache.Get(tenant1Ctx, "config") // "tenant1-config"Attach metadata to the context:
ctx := synapse.WithMetadata(ctx, "request_id", "abc123")
requestID, ok := synapse.GetMetadata(ctx, "request_id")All operations respect context cancellation:
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
// Long similarity search will be cancelled
_, _, _, found := cache.GetSimilar(ctx, "query")For best performance, try exact match before similarity search:
// Fast O(1) exact lookup
if value, found := cache.Get(ctx, key); found {
return value, nil
}
// Slower O(n) similarity search as fallback
if value, _, _, found := cache.GetSimilar(ctx, key); found {
return value, nil
}
return nil, ErrNotFoundWhen you always want the best match:
value, matchedKey, score, found := cache.GetSimilar(ctx, query)
if !found {
return nil, ErrNotFound
}
// Optionally check if it was an exact match
if score == 1.0 {
// Exact match
}| Operation | Complexity | Notes |
|---|---|---|
Get | O(1) | Single shard lookup |
Set | O(1) | Amortized, may trigger eviction |
Delete | O(n) | O(1) map delete + O(n) slice removal |
GetSimilar | O(nĆs) | n = entries per shard, s = shards |
Len | O(s) | s = number of shards |
Get, GetSimilar, Len) use RLockSet, Delete) use LockThe core synapse package provides a high-performance, generic similarity-based cache with intelligent sharding.
Import Path: github.com/kolosys/synapse
Synapse is more than a traditional key-value cache. It supports similarity-based lookups, allowing you to find entries with keys that are "close enough" to your query when exact matches don't exist.
Synapse distributes entries across multiple shards to reduce lock contention and improve concurrent performance:
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Cache[K, V] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā ā
ā ā Shard 0 ā ā Shard 1 ā ā Shard 2 ā ā Shard N ā ā
ā āāāāāāāāāāā⤠āāāāāāāāāāā⤠āāāāāāāāāāā⤠āāāāāāāāāāā⤠ā
ā ā RWMutex ā ā RWMutex ā ā RWMutex ā ā RWMutex ā ā
ā ā data map ā ā data map ā ā data map ā ā data map ā ā
ā ā keys []K ā ā keys []K ā ā keys []K ā ā keys []K ā ā
ā ā eviction ā ā eviction ā ā eviction ā ā eviction ā ā
ā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāEach shard operates independently with:
sync.RWMutex for thread-safe accessKeys are distributed to shards using FNV-1a hashing:
// Simplified key-to-shard mapping
hash := fnv.New64a()
hash.Write([]byte(keyToString(key)))
shardIndex := hash.Sum64() % uint64(numShards)This ensures even distribution across shards for most key patterns.
The main cache type, generic over key type K (must be comparable) and value type V (any type):
type Cache[K comparable, V any] struct {
shards []*Shard[K, V]
similarity SimilarityFunc[K]
threshold float64
options *Options
}Create a cache with functional options:
cache := synapse.New[string, string](
synapse.WithShards(16),
synapse.WithMaxSize(10000),
synapse.WithThreshold(0.8),
synapse.WithTTL(5 * time.Minute),
synapse.WithEviction(eviction.NewLRU(10000)),
)Each cache entry contains the value and metadata:
type Entry[K comparable, V any] struct {
Key K
Value V
CreatedAt time.Time
AccessedAt time.Time
AccessCount uint64
ExpiresAt time.Time
Metadata map[string]any
Namespace string
}The cache automatically manages:
CreatedAt - Set when the entry is createdAccessedAt - Updated on each accessAccessCount - Incremented on each accessExpiresAt - Set based on TTL configurationA function type for computing similarity between keys:
type SimilarityFunc[K comparable] func(a, b K) float64Must return a score between 0.0 (completely different) and 1.0 (identical).
Store a key-value pair:
err := cache.Set(ctx, "key", "value")
if err != nil {
// Handle context cancellation
}Behavior:
Retrieve a value by exact key match:
value, found := cache.Get(ctx, "key")
if found {
fmt.Println(value)
}Behavior:
Find the most similar key above the threshold:
value, matchedKey, score, found := cache.GetSimilar(ctx, "query")
if found {
fmt.Printf("Found %v at key %v (score: %.2f)
", value, matchedKey, score)
}Behavior:
Remove an entry:
deleted := cache.Delete(ctx, "key")
if deleted {
fmt.Println("Entry removed")
}Get total entry count:
count := cache.Len()Sums the count across all shards.
Set the number of shards (1-256):
synapse.WithShards(32)More shards reduce lock contention but increase memory overhead. Default: 16.
Set the maximum total entries:
synapse.WithMaxSize(10000)Distributed across shards: maxSizePerShard = maxSize / numShards. Default: 1000.
Set the minimum similarity score for matches:
synapse.WithThreshold(0.8) // 80% similarity requiredMust be between 0.0 and 1.0. Default: 0.8.
Set the eviction policy:
synapse.WithEviction(eviction.NewLRU(10000))Default: nil (FIFO fallback).
Set time-to-live for entries:
synapse.WithTTL(5 * time.Minute)Default: 0 (no expiration).
Enable statistics tracking:
synapse.WithStats(true)Default: false.
Partition entries by namespace:
tenant1Ctx := synapse.WithNamespace(ctx, "tenant-1")
tenant2Ctx := synapse.WithNamespace(ctx, "tenant-2")
// Same key, different namespaces
cache.Set(tenant1Ctx, "config", "tenant1-config")
cache.Set(tenant2Ctx, "config", "tenant2-config")
// Each tenant sees only their data
value, _ := cache.Get(tenant1Ctx, "config") // "tenant1-config"Attach metadata to the context:
ctx := synapse.WithMetadata(ctx, "request_id", "abc123")
requestID, ok := synapse.GetMetadata(ctx, "request_id")All operations respect context cancellation:
ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
// Long similarity search will be cancelled
_, _, _, found := cache.GetSimilar(ctx, "query")For best performance, try exact match before similarity search:
// Fast O(1) exact lookup
if value, found := cache.Get(ctx, key); found {
return value, nil
}
// Slower O(n) similarity search as fallback
if value, _, _, found := cache.GetSimilar(ctx, key); found {
return value, nil
}
return nil, ErrNotFoundWhen you always want the best match:
value, matchedKey, score, found := cache.GetSimilar(ctx, query)
if !found {
return nil, ErrNotFound
}
// Optionally check if it was an exact match
if score == 1.0 {
// Exact match
}| Operation | Complexity | Notes |
|---|---|---|
Get | O(1) | Single shard lookup |
Set | O(1) | Amortized, may trigger eviction |
Delete | O(n) | O(1) map delete + O(n) slice removal |
GetSimilar | O(nĆs) | n = entries per shard, s = shards |
Len | O(s) | s = number of shards |
Get, GetSimilar, Len) use RLockSet, Delete) use Lockāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Cache[K, V] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā ā
ā ā Shard 0 ā ā Shard 1 ā ā Shard 2 ā ā Shard N ā ā
ā āāāāāāāāāāā⤠āāāāāāāāāāā⤠āāāāāāāāāāā⤠āāāāāāāāāāā⤠ā
ā ā RWMutex ā ā RWMutex ā ā RWMutex ā ā RWMutex ā ā
ā ā data map ā ā data map ā ā data map ā ā data map ā ā
ā ā keys []K ā ā keys []K ā ā keys []K ā ā keys []K ā ā
ā ā eviction ā ā eviction ā ā eviction ā ā eviction ā ā
ā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā// Simplified key-to-shard mapping
hash := fnv.New64a()
hash.Write([]byte(keyToString(key)))
shardIndex := hash.Sum64() % uint64(numShards)type Cache[K comparable, V any] struct {
shards []*Shard[K, V]
similarity SimilarityFunc[K]
threshold float64
options *Options
}cache := synapse.New[string, string](
synapse.WithShards(16),
synapse.WithMaxSize(10000),
synapse.WithThreshold(0.8),
synapse.WithTTL(5 * time.Minute),
synapse.WithEviction(eviction.NewLRU(10000)),
)type Entry[K comparable, V any] struct {
Key K
Value V
CreatedAt time.Time
AccessedAt time.Time
AccessCount uint64
ExpiresAt time.Time
Metadata map[string]any
Namespace string
}type SimilarityFunc[K comparable] func(a, b K) float64err := cache.Set(ctx, "key", "value")
if err != nil {
// Handle context cancellation
}value, found := cache.Get(ctx, "key")
if found {
fmt.Println(value)
}value, matchedKey, score, found := cache.GetSimilar(ctx, "query")
if found {
fmt.Printf("Found %v at key %v (score: %.2f)
", value, matchedKey, score)
}deleted := cache.Delete(ctx, "key")
if deleted {
fmt.Println("Entry removed")
}count := cache.Len()synapse.WithShards(32)synapse.WithMaxSize(10000)synapse.WithThreshold(0.8) // 80% similarity requiredsynapse.WithEviction(eviction.NewLRU(10000))synapse.WithTTL(5 * time.Minute)synapse.WithStats(true)tenant1Ctx := synapse.WithNamespace(ctx, "tenant-1")
tenant2Ctx := synapse.WithNamespace(ctx, "tenant-2")
// Same key, different namespaces
cache.Set(tenant1Ctx, "config", "tenant1-config")
cache.Set(tenant2Ctx, "config", "tenant2-config")
// Each tenant sees only their data
value, _ := cache.Get(tenant1Ctx, "config") // "tenant1-config"ctx := synapse.WithMetadata(ctx, "request_id", "abc123")
requestID, ok := synapse.GetMetadata(ctx, "request_id")ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
// Long similarity search will be cancelled
_, _, _, found := cache.GetSimilar(ctx, "query")// Fast O(1) exact lookup
if value, found := cache.Get(ctx, key); found {
return value, nil
}
// Slower O(n) similarity search as fallback
if value, _, _, found := cache.GetSimilar(ctx, key); found {
return value, nil
}
return nil, ErrNotFoundvalue, matchedKey, score, found := cache.GetSimilar(ctx, query)
if !found {
return nil, ErrNotFound
}
// Optionally check if it was an exact match
if score == 1.0 {
// Exact match
}āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā Cache[K, V] ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā¤
ā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā ā
ā ā Shard 0 ā ā Shard 1 ā ā Shard 2 ā ā Shard N ā ā
ā āāāāāāāāāāā⤠āāāāāāāāāāā⤠āāāāāāāāāāā⤠āāāāāāāāāāā⤠ā
ā ā RWMutex ā ā RWMutex ā ā RWMutex ā ā RWMutex ā ā
ā ā data map ā ā data map ā ā data map ā ā data map ā ā
ā ā keys []K ā ā keys []K ā ā keys []K ā ā keys []K ā ā
ā ā eviction ā ā eviction ā ā eviction ā ā eviction ā ā
ā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā āāāāāāāāāāāā ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā// Simplified key-to-shard mapping
hash := fnv.New64a()
hash.Write([]byte(keyToString(key)))
shardIndex := hash.Sum64() % uint64(numShards)type Cache[K comparable, V any] struct {
shards []*Shard[K, V]
similarity SimilarityFunc[K]
threshold float64
options *Options
}cache := synapse.New[string, string](
synapse.WithShards(16),
synapse.WithMaxSize(10000),
synapse.WithThreshold(0.8),
synapse.WithTTL(5 * time.Minute),
synapse.WithEviction(eviction.NewLRU(10000)),
)type Entry[K comparable, V any] struct {
Key K
Value V
CreatedAt time.Time
AccessedAt time.Time
AccessCount uint64
ExpiresAt time.Time
Metadata map[string]any
Namespace string
}type SimilarityFunc[K comparable] func(a, b K) float64err := cache.Set(ctx, "key", "value")
if err != nil {
// Handle context cancellation
}value, found := cache.Get(ctx, "key")
if found {
fmt.Println(value)
}value, matchedKey, score, found := cache.GetSimilar(ctx, "query")
if found {
fmt.Printf("Found %v at key %v (score: %.2f)
", value, matchedKey, score)
}deleted := cache.Delete(ctx, "key")
if deleted {
fmt.Println("Entry removed")
}count := cache.Len()synapse.WithShards(32)synapse.WithMaxSize(10000)synapse.WithThreshold(0.8) // 80% similarity requiredsynapse.WithEviction(eviction.NewLRU(10000))synapse.WithTTL(5 * time.Minute)synapse.WithStats(true)tenant1Ctx := synapse.WithNamespace(ctx, "tenant-1")
tenant2Ctx := synapse.WithNamespace(ctx, "tenant-2")
// Same key, different namespaces
cache.Set(tenant1Ctx, "config", "tenant1-config")
cache.Set(tenant2Ctx, "config", "tenant2-config")
// Each tenant sees only their data
value, _ := cache.Get(tenant1Ctx, "config") // "tenant1-config"ctx := synapse.WithMetadata(ctx, "request_id", "abc123")
requestID, ok := synapse.GetMetadata(ctx, "request_id")ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond)
defer cancel()
// Long similarity search will be cancelled
_, _, _, found := cache.GetSimilar(ctx, "query")// Fast O(1) exact lookup
if value, found := cache.Get(ctx, key); found {
return value, nil
}
// Slower O(n) similarity search as fallback
if value, _, _, found := cache.GetSimilar(ctx, key); found {
return value, nil
}
return nil, ErrNotFoundvalue, matchedKey, score, found := cache.GetSimilar(ctx, query)
if !found {
return nil, ErrNotFound
}
// Optionally check if it was an exact match
if score == 1.0 {
// Exact match
}