Repository navigation
Expand file tree
/
Copy pathprocesscache.go
More file actions
180 lines (155 loc) · 5.59 KB
/
Copy pathprocesscache.go
File metadata and controls
180 lines (155 loc) · 5.59 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
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
// Package processcache provides a thread-safe, in-process LRU cache bounded by
// an accounted retained-size budget for Go applications that need fast local
// caching without Redis, Memcached, a database, an HTTP server, or a sidecar.
//
// Example usage:
//
// cache, err := processcache.NewMemoryCache(
// processcache.WithCleanupDisabled(),
// processcache.WithMaxSize(10*processcache.MB),
// )
// if err != nil {
// panic(err)
// }
// defer cache.Close()
//
// cache.Set("user:1", "Tonmoy", time.Minute)
//
// name, ok := processcache.GetAs[string](cache, "user:1")
// fmt.Println(name, ok)
package processcache
import (
"time"
internal "github.com/tonmoytalukder/process-cache/internal/processcache"
)
const (
// KB is one kibibyte in bytes.
KB = internal.KB
// MB is one mebibyte in bytes.
MB = internal.MB
// GB is one gibibyte in bytes.
GB = internal.GB
)
var (
// ErrInvalidMaxSize reports a non-positive cache size limit.
ErrInvalidMaxSize = internal.ErrInvalidMaxSize
// ErrInvalidCleanupInterval reports a non-positive cleanup interval when cleanup is enabled.
ErrInvalidCleanupInterval = internal.ErrInvalidCleanupInterval
// ErrInvalidTypePrefix reports an empty type-prefix quota key.
ErrInvalidTypePrefix = internal.ErrInvalidTypePrefix
// ErrInvalidTypeLimit reports a non-positive type quota.
ErrInvalidTypeLimit = internal.ErrInvalidTypeLimit
// ErrDuplicateTypePrefix reports duplicate configured type prefixes.
ErrDuplicateTypePrefix = internal.ErrDuplicateTypePrefix
// ErrOverlappingTypePrefix reports prefixes whose match ranges overlap.
ErrOverlappingTypePrefix = internal.ErrOverlappingTypePrefix
// ErrNilSizer reports a nil sizer implementation.
ErrNilSizer = internal.ErrNilSizer
// ErrNilClock reports a nil clock implementation.
ErrNilClock = internal.ErrNilClock
)
// Cache is the minimal concurrent cache contract exposed by this package.
type Cache interface {
Get(key string) (any, bool)
Set(key string, value any, ttl ...time.Duration) bool
Delete(key string) bool
// Exists checks presence and expiration without promoting LRU recency.
Exists(key string) bool
Clear()
// Len returns the number of tracked entries. Expired entries remain tracked
// until lazy expiration or the background sweep removes them.
Len() int
Stats() Stats
Close() error
}
// MemoryCache is the in-memory LRU cache implementation.
type MemoryCache = internal.MemoryCache
// Config configures a MemoryCache instance.
type Config = internal.Config
// TypeLimit caps the accounted size of keys with a given prefix. It is not a
// reservation; global LRU eviction still applies across all prefixes.
type TypeLimit = internal.TypeLimit
// Stats is a snapshot of cache counters and accounted capacity usage.
type Stats = internal.Stats
// Option mutates a Config during construction.
type Option = internal.Option
// Sizer estimates the retained cache cost of one entry.
//
// Implementations should be deterministic and concurrency-safe and must not
// mutate the value. Values must not be mutated concurrently with SizeOf. A
// non-positive result falls back to the built-in retained-size estimator.
type Sizer = internal.Sizer
// Clock provides time to the cache for expiration logic.
//
// Implementations must not call back into the cache; doing so may deadlock.
type Clock = internal.Clock
var (
_ Cache = (*MemoryCache)(nil)
_ Sizer = internal.DefaultSizer{}
_ Clock = internal.RealClock{}
)
// DefaultConfig returns the package defaults for a new MemoryCache.
func DefaultConfig() Config {
return internal.DefaultConfig()
}
// NewMemoryCache constructs a MemoryCache from functional options.
func NewMemoryCache(opts ...Option) (*MemoryCache, error) {
return internal.NewMemoryCache(opts...)
}
// NewMemoryCacheFromConfig constructs a MemoryCache from an explicit Config.
//
// Callers typically start from DefaultConfig and then override selected fields.
func NewMemoryCacheFromConfig(cfg Config) (*MemoryCache, error) {
return internal.NewMemoryCacheFromConfig(cfg)
}
// WithMaxSize sets the global accounted retained-size limit in bytes.
func WithMaxSize(bytes int64) Option {
return internal.WithMaxSize(bytes)
}
// WithCleanupInterval sets the background expiration sweep interval.
func WithCleanupInterval(interval time.Duration) Option {
return internal.WithCleanupInterval(interval)
}
// WithCleanupDisabled disables the background expiration sweeper.
func WithCleanupDisabled() Option {
return internal.WithCleanupDisabled()
}
// WithTypeLimit adds one prefix-scoped accounted-size maximum.
func WithTypeLimit(prefix string, bytes int64) Option {
return internal.WithTypeLimit(prefix, bytes)
}
// WithTypeLimits adds multiple prefix-scoped accounted-size maximums.
func WithTypeLimits(limits ...TypeLimit) Option {
return internal.WithTypeLimits(limits...)
}
// WithSizer overrides the default size estimator.
func WithSizer(sizer Sizer) Option {
return internal.WithSizer(sizer)
}
// WithClock overrides the time source used for expiration.
func WithClock(clock Clock) Option {
return internal.WithClock(clock)
}
// WithMetrics enables or disables atomic stats counters.
func WithMetrics(enabled bool) Option {
return internal.WithMetrics(enabled)
}
// GetAs returns a typed cache value when the key exists and matches T.
//
// Cached nil values are observable through Get, but GetAs returns false for
// them because a nil dynamic value cannot satisfy a concrete type assertion.
func GetAs[T any](c Cache, key string) (T, bool) {
var zero T
if c == nil {
return zero, false
}
value, ok := c.Get(key)
if !ok {
return zero, false
}
typed, ok := value.(T)
if !ok {
return zero, false
}
return typed, true
}