redisx

package module
v0.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 12, 2022 License: AGPL-3.0 Imports: 7 Imported by: 0

README

redisx Build Status codecov Go Report Card

redisx is a library of Go utilities built on the redigo redis client library.

IntervalSet

Creating very large numbers of Redis keys can hurt performance, but putting them all in a single set requires that they all have the same expiration. Marker is a way to have multiple sets based on time intervals, accessible like a single set. You trade accuracy of expiry times for a significantly reduced key space. For example using 2 intervals of 24 hours:

marker := NewIntervalSet("foos", time.Hour*24, 2)
marker.Add(rc, "A")  // time is 2021-12-02T09:00
...
marker.Add(rc, "B")  // time is 2021-12-03T10:00
marker.Add(rc, "C")  // time is 2021-12-03T11:00

Creates 2 Redis sets like:

foos:2021-12-02 => {"A"}       // expires at 2021-12-04T09:00
foos:2021-12-03 => {"B", "C"}  // expires at 2021-12-05T11:00

But can be accessed like a single set:

marker.Contains(rc, "A")   // true
marker.Contains(rc, "B")   // true
marker.Contains(rc, "D")   // false

IntervalHash

Same idea as IntervalSet but for hashes, and works well for caching values. For example using 2 intervals of 1 hour:

cache := NewIntervalHash("foos", time.Hour, 2)
cache.Set(rc, "A", "1")  // time is 2021-12-02T09:10
...
cache.Set(rc, "B", "2")  // time is 2021-12-02T10:15
cache.Set(rc, "C", "3")  // time is 2021-12-02T10:20

Creates 2 Redis hashes like:

foos:2021-12-02T09:00 => {"A": "1"}            // expires at 2021-12-02T11:10
foos:2021-12-02T10:00 => {"B": "2", "C": "3"}  // expires at 2021-12-02T12:20

But can be accessed like a single hash:

cache.Get(rc, "A")   // "1"
cache.Get(rc, "B")   // "2"
cache.Get(rc, "D")   // ""

IntervalSeries

When getting a value from an IntervalHash you're getting the newest value by looking back through the intervals. IntervalSeries however lets you get an accumulated value from each interval.

For example using 3 intervals of 1 hour:

series := NewIntervalSeries("foos", time.Hour, 3)
series.Record(rc, "A", 1)  // time is 2021-12-02T09:10
series.Record(rc, "A", 2)  // time is 2021-12-02T09:15
...
series.Record(rc, "A", 3)  // time is 2021-12-02T10:15
series.Record(rc, "A", 4)  // time is 2021-12-02T10:20
...
series.Record(rc, "A", 5)  // time is 2021-12-02T11:25
series.Record(rc, "B", 1)  // time is 2021-12-02T11:30

Creates 3 Redis hashes like:

foos:2021-12-02T09:00 => {"A": "3"}            // expires at 2021-12-02T12:15
foos:2021-12-02T10:00 => {"A": "7"}            // expires at 2021-12-02T13:20
foos:2021-12-02T11:00 => {"A": "5", "B": "1"}  // expires at 2021-12-02T14:30

But lets us retrieve values across intervals:

series.Get(rc, "A")   // [5, 7, 3]
series.Get(rc, "B")   // [1, 0, 0]
series.Get(rc, "C")   // [0, 0, 0]

CappedZSet

The CappedZSet type is based on a sorted set but enforces a cap on size, by only retaining the highest ranked members.

cset := NewCappedZSet("foos", 3, time.Hour*24)
cset.Add(rc, "A", 1) 
cset.Add(rc, "C", 3) 
cset.Add(rc, "D", 4)
cset.Add(rc, "B", 2) 
cset.Add(rc, "E", 5) 
cset.Members(rc)      // ["C", "D", "E"] / [3, 4, 5]

Testing Asserts

The assertredis package contains several asserts useful for testing the state of a Redis database.

rp := assertredis.TestDB()

assertredis.Keys(t, rp, []string{"foo", "bar"})
assertredis.Get(t, rp, "foo", "123")
assertredis.SMembers(t, rp, "foo_set", []string{"123", "234"})

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RandomBase64

func RandomBase64(n int) string

RandomBase64 creates a random string of the length passed in

func StringsWithScores

func StringsWithScores(reply interface{}, err error) ([]string, []float64, error)

