cacher

package module
v1.0.3 Latest Latest
Warning

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

Go to latest
Published: Jun 29, 2025 License: GPL-3.0 Imports: 4 Imported by: 16

README

Cacher

Cacher is a fast, decentralised caching library, generic in nature and uses Go's built-in maps to store data. It has a plenty of features like TTL, Revaluation etc.

There are plenty examples available in the examples directory and cover almost every feature of the library with explanation and real life examples.

Support Go Versions: Go v1.18 and newer

Go Reference GPLv3 license

Key Highlights:

  • Decentralised: Allows users to implement decentralised caching system which helps to perform multiple set-get operations parallely.
  • TTL (Time-To-Live): It allows us to expire a key after a specific time period.
  • Revaluation: This is another useful feature that allows us to keep keys cached as per their usage frequency.
  • Zero Bloat: Doesn't rely on any 3rd party library and only uses standard ones.
  • Structs Friendly: You don't need to serialize your structs to bytes to save them as values, which makes the set-get process faster and allows us to write more readable code.
  • Well Documentated: Cacher is very well documentated and contains examples in the docs wherever required. There are plenty of examples available in the examples directory to get a quick overview.

Getting Started

We have divided this section in several sub-sections, you can follow them sequentially to start using this library right now!

Downloading the library

You can download it using the standard go get command:

go get github.com/AnimeKaizoku/cacher
Basic Example

We will assume that you've already downloaded the library in your project as described in the previous section. Now we will learn how to use it in your Go projects with the help of a basic example.

You can check-out examples directory for more detailed and well explained examples, here we will create just a basic program with a simple Cacher instance:

package main

import "github.com/AnimeKaizoku/cacher"

var cache = cacher.NewCacher[int, string](nil)

func main() {
    cache.Set(1, "Value for 1 of type string")
    cache.Set(2, "Value for 2 of type string")

    valueOf1, ok := cache.Get(1)
    if !ok {
        println("value of 1 not found")
        return
    }
    println("value of 1 is:")
    println(valueOf1)
}
Documentation and Examples

Cacher is a well-documentated library, and contains well explained examples with the help of real life cases which can be found out in examples directory.

Click here to check-out documentations.

Decentralised Usage

As we have already learnt how to create a simple Cacher instance, we can head towards our next step.

Decentralising means, distributing the work of a single central system to multiple systems. Since Cacher is a lightweight library, we can easily create new cacher instances for every level of our program.

An example structure is shown below:

cacher1----module1.go---\
cacher2----module2.go----\
cacher3----module2.go-----} main.go
cacher4----module3.go----/
cacher5----module4.go---/

As we can see above, we have 5 modules in our program (module 1-5) where each of them have their own Cacher instance instead of a single caching instance we would've defined for our whole program. This approach allows us to distribute our load to multiple cachers which will help us to achieve better efficiency than we would have got from a single central cacher. This approach also allows us to use different Types of values for different modules.

Benchmarks

We made comparision between 3 libraries, i.e. Cacher, BigCache, FreeCache and took benchmark tests in two different situations:

Situation 1: Serialisation needed bench1 Above screenshot contains benchmark of the situation when you'll need to serialise your struct to bytes to store in BigCache/FreeCache, while you won't need to do that in case of Cacher since it uses Generics. We used "encoding/gob" for serialising the value struct to bytes

Situation 2: Serialisation not needed bench2 Above screenshot contains benchmark of the situation when you won't need to serialise your value to bytes or we can say, serialisation time removed.

Conclusion: We can clearly see the difference. Although the libraries like BigCache and FreeCache act quickly without the serialisation time included, in practical life, you will need to serialise your date when attempting to cache structs while since Cacher uses Generic ability of Go, you won't need to serialise your data while using it and can just create a new cacher instance with your Value Type set as your struct's type.

Contributing

Contributions are always welcome! Just create a PR (Pull Request) with what you want to contribute with a brief description.

Please make sure to update examples as appropriate.

License

GPLv3
Cacher is licensed under GNU General Public License v3

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Cacher

type Cacher[C comparable, T any] struct {
	// contains filtered or unexported fields
}

Cacher is a fast, decentralised caching system, generic in nature and uses Go's in built mapping to store data. It has a plenty of features like TTL, Revaluation etc.

Some of the main features are descried below:

TTL (Time-To-Live): It allows us to expire a key after a specific time period. Eg: If TTL is set to 30 seconds, then each key of current Cacher will be expired after 30 seconds of their addition.

Revaluation: This is another useful feature that allows us to keep keys cached as per their usage frequency. Working: Whenever the keys will be retrieved via (Cacher.Get) method, its expiry will be renewed and this will allow us to keep frequently used keys in the map without expiration.

func NewCacher

func NewCacher[KeyT comparable, ValueT any](opts *NewCacherOpts) *Cacher[KeyT, ValueT]

NewCacher is a generic function which creates a new Cacher instance.

Generic parameters (for current Cacher instance):

KeyT: It is the "static" type of keys of our cache. It accepts types which implement built-in comparable interface. Eg: If it is set to string, then keys will only be allowed as a string built-in data-type.

ValueT: It is the type of values of our cache. It can be set to any type. Eg: If it is set to string, then value will only be allowed as a string built-in data-type.

Input parameters:

opts (type *NewCacherOpts): It contains optional parameters which you can use while creating a new Cacher instance.

General Example: c := cacher.NewCacher[int, string](&cacher.NewCacherOpts{10*time.Minute, time.Hour, true}) will create a new Cacher instance which will expire keys after 10 minutes of their addition to the system, all the expired keys will be deleted from cache once in an hour. Keys will have their expiry revalueted on every c.Get call.

func (*Cacher[C, T]) Delete

func (c *Cacher[C, T]) Delete(key C)

Delete is used to delete the input key from current Cacher instance. It doesn't return anything. If there is no such key, Delete is a no-op.

func (*Cacher[C, T]) DeleteSome

func (c *Cacher[C, T]) DeleteSome(cond SegrigatorFunc[T])

DeleteSome is used to delete keys which satisfied a particular condition determined via SegrigatorFunc.

func (*Cacher[C, T]) Get

func (c *Cacher[C, T]) Get(key C) (value T, ok bool)

Set is used to get value of the input key. It returns value of input key with true while returns empty value with false if key is not found or has expired already

Note: It will renew the expiration time of the input key which is retrieved if revaluation mode is on for current Cacher instance.

func (*Cacher[C, T]) GetAll

func (c *Cacher[C, T]) GetAll() []T

GetAll is used to return all the unexpired key-value pairs present in the current Cacher instance, returns a slice of values.

Note: It doesn't renew expiration time of any key even if the revaluation mode is turned on for the current Cacher instance.

func (*Cacher[C, T]) GetSome

func (c *Cacher[C, T]) GetSome(cond SegrigatorFunc[T]) []T

GetSome is used to get keys which satisfired a particular condition determined via SegrigatorFunc. It returns those values which satisfied the condition determined via SegrigatorFunc.

func (*Cacher[C, T]) NumKeys

func (c *Cacher[C, T]) NumKeys() int

NumKeys counts the number of keys present in the current Cacher instance and returns that count.

func (*Cacher[C, T]) Reset

func (c *Cacher[C, T]) Reset()

The Reset function deletes the current cache map and reallocates an empty one in place of it. Use it if you want to delete all keys at once. It doesn't return anything.

func (*Cacher[C, T]) Set

func (c *Cacher[C, T]) Set(key C, val T)

Set is used to set a new key-value pair to the current Cacher instance. It doesn't return anything.

func (*Cacher[C, T]) SetWithTTL added in v1.0.2

func (c *Cacher[C, T]) SetWithTTL(key C, val T, ttl time.Duration)

SetWithTTL is used to set a new key-value pair to the current Cacher instance with a specific TTL. It doesn't return anything. It will expire the key after the input TTL, and TTL specified in this function will override the default TTL of current Cacher instance for this pair specifically.

type CleaningMode added in v1.0.3

type CleaningMode int
const (
	CleaningNone CleaningMode = iota
	CleaningCentral
	CleaningLocal
)

type Duplet

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

Dupley is a special type of PolyKeyer which is used when you want to set exactly 2 parameters as a key to some value. It creates a single key of type string from 2 values, and looks like: "primaryKey.secondaryKey" where dot (.) works as a key separator, primaryKey is the 1st key and set while making a new Duplet, while secondaryKey is provided while creating keys from a duplet.

