-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathinmemory.go
135 lines (112 loc) · 3.4 KB
/
inmemory.go
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
package backend
import (
"context"
"sync"
datastructure "github.com/hyp3rd/hypercache/datastructure/v4"
"github.com/hyp3rd/hypercache/errors"
"github.com/hyp3rd/hypercache/types"
)
// InMemory is a cache backend that stores the items in memory, leveraging a custom `ConcurrentMap`.
type InMemory struct {
items datastructure.ConcurrentMap // map to store the items in the cache
capacity int // capacity of the cache, limits the number of items that can be stored in the cache
sync.RWMutex // mutex to protect the cache from concurrent access
}
// NewInMemory creates a new in-memory cache with the given options.
func NewInMemory(opts ...Option[InMemory]) (backend IBackend[InMemory], err error) {
InMemory := &InMemory{
items: datastructure.New(),
}
// Apply the backend options
ApplyOptions(InMemory, opts...)
// Check if the `capacity` is valid
if InMemory.capacity < 0 {
return nil, errors.ErrInvalidCapacity
}
return InMemory, 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() 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(key string) (item *types.Item, ok bool) {
item, ok = cacheBackend.items.Get(key)
if !ok {
return nil, false
}
// return the item
return item, true
}
// Set adds a Item to the cache.
func (cacheBackend *InMemory) Set(item *types.Item) error {
// Check for invalid key, value, or duration
if err := item.Valid(); err != nil {
types.ItemPool.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(ctx context.Context, filters ...IFilter) (items []*types.Item, err error) {
// Apply the filters
cacheBackend.RLock()
defer cacheBackend.RUnlock()
items = make([]*types.Item, 0, cacheBackend.items.Count())
for item := range cacheBackend.items.IterBuffered() {
copy := item
items = append(items, ©.Val)
}
// Apply the filters
if len(filters) > 0 {
for _, filter := range filters {
items, err = filter.ApplyFilter("in-memory", items)
}
}
return items, err
}
// 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) (err 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 errors.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 errors.ErrTimeoutOrCanceled
}
}