Golang: moje Supercache…

Teda ne celá, ale plně funkční nástřel, včetně zamykání položek pro čtení a zápis. A nutno dodat, že nejde jen o obyčejnou cache, ale a keš keší.

Kešovat asi není moc složité, ale tohle jsem už na netu nenašel. Jedná se o univerzální jednu jedinou datovou strukturu, která umožňuje udžovat separátně jednotlivé keše. Díky tomu můžete nad jednotlivými kešemi provádět základní operace Get a Set, ale díky tomu, že jde o jedinou strukturu, pak nad ní jdou provádět agregované funkce, jako je například hledání napříč všemi cachemi.

package main

import (
	"fmt"
	"sync"
)

type data struct {
	mux   sync.Mutex
	name  string
	cache map[string]string
}

func (d *data) Set(key, value string) {
	d.mux.Lock()
	defer d.mux.Unlock()

	d.cache[key] = value

}

func (d *data) Get(key string) (string, bool) {
	d.mux.Lock()
	defer d.mux.Unlock()

	value, ok := d.cache[key]
	return value, ok
}

// Supercache is more than one cahce...
type Supercache map[string]*data

// Create new chache in Supercache
func (sc Supercache) Create(name string) error {
	if _, ok := sc[name]; ok {
		return fmt.Errorf("%s uz existuje", name)
	}
	sc[name] = &data{
		cache: make(map[string]string),
		name:  name,
	}

	return nil
}

// Get value by key from subcache in Supercache
func (sc Supercache) Get(name, key string) (string, bool) {
	if _, ok := sc[name]; ok {
		value, ok := sc[name].Get(key)
		return value, ok
	}
	return "", false
}

// Set value for key in subchace in Supercache
func (sc Supercache) Set(name, key, value string) error {
	if _, ok := sc[name]; !ok {
		return fmt.Errorf("cache %s not exist", name)
	}

	sc[name].Set(key, value)
	return nil
}

// Len return num of keys in subcache
func (sc Supercache) Len(name string) int {
	if _, ok := sc[name]; !ok {
		return 0
	}

	return len(sc[name].cache)
}

// Delete subcache from Supercache
func (sc Supercache) Delete(name string) bool {
	if _, ok := sc[name]; !ok {
		return false
	}
	delete(sc, name)
	return true
}

// FindAll key in all subcaches in Supercache
func (sc Supercache) FindAll(key string) map[string]string {
	res := make(map[string]string)

	for _, name := range sc {
		if val, ok := name.cache[key]; ok {
			res[name.name] = val
		}
	}
	return res
}

func main() {

	sc := make(Supercache)

	sc.Create("lidi")
	sc.Set("lidi", "honza", "Jan Novak")
	sc.Set("lidi", "milan", "Milan Bubak")
	sc.Set("lidi", "petr", "Petr Novy")

	fmt.Println(sc.Len("lidi"))

	if vek, ok := sc.Get("lidi", "milan"); ok {
		fmt.Println(vek)
	}

	sc.Create("mesta")
	sc.Set("mesta", "ZN", "Znojmo")
	sc.Set("mesta", "MB", "Mlada Boleslav")
	sc.Set("mesta", "milan", "Velky Milanov")

	fmt.Println(sc.Len("mesta"))

	if vek, ok := sc.Get("mesta", "ZN"); ok {
		fmt.Println(vek)
	}

	h := "milan"
	milanove := sc.FindAll(h)
	fmt.Println("hledam:", h)
	if len(milanove) > 0 {
		fmt.Println("heja! naselm jsem:", len(milanove))
		for i, m := range milanove {
			fmt.Printf("\t[%s] %s\n", i, m)
		}

	}

	sc.Delete("lidi")
	fmt.Println(sc.Len("lidi"))

}

Výsledek je pak očekávatelný:

Jen nástřel

Tohle je jen 1. verze mého kešování. Finální verze implementuje práci s TTL keší a její rebuildování z externíh zdrojů, jako je JSON soubor, Redis, nebo Postgresql.

Publikováno v Go