Documentation
¶
Overview ¶
Package storage owns atomic cache values, counters, expiry and sweeping.
Index ¶
- type Store
- func (driver *Store) Add(ctx context.Context, key string, value []byte, ttl time.Duration) (bool, error)
- func (driver *Store) CompareAndPut(ctx context.Context, match cache.Match, entry cache.Entry) (bool, error)
- func (driver *Store) Decrement(ctx context.Context, key string, delta int64) (int64, error)
- func (driver *Store) Delete(ctx context.Context, key string) error
- func (driver *Store) ExtendLock(ctx context.Context, name, token string, ttl time.Duration) (bool, error)
- func (driver *Store) Get(ctx context.Context, key string) ([]byte, error)
- func (driver *Store) Has(ctx context.Context, key string) (bool, error)
- func (driver *Store) Increment(ctx context.Context, key string, delta int64) (int64, error)
- func (driver *Store) IncrementWithTTL(ctx context.Context, key string, delta int64, ttl time.Duration) (int64, time.Duration, error)
- func (driver *Store) Pull(ctx context.Context, key string) ([]byte, error)
- func (driver *Store) Put(ctx context.Context, key string, value []byte, ttl time.Duration) error
- func (driver *Store) Start(ctx context.Context) error
- func (driver *Store) Stop(ctx context.Context) error
- func (driver *Store) TTL(ctx context.Context, key string) (time.Duration, error)
- func (driver *Store) TryLock(ctx context.Context, name, token string, ttl time.Duration) (bool, error)
- func (driver *Store) Unlock(ctx context.Context, name, token string) (bool, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type Store ¶
type Store struct {
// Mu guards entries.
Mu sync.Mutex
// Entries maps keys to stored values, including expired ones the janitor
// or a later access has not removed yet.
Entries map[string]entry
// Cleanup is the interval between sweeps, inline and janitor. Negative
// disables sweeping.
Cleanup time.Duration
// LastSweep is when expired entries were last removed in bulk. Guarded
// by mu.
LastSweep time.Time
// Lifecycle guards cancel and done.
Lifecycle sync.Mutex
// Cancel ends the janitor goroutine. It is nil until Start runs.
Cancel context.CancelFunc
// Done closes when the janitor goroutine exits.
Done chan struct{}
}
Store implements cache.Driver in process memory.
Store is suitable for single-process applications, local development, and tests where persistence across restarts is not required. It is safe for concurrent use. Expiry is checked on access, so correctness never depends on sweeping. Writes sweep expired entries inline at most once per [Builder.Cleanup], so memory stays bounded without calling Store.Start.
Example:
driver := memorycache.New()
if err := driver.Put(ctx, "version", []byte("v1"), time.Minute); err != nil {
return err
}
func (*Store) Add ¶
func (driver *Store) Add(ctx context.Context, key string, value []byte, ttl time.Duration) (bool, error)
Add stores a copy of value only when key is absent or expired.
Example:
added, err := driver.Add(ctx, "receipt", []byte("claimed"), time.Hour)
if err != nil {
return err
}
_ = added
func (*Store) CompareAndPut ¶
func (driver *Store) CompareAndPut(ctx context.Context, match cache.Match, entry cache.Entry) (bool, error)
CompareAndPut compares the existing guard and writes entry under one mutex. Missing, expired, or unequal guards return false without changing logical values or lifetimes. A matching guard permits a copied replacement with the requested TTL; a different guard key retains its content and expiry. Cancellation is checked both before waiting and after acquiring the mutex.
Example:
driver := memorycache.New()
if err := driver.Put(ctx, "document", []byte("draft"), time.Minute); err != nil {
return err
}
applied, err := driver.CompareAndPut(ctx,
cache.Match{Key: "document", Value: []byte("draft")},
cache.Entry{Key: "document", Value: []byte("revised"), TTL: time.Minute})
if err != nil {
return err
}
_ = applied
func (*Store) Decrement ¶
Decrement decreases the integer stored at key by delta and returns the new value. A missing key is created from zero. The remaining TTL is preserved. Subtraction is checked directly, including delta == math.MinInt64. A result outside int64 returns an error wrapping strconv.ErrRange without changing the target value or expiry; a missing target remains absent.
Example:
count, err := driver.Decrement(ctx, "available", 1)
if err != nil {
return err
}
_ = count
func (*Store) Delete ¶
Delete removes key. Deleting a missing key is a no-op.
Example:
if err := driver.Delete(ctx, "version"); err != nil {
return err
}
func (*Store) ExtendLock ¶
func (driver *Store) ExtendLock(ctx context.Context, name, token string, ttl time.Duration) (bool, error)
ExtendLock resets the expiry of name to ttl from now only while it holds token and reports whether it did. It returns an error wrapping cache.ErrInvalidTTL when ttl is not positive.
Example:
extended, err := driver.ExtendLock(ctx, "lock:report", token, time.Minute)
if err != nil {
return err
}
_ = extended
func (*Store) Get ¶
Get returns a copy of the bytes stored for key. It returns cache.ErrNotFound when the key does not exist or has expired.
Example:
raw, err := driver.Get(ctx, "version")
if err != nil {
return err
}
_ = raw // Independent bytes; mutation does not alter the stored value.
func (*Store) Has ¶
Has reports whether key exists and has not expired.
Example:
found, err := driver.Has(ctx, "version")
if err != nil {
return err
}
_ = found // Observation only; use an atomic operation to guard a write.
func (*Store) Increment ¶
Increment increases the integer stored at key by delta and returns the new value. A missing key is created from zero. The remaining TTL is preserved. A mathematical result outside int64 returns an error wrapping strconv.ErrRange without changing the target value or TTL. An absent target remains absent.
Example:
count, err := driver.Increment(ctx, "views", 1)
if err != nil {
return err
}
_ = count
func (*Store) IncrementWithTTL ¶
func (driver *Store) IncrementWithTTL(ctx context.Context, key string, delta int64, ttl time.Duration) (int64, time.Duration, error)
IncrementWithTTL increases the integer stored at key by delta, ensures the key expires, and returns the new value with the remaining lifetime. A key that is missing or has no expiry gets ttl; an existing expiry is kept. It returns an error when ttl is not positive. A mathematical result outside int64 returns an error wrapping strconv.ErrRange before changing the target value or expiry. Overflow never adds a TTL to a persistent target or creates an absent one.
Example:
count, remaining, err := driver.IncrementWithTTL(ctx, "requests", 1, time.Minute)
if err != nil {
return err
}
_, _ = count, remaining
func (*Store) Pull ¶
Pull returns the bytes stored for key and removes the entry under the same lock, so concurrent callers cannot both receive the value. It returns cache.ErrNotFound when the key does not exist or has expired.
Example:
raw, err := driver.Pull(ctx, "one-time-token")
if err != nil {
return err
}
_ = raw // The entry was removed atomically with this read.
func (*Store) Put ¶
Put stores a copy of value for key. A zero ttl stores the entry without expiration.
Example:
if err := driver.Put(ctx, "version", []byte("v1"), time.Minute); err != nil {
return err
}
func (*Store) Start ¶
Start launches the janitor unless Cleanup is negative. Starting an already started driver does nothing.
Example:
driver := memorycache.New()
if err := driver.Start(ctx); err != nil {
return err
}
return driver.Stop(ctx)
func (*Store) Stop ¶
Stop ends the janitor and waits for it to exit or ctx to end. The driver stays usable afterwards; expired entries are then removed by access and by inline sweeps on writes.
Example:
cleanup, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
if err := driver.Stop(cleanup); err != nil {
return err
}
func (*Store) TTL ¶
TTL returns the remaining lifetime for key, or zero when it never expires. It returns cache.ErrNotFound when the key does not exist or has expired.
Example:
remaining, err := driver.TTL(ctx, "version")
if err != nil {
return err
}
_ = remaining
func (*Store) TryLock ¶
func (driver *Store) TryLock(ctx context.Context, name, token string, ttl time.Duration) (bool, error)
TryLock stores token under name for ttl when name is absent or expired, and reports whether it did. The entry is an ordinary one, so an expired lock is replaced like any expired key. It returns an error wrapping cache.ErrInvalidTTL when ttl is not positive.
Example:
token := rand.Text() // crypto/rand: unique to this attempt.
held, err := driver.TryLock(ctx, "lock:report", token, time.Minute)
if err != nil {
return err
}
if held {
_, err = driver.Unlock(ctx, "lock:report", token)
}
return err