From 2f1f4c4838228b8c71bb59e26232ea54338e6fbb Mon Sep 17 00:00:00 2001 From: parMaster Date: Mon, 10 Jul 2023 16:06:42 +0300 Subject: [PATCH] Readme and examples --- README.md | 137 ++++++++++++++++++++++++++++++++++++++++ examples/example.go | 44 +++++++++++++ examples/hit_or_miss.go | 32 ++++++++++ 3 files changed, 213 insertions(+) create mode 100644 README.md create mode 100644 examples/example.go create mode 100644 examples/hit_or_miss.go diff --git a/README.md b/README.md new file mode 100644 index 0000000..08a97ef --- /dev/null +++ b/README.md @@ -0,0 +1,137 @@ +# mcache + +`mcache` is a simple and thread-safe in-memory cache library for Go. + +## Features + +- Thread-safe cache operations +- Set key-value pairs with optional expiration time +- Get values by key +- Check if a key exists +- Delete key-value pairs +- Clear the entire cache +- Cleanup expired key-value pairs + +## Installation + +Use `go get` to install the package: + +```shell +go get github.com/parMaster/mcache +``` + +## Usage + +Import the `mcache` package in your Go code: + +```go +import "github.com/parMaster/mcache" +``` + +Create a new cache instance using the `NewCache` constructor: + +```go +cache := mcache.NewCache() +``` + +### Set + +Set a key-value pair in the cache. The key must be a string, and the value can be any type that implements the `interface{}` interface, ttl is int64 value in seconds: + +```go +err := cache.Set("key", "value", 0) +if err != nil { + // handle error +} +``` + +If the key already exists and is not expired, an error `mcache.ErrKeyExists` will be returned. If the key exists but is expired, the value will be updated. + +You can also set a key-value pair with an expiration time (in seconds): + +```go +err := cache.Set("key", "value", 60) +if err != nil { + // handle error +} +``` + +The value will automatically expire after the specified duration. + +_Note that int64 is used instead of time.Duration for the expiration time. This choise is deliberate to simplify the API. It can be changed in the future, I can break the API but only in the next major version._ + +### Get + +Retrieve a value from the cache by key: + +```go +value, err := cache.Get("key") +if err != nil { + // handle error +} +``` + +If the key does not exist, an error `mcache.ErrKeyNotFound` will be returned. If the key exists but is expired, an error `mcache.ErrExpired` will be returned, and the key-value pair will be deleted. + +Either error or value could be checked to determine if the key exists. + +### Has + +Check if a key exists in the cache: + +```go +exists, err := cache.Has("key") +if err != nil { + // handle error +} + +if exists { + // key exists +} else { + // key does not exist +} +``` + +If the key exists but is expired, an error `mcache.ErrExpired` will be returned, and the key-value pair will be deleted. + +### Delete + +Delete a key-value pair from the cache: + +```go +err := cache.Del("key") +if err != nil { + // handle error +} +``` + +### Clear + +Clear the entire cache: + +```go +err := cache.Clear() +if err != nil { + // handle error +} +``` + +### Cleanup + +Cleanup expired key-value pairs in the cache. You can call this method periodically to remove expired key-value pairs from the cache: + +```go +cache.Cleanup() +``` + +## Examples + +See the [examples](https://github.com/parMaster/mcache/examples) directory for more examples. + +## Contributing + +Contributions are welcome! If you find any issues or have suggestions for improvements, please open an issue or submit a pull request. + +## License + +This project is licensed under the [GNU GPLv3](https://choosealicense.com/licenses/gpl-3.0/) license. diff --git a/examples/example.go b/examples/example.go new file mode 100644 index 0000000..5308374 --- /dev/null +++ b/examples/example.go @@ -0,0 +1,44 @@ +package main + +import ( + "fmt" + "time" + + "github.com/parMaster/mcache" +) + +func demo() { + + fmt.Println("\r\n Demo 1:") + fmt.Println("------------------------------------------------------------") + + cache := mcache.NewCache() + + cache.Set("save indefinitely", "value without expiration", 0) // set value without expiration + cache.Set("save for 1 second", "value will expire in 1 second", 1) // set value with expiration in 1 second + + exists, err := cache.Has("no such key") + // either exists or error can be checked + if err != nil { + // possible errors: + // mcache.ErrKeyNotFound + // mcache.ErrExpired + fmt.Println(err) + } + if !exists { + fmt.Println("key doen't exist or expired") + } + + v, _ := cache.Get("save indefinitely") + fmt.Println(v) + + time.Sleep(1 * time.Second) + v, _ = cache.Get("save for 1 second") + fmt.Println(v) // because key expired + +} + +func main() { + demo() + demo_hit_or_miss() +} diff --git a/examples/hit_or_miss.go b/examples/hit_or_miss.go new file mode 100644 index 0000000..d4c682d --- /dev/null +++ b/examples/hit_or_miss.go @@ -0,0 +1,32 @@ +package main + +import ( + "fmt" + "time" + + "github.com/parMaster/mcache" +) + +func expensive_func() interface{} { + time.Sleep(1 * time.Second) + return "expensive result" +} + +func demo_hit_or_miss() { + fmt.Println("\r\n Hit or Miss:") + fmt.Println("------------------------------------------------------------") + + cache := mcache.NewCache() + // expensive_func will be called only once + // because result will be saved in cache + for i := 0; i < 10; i++ { + v, err := cache.Get("expensive value") + if err != nil { + fmt.Println("cache miss, calling expensive_func") + v = expensive_func() + cache.Set("expensive value", v, 0) + continue + } + fmt.Println("cache hit - " + v.(string)) + } +}