mirror of https://github.com/aldy505/cheapcash.git
commit
5ee43946ea
12
README.md
12
README.md
|
@ -4,6 +4,12 @@
|
||||||
|
|
||||||
SSD is cheap. Why don't we use it for caching?
|
SSD is cheap. Why don't we use it for caching?
|
||||||
|
|
||||||
|
A simple library implementing filesystem I/O as a cache. Should be must useful when used again a Solid State Drive
|
||||||
|
for maximum speed and to handle good amount of concurrent read/write.
|
||||||
|
|
||||||
|
The API itself is also pretty simple considering I don't want this to be a full-blown caching library like Redis,
|
||||||
|
I just want it to be simple like Bigcache or similar caching library.
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
```go
|
```go
|
||||||
|
@ -55,3 +61,9 @@ func main() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See Godoc documentation (link above, beneath the title) for more complete documentation of the package.
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
[MIT](./LICENSE)
|
||||||
|
|
13
append.go
13
append.go
|
@ -2,6 +2,19 @@ package cheapcash
|
||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
|
||||||
|
// Directly append a value into an existing key.
|
||||||
|
// If a key doesn't exists, it will return an error
|
||||||
|
// with a type of ErrNotExists.
|
||||||
|
//
|
||||||
|
// c := cheapcash.Default()
|
||||||
|
// err := c.Append("users", []byte("Someone\n"))
|
||||||
|
// if err != nil {
|
||||||
|
// if errors.Is(err, cheapcash.ErrNotExists) {
|
||||||
|
// // Handle if file does not exists!
|
||||||
|
// }
|
||||||
|
// // Handle any other errors
|
||||||
|
// }
|
||||||
|
//
|
||||||
func (c *Cache) Append(key string, value []byte) error {
|
func (c *Cache) Append(key string, value []byte) error {
|
||||||
check, err := c.Exists(c.Path + key)
|
check, err := c.Exists(c.Path + key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
27
cheapcash.go
27
cheapcash.go
|
@ -17,13 +17,40 @@ var ErrInvalidPath = errors.New("path supplied is invalid")
|
||||||
var ErrDiskFull = errors.New("there was no space left on the device")
|
var ErrDiskFull = errors.New("there was no space left on the device")
|
||||||
var ErrExists = errors.New("key already exists")
|
var ErrExists = errors.New("key already exists")
|
||||||
|
|
||||||
|
// Creates default Cheapcash instance which defaults
|
||||||
|
// the corresponding cache path to /tmp/cheapcash.
|
||||||
|
//
|
||||||
|
// The caveat of using this one is this will be most likely
|
||||||
|
// only compatible with UNIX-like filesystem.
|
||||||
|
// Windows devices will most likely happen to have
|
||||||
|
// an error of the invalid path.
|
||||||
|
//
|
||||||
|
// This returns a Cheapcash instance, which method
|
||||||
|
// ('Append', 'Exists', 'Write', 'Read') you can do
|
||||||
|
// by just specifying the key, without supplying the
|
||||||
|
// full path of the cached file.
|
||||||
func Default() *Cache {
|
func Default() *Cache {
|
||||||
return &Cache{
|
return &Cache{
|
||||||
Path: "/tmp/cheapcash/",
|
Path: "/tmp/cheapcash/",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Creates a new Cheapcash instance with the given
|
||||||
|
// path from the argument provided.
|
||||||
|
//
|
||||||
|
// If path is empty (or an empty string), it will panic
|
||||||
|
// with ErrInvalidPath error.
|
||||||
|
//
|
||||||
|
// The path provided might have '/' as the ending, so
|
||||||
|
// these are valid and will return the same path:
|
||||||
|
//
|
||||||
|
// New("/tmp/box")
|
||||||
|
// New("/tmp/box/")
|
||||||
func New(path string) *Cache {
|
func New(path string) *Cache {
|
||||||
|
if path == "" {
|
||||||
|
panic(ErrInvalidPath)
|
||||||
|
}
|
||||||
|
|
||||||
if !strings.HasSuffix(path, "/") {
|
if !strings.HasSuffix(path, "/") {
|
||||||
path += "/"
|
path += "/"
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package cheapcash_test
|
package cheapcash_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"errors"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
@ -29,6 +30,19 @@ func TestNew(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestNew_InvalidPath(t *testing.T) {
|
||||||
|
defer func(){
|
||||||
|
if e := recover().(error); e != nil {
|
||||||
|
if !errors.Is(e, cheapcash.ErrInvalidPath) {
|
||||||
|
t.Error("expected ErrInvalidPath, got:", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
_ = cheapcash.New("")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func removeDirIfExists(path string) {
|
func removeDirIfExists(path string) {
|
||||||
dir, err := os.Stat(path)
|
dir, err := os.Stat(path)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
|
7
check.go
7
check.go
|
@ -31,6 +31,13 @@ func (c *Cache) Exists(key string) (bool, error) {
|
||||||
return true, nil
|
return true, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Will validate the existance of a directory.
|
||||||
|
// If the directory (including its' children) doesn't
|
||||||
|
// exists, it will create the corresponding directory
|
||||||
|
// tree from the given directory path.
|
||||||
|
//
|
||||||
|
// If the directory already exists, it will return
|
||||||
|
// a nil value.
|
||||||
func checkDir(path string) error {
|
func checkDir(path string) error {
|
||||||
// Remove / from path
|
// Remove / from path
|
||||||
path = strings.TrimSuffix(path, "/")
|
path = strings.TrimSuffix(path, "/")
|
||||||
|
|
10
delete.go
10
delete.go
|
@ -2,6 +2,16 @@ package cheapcash
|
||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
|
||||||
|
// Delete a key from the cache directory.
|
||||||
|
// And of course would return an error of ErrNotExists
|
||||||
|
// if the key doesn't exists.
|
||||||
|
//
|
||||||
|
// c := cheapcash.Default()
|
||||||
|
// err := c.Write("users", []byte("Someone\n"))
|
||||||
|
// // Handle error here
|
||||||
|
// err = c.Delete("users")
|
||||||
|
// // Handle error here
|
||||||
|
//
|
||||||
func (c *Cache) Delete(key string) error {
|
func (c *Cache) Delete(key string) error {
|
||||||
check, err := c.Exists(c.Path + key)
|
check, err := c.Exists(c.Path + key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
11
reader.go
11
reader.go
|
@ -5,6 +5,17 @@ import (
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Read the value of a given key.
|
||||||
|
// Will return an error of ErrNotExists if the given
|
||||||
|
// key does not exists.
|
||||||
|
//
|
||||||
|
// c := cheapcash.Default()
|
||||||
|
// res, err := c.Read("users")
|
||||||
|
// if err != nil {
|
||||||
|
// // handle your error here!
|
||||||
|
// }
|
||||||
|
// log.Println(string(res))
|
||||||
|
//
|
||||||
func (c *Cache) Read(key string) ([]byte, error) {
|
func (c *Cache) Read(key string) ([]byte, error) {
|
||||||
check, err := c.Exists(c.Path + key)
|
check, err := c.Exists(c.Path + key)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
11
rename.go
11
rename.go
|
@ -2,6 +2,17 @@ package cheapcash
|
||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
|
||||||
|
// Rename a key. It's that simple.
|
||||||
|
// The contents of the cache stays the same, but the key
|
||||||
|
// is renamed.
|
||||||
|
//
|
||||||
|
// It will return 2 different error in case of:
|
||||||
|
//
|
||||||
|
// 1. If the old key (first argument parameter) doesn't exists,
|
||||||
|
// it will return an error of ErrNotExists
|
||||||
|
//
|
||||||
|
// 2. If the new key (second argument parameter) already exists,
|
||||||
|
// it will return an error of ErrExists
|
||||||
func (c *Cache) Rename(old, new string) error {
|
func (c *Cache) Rename(old, new string) error {
|
||||||
err := checkDir(sanitizePath(c.Path))
|
err := checkDir(sanitizePath(c.Path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -7,6 +7,9 @@ type restriction struct {
|
||||||
ReplaceWith string
|
ReplaceWith string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sanitize path that is a valid string when the user
|
||||||
|
// submitted it, but it's invalid when it's written
|
||||||
|
// as a file name on local filesystem.
|
||||||
func sanitizePath(path string) string {
|
func sanitizePath(path string) string {
|
||||||
restricted := []restriction{
|
restricted := []restriction{
|
||||||
{Key: " ", ReplaceWith: "_s_"},
|
{Key: " ", ReplaceWith: "_s_"},
|
||||||
|
|
11
writer.go
11
writer.go
|
@ -2,6 +2,17 @@ package cheapcash
|
||||||
|
|
||||||
import "os"
|
import "os"
|
||||||
|
|
||||||
|
// Write a key with a value.
|
||||||
|
// If the key already exists in the first place, it will
|
||||||
|
// delete the existing key and replace it with the new
|
||||||
|
// value.
|
||||||
|
//
|
||||||
|
// c := cheapcash.Default()
|
||||||
|
// err := c.Write("users", []byte("Someone\n"))
|
||||||
|
// if err != nil {
|
||||||
|
// // handle your error
|
||||||
|
// }
|
||||||
|
//
|
||||||
func (c *Cache) Write(key string, value []byte) error {
|
func (c *Cache) Write(key string, value []byte) error {
|
||||||
err := checkDir(sanitizePath(c.Path))
|
err := checkDir(sanitizePath(c.Path))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
Loading…
Reference in New Issue