Skip to content

onurbaran/easy-cache

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

README.md

Easy-Cache

Easy-Cache is a flexible and efficient caching library written in Go, designed to handle common data structures such as maps, slices, and structs with advanced features like TTL (Time-To-Live), eviction policies, and event-driven invalidation. The library is optimized for performance and supports native caching without the need for JSON serialization, making it ideal for high-performance applications.

Features

  • Native Caching: Supports caching of Go's native data structures (map, slice, struct) without the need for JSON serialization.
  • TTL (Time-To-Live): Automatically expire cache entries after a specified duration.
  • Eviction Policies: Supports Least Recently Used (LRU) and Least Frequently Used (LFU) eviction policies.
  • Event-Driven Invalidation: Invalidate cache entries based on custom events.
  • Sharded Cache: Scale cache horizontally by sharding data across multiple caches.

Installation

To install Easy-Cache, use the following go get command:

go get github.com/onurbaran/easy-cache

Getting Started

Basic Usage

Here is a basic example of how to use Easy-Cache to cache a simple key-value pair:

package main

import (
    "context"
    "fmt"
    "github.com/onurbaran/easy-cache/pkg/cache"
)

func main() {
    // Create a new cache with default configuration
    config := cache.DefaultConfig()
    c := cache.NewCache(config)

    // Set a value in the cache
    ctx := context.Background()
    c.Set(ctx, "key1", "value1", 1, "default")

    // Get the value from the cache
    data, found, _ := c.Get(ctx, "key1")
    if found {
        fmt.Println("Found:", data)
    } else {
        fmt.Println("Not found")
    }

    // Delete the value from the cache
    c.Delete(ctx, "key1")

    // Try to get the value again after deletion
    data, found, _ = c.Get(ctx, "key1")
    if found {
        fmt.Println("Found:", data)
    } else {
        fmt.Println("Not found after deletion")
    }
}

Caching Maps

Easy-Cache supports caching map[string]interface{} natively:

package main

import (
    "context"
    "fmt"
    "github.com/onurbaran/easy-cache/pkg/cache"
)

func main() {
    // Create a MapCache
    config := cache.DefaultConfig()
    mapCache := cache.NewMapCache(config)

    // Cache a map
    ctx := context.Background()
    exampleMap := map[string]interface{}{"key1": "value1", "key2": "value2"}
    mapCache.Set(ctx, "example", exampleMap)

    // Retrieve the map from the cache
    data, found, err := mapCache.Get(ctx, "example")
    if err != nil {
        fmt.Println("Error getting map from cache:", err)
        return
    }
    if found {
        fmt.Printf("Found map in cache: %+v\n", data)
    } else {
        fmt.Println("Map not found in cache")
    }
}

Caching Slices

You can also cache []interface{} slices natively:

package main

import (
    "context"
    "fmt"
    "github.com/onurbaran/easy-cache/pkg/cache"
)

func main() {
    // Create a SliceCache
    config := cache.DefaultConfig()
    sliceCache := cache.NewSliceCache(config)

    // Cache a slice
    ctx := context.Background()
    exampleSlice := []interface{}{"value1", "value2", "value3"}
    sliceCache.Set(ctx, "exampleSlice", exampleSlice)

    // Retrieve the slice from the cache
    data, found, err := sliceCache.Get(ctx, "exampleSlice")
    if err != nil {
        fmt.Println("Error getting slice from cache:", err)
        return
    }
    if found {
        fmt.Printf("Found slice in cache: %+v\n", data)
    } else {
        fmt.Println("Slice not found in cache")
    }
}

Caching Structs with TTL

Structs can be cached with a TTL (Time-To-Live) to automatically expire after a certain period:

package main

import (
    "context"
    "fmt"
    "time"
    "github.com/onurbaran/easy-cache/pkg/cache"
)

type User struct {
    Name  string
    Email string
    Age   int
}

func main() {
    // Create a StructCache with a 5-second TTL
    config := cache.DefaultConfig()
    config.BaseTTL = 5 * time.Second
    structCache := cache.NewStructCache(config)

    // Cache a struct
    ctx := context.Background()
    user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
    err := structCache.Set(ctx, "user1", user)
    if err != nil {
        fmt.Println("Error setting struct in cache:", err)
        return
    }

    // Retrieve the struct from the cache
    data, found, _ := structCache.Get(ctx, "user1")
    if found {
        fmt.Printf("Initially found struct in cache: %+v\n", data.(User))
    } else {
        fmt.Println("Struct not found in cache initially")
    }

    // Wait for the TTL to expire
    time.Sleep(6 * time.Second)

    // Check the cache after TTL expiration
    data, found, _ = structCache.Get(ctx, "user1")
    if !found {
        fmt.Println("Struct has expired and is no longer in cache")
    } else {
        fmt.Printf("Struct still found in cache after TTL: %+v\n", data.(User))
    }
}

Event-Driven Invalidation

Easy-Cache supports event-driven cache invalidation, allowing you to remove or update cache entries based on custom events.

package main

import (
    "context"
    "fmt"
    "github.com/onurbaran/easy-cache/pkg/cache"
    "github.com/onurbaran/easy-cache/pkg/event"
)

type User struct {
    Name  string
    Email string
    Age   int
}

type InvalidateEventListener struct {
    cache *cache.StructCache
}

func (l *InvalidateEventListener) OnEvent(e event.Event) {
    ctx := context.Background()
    key := e.Data.(string)
    l.cache.Delete(ctx, key)
    fmt.Println("Invalidated struct with key:", key)
}

func main() {
    // Create an Event Manager and attach it to the cache
    eventManager := event.NewEventManager()
    config := cache.DefaultConfig()
    config.EventManager = eventManager
    structCache := cache.NewStructCache(config)

    // Cache a struct
    ctx := context.Background()
    user := User{Name: "Alice", Email: "alice@example.com", Age: 30}
    structCache.Set(ctx, "user1", user)

    // Register an event listener
    listener := &InvalidateEventListener{cache: structCache}
    eventManager.RegisterListener("invalidateUser", listener)

    // Trigger the invalidation event
    eventManager.TriggerEvent(event.Event{Name: "invalidateUser", Data: "user1"})

    // Check the cache after event
    data, found, _ := structCache.Get(ctx, "user1")
    if !found {
        fmt.Println("Struct successfully invalidated and deleted from cache")
    } else {
        fmt.Println("Struct still found in cache:", data)
    }
}

Advanced Features

Eviction Policies

Easy-Cache supports LRU (Least Recently Used) and LFU (Least Frequently Used) eviction policies to manage cache size.

LRU Eviction

config := cache.DefaultConfig()
config.EvictionPolicy = &cache.LRUEviction{}

LFU Eviction

config := cache.DefaultConfig()
config.EvictionPolicy = &cache.LFUEviction{}

Sharded Cache

Easy-Cache allows you to shard your cache across multiple instances for improved scalability.

config := cache.DefaultConfig()
config.NumShards = 8
shardedCache := cache.NewShardedCache(config)

TODO

  • Distributed cache
  • Gossip Protocol Implementation
  • Avro Serialization/Deserialization
  • Adaptive TTL Management

Conclusion

Easy-Cache is a flexible caching library designed to handle various data structures efficiently in Go. With features like native caching, TTL, eviction policies, and event-driven invalidation, it provides a solution for caching in high-performance applications.

Feel free to explore the examples provided and integrate Easy-Cache into your Go projects. For more information, check out the source code and additional documentation.

License

This project is licensed under the MIT License.


About

easy-cache is a high-performance, modular, and flexible caching library for Go

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages