-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathinmemory.go
More file actions
155 lines (123 loc) · 3.86 KB
/
inmemory.go
File metadata and controls
155 lines (123 loc) · 3.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package backend
import (
"context"
"sync"
"github.com/hyp3rd/hypercache/internal/constants"
"github.com/hyp3rd/hypercache/internal/sentinel"
cache "github.com/hyp3rd/hypercache/pkg/cache/v2"
)
// InMemory is a cache backend that stores the items in memory, leveraging a custom `ConcurrentMap`.
type InMemory struct {
sync.RWMutex // mutex to protect the cache from concurrent access
items cache.ConcurrentMap // map to store the items in the cache
itemPoolManager *cache.ItemPoolManager // item pool manager to manage the item pool
capacity int // capacity of the cache, limits the number of items that can be stored in the cache
}
// NewInMemory creates a new in-memory cache with the given options.
func NewInMemory(opts ...Option[InMemory]) (IBackend[InMemory], error) {
backendInstance := &InMemory{
items: cache.New(),
itemPoolManager: cache.NewItemPoolManager(),
}
// Apply the backend options
ApplyOptions(backendInstance, opts...)
// Check if the `capacity` is valid
if backendInstance.capacity < 0 {
return nil, sentinel.ErrInvalidCapacity
}
return backendInstance, nil
}
// SetCapacity sets the capacity of the cache.
func (cacheBackend *InMemory) SetCapacity(capacity int) {
if capacity < 0 {
return
}
cacheBackend.capacity = capacity
}
// Capacity returns the capacity of the cacheBackend.
func (cacheBackend *InMemory) Capacity() int {
return cacheBackend.capacity
}
// Count returns the number of items in the cache.
func (cacheBackend *InMemory) Count(_ context.Context) int {
return cacheBackend.items.Count()
}
// Get retrieves the item with the given key from the cacheBackend. If the item is not found, it returns nil.
func (cacheBackend *InMemory) Get(_ context.Context, key string) (*cache.Item, bool) {
item, ok := cacheBackend.items.GetCopy(key)
if !ok {
return nil, false
}
// return the item
return item, true
}
// Touch updates the last access time and access count for a key.
func (cacheBackend *InMemory) Touch(_ context.Context, key string) bool { //nolint:ireturn
return cacheBackend.items.Touch(key)
}
// Set adds a Item to the cache.
func (cacheBackend *InMemory) Set(_ context.Context, item *cache.Item) error {
// Check for invalid key, value, or duration
err := item.Valid()
if err != nil {
cacheBackend.itemPoolManager.Put(item)
return err
}
cacheBackend.Lock()
defer cacheBackend.Unlock()
cacheBackend.items.Set(item.Key, item)
return nil
}
// List returns a list of all items in the cache filtered and ordered by the given options.
func (cacheBackend *InMemory) List(_ context.Context, filters ...IFilter) ([]*cache.Item, error) {
// Apply the filters
cacheBackend.RLock()
defer cacheBackend.RUnlock()
var err error
items := make([]*cache.Item, 0, cacheBackend.items.Count())
for item := range cacheBackend.items.IterBuffered() {
cloned := item
items = append(items, &cloned.Val)
}
// Apply the filters
if len(filters) > 0 {
for _, filter := range filters {
items, err = filter.ApplyFilter(constants.InMemoryBackend, items)
if err != nil {
return nil, err
}
}
}
return items, nil
}
// Remove removes items with the given key from the cacheBackend. If an item is not found, it does nothing.
func (cacheBackend *InMemory) Remove(ctx context.Context, keys ...string) error {
done := make(chan struct{})
go func() {
defer close(done)
for _, key := range keys {
cacheBackend.items.Remove(key)
}
}()
select {
case <-done:
return nil
case <-ctx.Done():
return sentinel.ErrTimeoutOrCanceled
}
}
// Clear removes all items from the cacheBackend.
func (cacheBackend *InMemory) Clear(ctx context.Context) error {
done := make(chan struct{})
go func() {
defer close(done)
// clear the cacheBackend
cacheBackend.items.Clear()
}()
select {
case <-done:
return nil
case <-ctx.Done():
return sentinel.ErrTimeoutOrCanceled
}
}