Note: You can use PolyKeyer in case you want to use more than one extra parameter.

Example
// 2 is number of extra keys we'd use.
// total keys become 3 then
keyer := NewDuplet("chat")

fmt.Println(keyer.New(fmt.Sprint(100291)))

fmt.Println(keyer.New(fmt.Sprint(100292)))
Output:
chat.100291
chat.100292

func NewDuplet

func NewDuplet(primaryKey string) *Duplet

This function creates a new Duplet instance with the provided primary key.

func (*Duplet) New

func (k *Duplet) New(key any) string

It creates a new unity key of type string with 1st key as the primary key of current Duplet and secondary key as the one passed which was passed as an argument to this function.

Example
// 2 is number of extra keys we'd use.
// total keys become 3 then
keyer := NewPolyKeyer("chat", 2)

fmt.Println(keyer.New("public", fmt.Sprint(100291)))

fmt.Println(keyer.New("private", fmt.Sprint(100292)))
Output:
chat.public.100291
chat.private.100292

type NewCacherOpts

type NewCacherOpts struct {
	TimeToLive    time.Duration
	CleanInterval time.Duration
	Revaluate     bool
	CleanerMode   CleaningMode
}

This struct contains the optional arguments which can be filled while creating a new Cacher instance.

Parameters:

TimeToLive (type time.Duration): It allows us to expire a key after a specific time period. Eg: If it is set to 30 seconds, then each key of current Cacher will be expired after 30 seconds of their addition.

CleanInterval (type time.Duration): It is the time of interval between two cleaner windows. A cleaner window is that time frame when all the expired keys will be deleted from our cache mapping. Note: It TTL is set to a finite value and no value is passed to CleanInterval, it'll use a default time interval of 1 day for clean window. Eg: If CleanInterval is set to 1 hour, then cleaner window will be run after every 1 hour, and the expired keys which are present in our cache map will be deleted.

Revaluate (type bool): It allows us to keep keys cached as per their usage frequency. Working: Whenever the keys will be retrieved via (Cacher.Get) method, its expiry will be renewed and this will allow us to keep frequently used keys in the map without expiration.

type PolyKeyer

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

PolyKeyer is a special type of struct which is used when you want to set more than 1 parameter as a key to some value. It creates a single key of type string from multiple values, and looks like: "primaryKey.extraKey1.extraKey2.extraKeyn" where dot (.) works as a key separator, primaryKey is the 1st key and set while making a new PolyKeyer, while extraKeys are provided while creating keys from a polykeyer.

Note: You should use Duplet in case there is only one extra parameter.

Example
// 2 is number of extra keys we'd use.
// total keys become 3 then
keyer := NewPolyKeyer("chat", 2)

fmt.Println(keyer.New("public", fmt.Sprint(100291)))

fmt.Println(keyer.New("private", fmt.Sprint(100292)))
Output:
chat.public.100291
chat.private.100292

func NewPolyKeyer

func NewPolyKeyer(primaryKey string, numExtraKeys int) *PolyKeyer

This function creates a new PolyKeyer instance with the provided primary key and number of extra keys. Eg: If we pass "chat" to primaryKey and 2 to numExtraKeys then this function will create a new PolyKeyer which would create unified key of type string with 3 keys in it.

func (*PolyKeyer) New

func (k *PolyKeyer) New(extraKeys ...string) string

It creates a new unity key of type string with 1st key as the primary key of current PolyKeyer and rest of the keys in the same order as they were passed as an argument.

Example
// 2 is number of extra keys we'd use.
// total keys become 3 then
keyer := NewPolyKeyer("chat", 2)

fmt.Println(keyer.New("public", fmt.Sprint(100291)))

fmt.Println(keyer.New("private", fmt.Sprint(100292)))
Output:
chat.public.100291
chat.private.100292

type SegrigatorFunc

type SegrigatorFunc[T any] func(value T) bool

SegrigatorFunc takes the input as value of current key. Returned boolean is used for segrigation of keys for GetSome function.

Directories

Path Synopsis
examples
multiKey module

Jump to

Keyboard shortcuts

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