easy-cache

module
v0.0.0-...-a80d2e7 Latest Latest
Warning

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

Go to latest
Published: Aug 19, 2024 License: MIT

README

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.


Directories

Path Synopsis
pkg

Jump to

Keyboard shortcuts

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