StringsWithScores parses an array reply which is alternating pairs of strings and scores (floats)

Types

type CappedZSet

type CappedZSet struct {
	// contains filtered or unexported fields
}

CappedZSet is a sorted set but enforces a cap on size

func NewCappedZSet

func NewCappedZSet(key string, cap int, expire time.Duration) *CappedZSet

NewCappedZSet creates a new capped sorted set

func (*CappedZSet) Add

func (z *CappedZSet) Add(rc redis.Conn, member string, score float64) error

Add adds an element to the set, if its score puts in the top `cap` members

func (*CappedZSet) Card

func (z *CappedZSet) Card(rc redis.Conn) (int, error)

Card returns the cardinality of the set

func (*CappedZSet) Members

func (z *CappedZSet) Members(rc redis.Conn) ([]string, []float64, error)

Members returns all members of the set, ordered by ascending rank

type IntervalHash

type IntervalHash struct {
	// contains filtered or unexported fields
}

IntervalHash operates like a hash map but with expiring intervals

func NewIntervalHash

func NewIntervalHash(keyBase string, interval time.Duration, size int) *IntervalHash

NewIntervalHash creates a new empty interval hash

func (*IntervalHash) ClearAll

func (h *IntervalHash) ClearAll(rc redis.Conn) error

ClearAll removes all values

func (*IntervalHash) Get

func (h *IntervalHash) Get(rc redis.Conn, field string) (string, error)

Get returns the value of the given field

func (*IntervalHash) Remove

func (h *IntervalHash) Remove(rc redis.Conn, field string) error

Remove removes the given field

func (*IntervalHash) Set

func (h *IntervalHash) Set(rc redis.Conn, field, value string) error

Set sets the value of the given field

type IntervalSeries

type IntervalSeries struct {
	// contains filtered or unexported fields
}

IntervalSeries returns all values from interval based hashes.

func NewIntervalSeries

func NewIntervalSeries(keyBase string, interval time.Duration, size int) *IntervalSeries

NewIntervalSeries creates a new empty series

func (*IntervalSeries) Get

func (s *IntervalSeries) Get(rc redis.Conn, field string) ([]int64, error)

Get gets the values of field in all intervals

func (*IntervalSeries) Record

func (s *IntervalSeries) Record(rc redis.Conn, field string, value int64) error

Record increments the value of field by value in the current interval

func (*IntervalSeries) Total

func (s *IntervalSeries) Total(rc redis.Conn, field string) (int64, error)

Total gets the total value of field across all intervals

type IntervalSet

type IntervalSet struct {
	// contains filtered or unexported fields
}

IntervalSet operates like a set but with expiring intervals

func NewIntervalSet

func NewIntervalSet(keyBase string, interval time.Duration, size int) *IntervalSet

NewIntervalSet creates a new empty interval set

func (*IntervalSet) Add

func (s *IntervalSet) Add(rc redis.Conn, member string) error

Add adds the given value

func (*IntervalSet) ClearAll

func (s *IntervalSet) ClearAll(rc redis.Conn) error

ClearAll removes all values

func (*IntervalSet) Contains

func (s *IntervalSet) Contains(rc redis.Conn, member string) (bool, error)

Contains returns whether we contain the given value

func (*IntervalSet) Remove

func (s *IntervalSet) Remove(rc redis.Conn, member string) error

Remove removes the given value

type Locker

type Locker struct {
	// contains filtered or unexported fields
}

Locker is a lock implementation where grabbing returns a lock value and that value must be used to release or extend the lock.

func NewLocker

func NewLocker(key string, expiration time.Duration) *Locker

NewLocker creates a new locker using the given key and expiration

func (*Locker) Extend

func (l *Locker) Extend(rp *redis.Pool, value string, expiration time.Duration) error

Extend extends our lock expiration by the passed in number of seconds provided the lock value is correct

func (*Locker) Grab

func (l *Locker) Grab(rp *redis.Pool, retry time.Duration) (string, error)

Grab tries to grab this lock in an atomic operation. It returns the lock value if successful. It will retry every second until the retry period has ended, returning empty string if not acquired in that time.

func (*Locker) Release

func (l *Locker) Release(rp *redis.Pool, value string) error

Release releases this lock if the given lock value is correct (i.e we own this lock). It is not an error to release a lock that is no longer present.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL