Skip to content

Commit

Permalink
feature: update readme and licenses
Browse files Browse the repository at this point in the history
  • Loading branch information
NonsoAmadi10 committed Aug 12, 2024
1 parent 8505d83 commit 83cbe8b
Show file tree
Hide file tree
Showing 7 changed files with 128 additions and 7 deletions.
77 changes: 77 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,80 @@
An in-memory cache system in Go that supports expirable cache entries and various cache eviction policies including Least Frequently Used (LFU), Least Recently Used (LRU), and Adaptive Replacement Cache (ARC).

[![zwis library workflow](https://github.com/NonsoAmadi10/zwis/actions/workflows/main.yaml/badge.svg)](https://github.com/NonsoAmadi10/zwis/actions/workflows/main.yaml)


## Installation
```bash
go get github.com/NonsoAmadi10/zwis
```

## Usage

Here's a quick example of how to use the cache:

```go
package main

import (
"context"
"fmt"
"time"

"github.com/NonsoAmadi10/zwis/zwis"
)

func main() {
ctx := context.Background()

// Create an LRU cache
lruCache, err := zwis.NewCache(cache.LRUCacheType, 100)
if err != nil {
panic(err)
}

// Set a value
lruCache.Set(ctx, "key1", "value1", 5*time.Second)

// Get a value
if value, ok := lruCache.Get(ctx, "key1"); ok {
fmt.Printf("key1: %v\n", value)
}

// Delete a value
lruCache.Delete(ctx, "key1")

// Clear the cache
lruCache.Clear(ctx)
}
```

## Available Cache Types

* MemoryCache: Simple in-memory cache
* LRUCache: Least Recently Used cache
* LFUCache: Least Frequently Used cache
* ARCCache: Adaptive Replacement Cache
* DiskStore: Implementing a Simple Disk-Backed Cache (coming soon)

## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.

This project structure provides a solid foundation for a Go cache library. It demonstrates several important Go concepts and best practices:

1. Interface-based design
2. Concurrency handling with mutexes
3. Use of context for cancelation and timeouts
4. Proper error handling
5. Package organization
6. Unit testing
7. Documentation

Areas for potential improvement or expansion:

1. Implement a cache using a diskstore
2. Add benchmarking tests to compare performance of different cache types
3. Implement cache statistics (hit rate, miss rate, etc.)
4. Add support for cache serialization/deserialization for persistence
5. Implement a distributed cache using Redis or similar

Remember, this is a learning exercise, so feel free to experiment with different approaches and optimizations as you build out this library. Good luck with your project!
2 changes: 1 addition & 1 deletion tests/arc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ func TestARCCache(t *testing.T) {

// Test Clear
cache.Set(ctx, "key7", "value7", 0)
cache.Clear(ctx)
cache.Flush(ctx)
if _, ok := cache.Get(ctx, "key7"); ok {
t.Error("Cache should be empty after Clear")
}
Expand Down
2 changes: 1 addition & 1 deletion zwis/arc.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ func (c *ARCCache) Delete(ctx context.Context, key string) error {
}

// Clear removes all items from the cache.
func (c *ARCCache) Clear(ctx context.Context) error {
func (c *ARCCache) Flush(ctx context.Context) error {
c.mu.Lock()
defer c.mu.Unlock()

Expand Down
29 changes: 29 additions & 0 deletions zwis/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package zwis

import (
"fmt"
)

type CacheType string

const (
MemoryCacheType CacheType = "memory"
LRUCacheType CacheType = "lru"
LFUCacheType CacheType = "lfu"
ARCCacheType CacheType = "arc"
)

func NewCache(cacheType CacheType, capacity int) (Cache, error) {
switch cacheType {
case MemoryCacheType:
return NewMemoryCache(), nil
case LRUCacheType:
return NewLRUCache(capacity), nil
case LFUCacheType:
return NewLFUCache(capacity), nil
case ARCCacheType:
return NewARCCache(capacity), nil
default:
return nil, fmt.Errorf("unknown cache type: %s", cacheType)
}
}
14 changes: 10 additions & 4 deletions zwis/lru.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func NewLRUCache(capacity int) *LRUCache {
}
}

func (lru *LRUCache) Get(ctx context.Context, key interface{}) (interface{}, bool) {
func (lru *LRUCache) Get(ctx context.Context, key string) (interface{}, bool) {
lru.mutex.RLock()
elem, ok := lru.cache[key]
lru.mutex.RUnlock()
Expand All @@ -50,7 +50,7 @@ func (lru *LRUCache) Get(ctx context.Context, key interface{}) (interface{}, boo
return entry.value, true
}

func (lru *LRUCache) Set(ctx context.Context, key, value interface{}, ttl time.Duration) {
func (lru *LRUCache) Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error {
lru.mutex.Lock()
defer lru.mutex.Unlock()

Expand All @@ -70,23 +70,29 @@ func (lru *LRUCache) Set(ctx context.Context, key, value interface{}, ttl time.D
elem := lru.list.PushFront(&entry{key, value, expiration})
lru.cache[key] = elem
}

return nil
}

func (lru *LRUCache) Delete(ctx context.Context, key interface{}) {
func (lru *LRUCache) Delete(ctx context.Context, key string) error {
lru.mutex.Lock()
defer lru.mutex.Unlock()

if elem, ok := lru.cache[key]; ok {
lru.removeElement(elem)
}

return nil
}

func (lru *LRUCache) Clear(ctx context.Context) {
func (lru *LRUCache) Flush(ctx context.Context) error {
lru.mutex.Lock()
defer lru.mutex.Unlock()

lru.list.Init()
lru.cache = make(map[interface{}]*list.Element)

return nil
}

func (lru *LRUCache) removeOldest() {
Expand Down
2 changes: 1 addition & 1 deletion zwis/memory.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ func (c *MemoryCache) Delete(ctx context.Context, key string) error {
return nil
}

func (c *MemoryCache) Clear(ctx context.Context) error {
func (c *MemoryCache) Flush(ctx context.Context) error {
c.mu.Lock()
defer c.mu.Unlock()

Expand Down
9 changes: 9 additions & 0 deletions zwis/zwis.go
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
// Package zwis provides various cache implementations including in-memory,
// LRU (Least Recently Used), LFU (Least Frequently Used), and ARC (Adaptive Replacement Cache).
package zwis

import (
Expand All @@ -15,9 +17,16 @@ Flush()
*/

// Cache interface defines the methods that all cache implementations must support.
type Cache interface {
// Set adds an item to the cache, replacing any existing item. If the TTL
// is 0, the item never expires.
Set(ctx context.Context, key string, value interface{}, ttl time.Duration) error
// Get retrieves an item from the cache. It returns the item and a boolean
// indicating whether the key was found.
Get(ctx context.Context, key string) (interface{}, bool)
// Delete removes the provided key from the cache.
Delete(ctx context.Context, key string) error
// Clear removes all items from the cache.
Flush(ctx context.Context) error
}

0 comments on commit 83cbe8b

Please sign in to comment.