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.