Initial commit
This commit is contained in:
137
cache.go
Normal file
137
cache.go
Normal file
@@ -0,0 +1,137 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
// region DB
|
||||
type DB struct {
|
||||
path string
|
||||
readConn *sql.DB
|
||||
writeConn *sql.DB
|
||||
}
|
||||
|
||||
func (db *DB) Open() error {
|
||||
if db.path == "" {
|
||||
return fmt.Errorf("database path not set")
|
||||
}
|
||||
|
||||
writeConn, err := sql.Open("sqlite3", db.path+"?_journal=WAL&_synchronous=NORMAL")
|
||||
if err != nil {
|
||||
Error.Printf("%++v", err)
|
||||
return err
|
||||
}
|
||||
writeConn.SetMaxOpenConns(1)
|
||||
writeConn.SetConnMaxIdleTime(30 * time.Second)
|
||||
writeConn.SetConnMaxLifetime(30 * time.Second)
|
||||
db.writeConn = writeConn
|
||||
|
||||
readConn, err := sql.Open("sqlite3", db.path+"?mode=ro&_journal=WAL&_synchronous=NORMAL&_mode=ro")
|
||||
if err != nil {
|
||||
Error.Printf("%++v", err)
|
||||
return err
|
||||
}
|
||||
readConn.SetMaxOpenConns(4)
|
||||
readConn.SetConnMaxIdleTime(30 * time.Second)
|
||||
readConn.SetConnMaxLifetime(30 * time.Second)
|
||||
db.readConn = readConn
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *DB) Close() error {
|
||||
err := db.writeConn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = db.readConn.Close()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type DBCache interface {
|
||||
Get(key string) (any, error)
|
||||
Set(key string, value any) error
|
||||
Tidy() error
|
||||
Init() error
|
||||
}
|
||||
|
||||
// region Cache
|
||||
type Cache struct {
|
||||
db *DB
|
||||
hits int
|
||||
misses int
|
||||
}
|
||||
type CacheEntry struct {
|
||||
Key string
|
||||
Value string
|
||||
Date time.Time
|
||||
}
|
||||
|
||||
func (cache *Cache) Get(key string) (CacheEntry, error) {
|
||||
ret := CacheEntry{}
|
||||
var rkey, rvalue string
|
||||
var date time.Time
|
||||
err := cache.db.readConn.QueryRow("SELECT key, value, date FROM cache WHERE key = ?", key).Scan(&rkey, &rvalue, &date)
|
||||
if err != nil {
|
||||
log.Printf("Cache miss for %s: %v", key, err)
|
||||
cache.misses++
|
||||
return ret, err
|
||||
}
|
||||
|
||||
ret.Key = rkey
|
||||
ret.Value = rvalue
|
||||
ret.Date = date
|
||||
|
||||
cache.hits++
|
||||
log.Printf("Cache hit for %s", key)
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (cache *Cache) Set(key string, value string) error {
|
||||
_, err := cache.db.writeConn.Exec("INSERT INTO cache (key, value) VALUES (?, ?)", key, value)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cache *Cache) Init() error {
|
||||
_, err := cache.db.writeConn.Exec("CREATE TABLE IF NOT EXISTS cache (key TEXT, value TEXT, date DATE DEFAULT CURRENT_TIMESTAMP)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = cache.db.writeConn.Exec("CREATE INDEX IF NOT EXISTS idx_cache_key ON cache (key)")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cache *Cache) Tidy() error {
|
||||
_, err := cache.db.writeConn.Exec("DELETE FROM cache WHERE date < datetime('now', '-1 day')")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cache *Cache) Rate() float32 {
|
||||
return float32(cache.hits) / float32(cache.hits+cache.misses)
|
||||
}
|
||||
func (cache *Cache) RatePerc() string {
|
||||
return fmt.Sprintf("%.2f%%", cache.Rate()*100)
|
||||
}
|
Reference in New Issue
Block a user