fcache

package module
v0.2.0 Latest Latest
Warning

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

Go to latest
Published: Jul 28, 2020 License: MIT Imports: 7 Imported by: 0

README

go-fcache

Go Report Card codecov PkgGoDev Build Status LICENSE

go-fcache is a file cache library implemented by pure Go. This package provides simple interface for file caching which allows you to peform some operations to these file caches.

Motivation

There are many existing and awesome caching libraries implemented in Go, such as go-cache, bigCache, redis-cache ...etc.

But most of them stored data in memory instead of a file. Some of them do not handle the upper bound of what they can store. Furthermore, cache replacement mechanism is also hide from user, so we cannot substitute it easily. And the most important thing is that they can merely guarantee that not to evict the caches which are used by others. This might leads severe errors when developing a storage related application.

Due to the reasons above, go-fcache comes up with focusing file cache only, and guaranteens that not to evict the referenced cache item from cache volume.

Features

  • Using Key-Value store as backend
  • Support upper bound of a cache volume
  • Only evict file caches when it needs space to store new caches.
  • Ensures that not to evict file caches which are being referenced.
  • Build-in common cache replacement algorithms
  • Support concurrent usage
  • Simple interface with high scalabilities
  • Cache replacement alogrithm and storing backend are customizable

Built-in cache replacement algorithms

  • FIFO (First-in-first-out)
  • LIFO (Last-in-first-out)
  • LRU (Least Recently Used)
  • MRU (Most Recently Used)
  • RR (Random Replacement)

Built-in backend

Customization

How to customize a cache replacement algorithm

Every object which implements cache.Policy interface could be used as a cache replacement algorithm.

import "github.com/meowdada/go-fcache/cache"

type Policy interface {
	Emit(db cache.DB) (cache.Item, error)
}

And cache.DB provides following APIs:

type DB interface {
	Iter(iterCb func(k string, v Item) error) error
	Put(key string, size int64) error
	Get(key string) (Item, error)
	Remove(key string) error
	IncrRef(keys ...string) error
	DecrRef(keys ...string) error
	Close() error
}

In most cases, only DB.Iter needs to be invoked to implement a cache replacement algorithm.

How to customize a storing backend.

Every object which implements backend.Store interface could be refered as a storing backend.

type Store interface {
	Put(k, v []byte) error
	Get(k []byte) (v []byte, e error)
	Remove(k []byte) error
	Iter(iterCb func(k, v []byte) error) error
	Close() error
}

Note that you must return cache.ErrNoSuchKey when cache is missing, or the functionalities might break up.

Examples

Simple cache manager

Creates a file cache manager to manages file caches with limited cache volume.


import (
	"os"

	"github.com/dustin/go-humanize"
	"github.com/meowdada/go-fcache"
	"github.com/meowdada/go-fcache/backend/gomap"
	"github.com/meowdada/go-fcache/codec"
	"github.com/meowdada/go-fcache/policy"
)

// Note that this is just a example not best practice. Please
// do not use it directly.
func main() {
	// Create a cache manager to manage file caches.
	mgr := fcache.New(fcache.Options{
		Capacity:     int64(2 * humanize.GiByte),
		Codec:        codec.Gob{},
		Backend:      gomap.New(),
		CachePolicy:  policy.LRU(),
		RetryOptions: nil,
	})

	// Put a 500MiB file cache into the manager.
	err := mgr.Set("/path/to/file", int64(500*humanize.MiByte))
	if err != nil {
		panic(err)
	}

	// Get the file cache from the manager.
	item, err := mgr.Get("/path/to/file")
	if err != nil {
		panic(err)
	}

	// Get the file reader and use it as you want.
	f, err := os.Open(item.Path)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	// Your code logic...
}
Cache item if miss

In this example we showed that how to set a missing cache immediately after finding it missed in the cache volume.

package main

import (
	"os"

	"github.com/meowdada/go-fcache"
	"github.com/meowdada/go-fcache/backend/gomap"
	"github.com/meowdada/go-fcache/cache"
	"github.com/meowdada/go-fcache/codec"
	"github.com/meowdada/go-fcache/policy"
)

