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.