aboutsummaryrefslogtreecommitdiffstats
path: root/skate/cache.go
diff options
context:
space:
mode:
authorMartin Czygan <martin.czygan@gmail.com>2021-05-20 13:23:09 +0200
committerMartin Czygan <martin.czygan@gmail.com>2021-05-20 13:23:09 +0200
commit7be09009b42d3af96ca8875c698922710d92d074 (patch)
treea7dea586f68f588438bd9ffa39e128d44fead3b7 /skate/cache.go
parentcec830ea500b50e9d38b0d6193b22cd10f577370 (diff)
downloadrefcat-7be09009b42d3af96ca8875c698922710d92d074.tar.gz
refcat-7be09009b42d3af96ca8875c698922710d92d074.zip
wip: cdx lookup
Diffstat (limited to 'skate/cache.go')
-rw-r--r--skate/cache.go92
1 files changed, 92 insertions, 0 deletions
diff --git a/skate/cache.go b/skate/cache.go
new file mode 100644
index 0000000..e5b0171
--- /dev/null
+++ b/skate/cache.go
@@ -0,0 +1,92 @@
+package skate
+
+import (
+ "crypto/sha1"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+
+ "git.archive.org/martin/cgraph/skate/atomic"
+)
+
+var ErrCacheMiss = errors.New("cache miss")
+
+type Cache struct {
+ Dir string
+ initialized bool
+}
+
+// Init creates all directories.
+func (c *Cache) init() error {
+ for i := 0; i < 256; i++ {
+ s := fmt.Sprintf("%02x", i)
+ d := path.Join(c.Dir, s)
+ if _, err := os.Stat(d); os.IsNotExist(err) {
+ if err := os.MkdirAll(d, 0755); err != nil {
+ return err
+ }
+ }
+ }
+ c.initialized = true
+ return nil
+}
+
+func (c *Cache) Has(k string) bool {
+ var (
+ shard, name = shardedHash(k)
+ spath = path.Join(c.Dir, shard, name)
+ )
+ if _, err := os.Stat(spath); os.IsNotExist(err) {
+ return false
+ }
+ return true
+}
+
+func (c *Cache) Get(k string) ([]byte, error) {
+ var (
+ shard, name = shardedHash(k)
+ spath = path.Join(c.Dir, shard, name)
+ )
+ if !c.initialized {
+ if err := c.init(); err != nil {
+ return nil, err
+ }
+ }
+ if _, err := os.Stat(spath); os.IsNotExist(err) {
+ return nil, ErrCacheMiss
+ }
+ f, err := os.Open(spath)
+ if err != nil {
+ return nil, err
+ }
+ defer f.Close()
+ return ioutil.ReadAll(f)
+}
+
+func (c *Cache) Set(k string, v []byte) error {
+ var (
+ shard, name = shardedHash(k)
+ spath = path.Join(c.Dir, shard, name)
+ )
+ if !c.initialized {
+ if err := c.init(); err != nil {
+ return err
+ }
+ }
+ if err := atomic.WriteFile(spath, v, 0755); err != nil {
+ return err
+ }
+ return nil
+}
+
+// shardedHash returns a sha1 shard (2) and name (38) for a given string value
+// (e.g. a URL).
+func shardedHash(v string) (shard, name string) {
+ h := sha1.New()
+ _, _ = io.WriteString(h, v)
+ name = fmt.Sprintf("%x", h.Sum(nil))
+ return name[:2], name[2:]
+}