// Note that this is just a example not best practice. Please
// do not use it directly.
func main() {
	// Create a cache manager to manage file caches.
	mgr := fcache.New(fcache.Options{
		Capacity:     int64(1000),
		Codec:        codec.Gob{},
		Backend:      gomap.New(),
		CachePolicy:  policy.LRU(),
		RetryOptions: nil,
	})

	// onceHandler will be invoked when try getting a missing cache item
	// by calling Once.
	onceHandler := func(
		preconditionChecker func(item cache.Item) error,
		putCacheFn func(path string, size int64) error,
		rollback func(path string) error,
	) (item cache.Item, err error) {
		// Create a psudo cache item first.
		item = cache.New(1000, "file1.tmp", 200)

		// Check if the cache item is valid or not.
		err = preconditionChecker(item)
		if err != nil {
			return item, err
		}

		// Put the psudo cache item into the cache manager first to ensure
		// there is enough space to insert this cache.
		err = putCacheFn("file1.tmp", 200)
		if err != nil {
			return item, err
		}

		// Prepare to rollback if download file failed.
		defer func() {
			if err != nil {
				rollback("file1.tmp")
			}
		}()

		// Then, download it from the cloud.
		err = downloadFileFromS3()
		return item, err
	}

	item, err := mgr.Once("file1.tmp", onceHandler)
	if err != nil {
		panic(err)
	}

	// Get the file reader and use it as you want.
	f, err := os.Open(item.Path)
	if err != nil {
		panic(err)
	}
	defer f.Close()

	// Your code logic...
}

// Download a file from s3.
func downloadFileFromS3() error {
	// Your code logic...
	return nil
}

Documentation

Overview

Package fcache provides utilities to manage file caches with limited local cache volume.

Index

Constants

This section is empty.

Variables

View Source
var ErrCacheMiss = errors.New("cache miss")

ErrCacheMiss raises when try getting an unexist record.

View Source
var ErrCacheTooLarge = errors.New("cache item is too large")

ErrCacheTooLarge raises when the inserting cache item is too large.

View Source
var ErrDupKey = errors.New("cache key duplicates")

ErrDupKey raises when try inserting duplicated key.

Functions

This section is empty.

Types

type Manager

type Manager struct {
	// contains filtered or unexported fields
}

Manager manages transactions of file caches.

func New

func New(opts Options) *Manager

New creates an instance of file cache manager.

func (*Manager) Cap

func (mgr *Manager) Cap() int64

Cap returns the capacity of the cache volume.

func (*Manager) Get

func (mgr *Manager) Get(key string) (item cache.Item, err error)

Get gets the cache item record from the cache volume. If it failed to find the cache item. It returns a zero valued Item and error as ErrCacheMiss.

func (*Manager) Once added in v0.1.0

func (mgr *Manager) Once(path string, createFn OnceHandler) (item cache.Item, err error)

Once try get a cache item from the cache volume first. If the cache item has been found, it will return it immediately. If not, it will invoke the given lambda createFn to create the file cache, then insert it to the cache volume. And finally, return the inserted cache item as result.

func (*Manager) Register

func (mgr *Manager) Register(keys ...string)

Register register file caches with their key and increment their reference count. With normal cache replacement policy, a referenced file cache will not be pick as a victim for cache replacement. If you no longer need these files, Unregister it if you have once registered them. It is also possible to register a key which does not present so far.

func (*Manager) Set

func (mgr *Manager) Set(key string, size int64) error

Set sets a file as a cache record into the manager. If the cache volume is full, it will try emit some cache items to cleanup some cache space then insert this one. It is possible that no cache items could be emitted at the moment which leads to this operation be unavailable. To prevent waiting deadlock, by default we use timeout setting and retry mechanism internally to prevent this condition.

func (*Manager) Unregister

func (mgr *Manager) Unregister(keys ...string)

Unregister unregister file caches with their key and decrement their reference count. Any file caches with no reference count unregistered by this function will remains the same status.

type OnceHandler added in v0.1.0

type OnceHandler func(
	preconditionCheck func(item cache.Item) error,
	putCacheFn func(path string, size int64) error,
	rollback func(path string) error,
) (cache.Item, error)

OnceHandler is a handler for once method.

type Options added in v0.1.0

type Options struct {
	Capacity     int64
	Codec        codec.Codec
	Backend      backend.Store
	CachePolicy  policy.Policy
	RetryOptions []retry.Option
}

Options configures file cache manager.

Directories

Path Synopsis
examples
pkg

Jump to

Keyboard shortcuts

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