diff options
author | Marc Pervaz Boocha <marcpervaz@qburst.com> | 2025-02-14 18:06:02 +0530 |
---|---|---|
committer | Marc Pervaz Boocha <marcpervaz@qburst.com> | 2025-02-14 18:06:02 +0530 |
commit | 0b6df1549e53ca4747b070043ebc4a41c5a5f47c (patch) | |
tree | 203b46f596473e10dfeb9157c8cb4763d29e2d76 /encoding.go | |
download | cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.gz cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.bz2 cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.lz cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.xz cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.tar.zst cache-0b6df1549e53ca4747b070043ebc4a41c5a5f47c.zip |
First Commit
Diffstat (limited to 'encoding.go')
-rw-r--r-- | encoding.go | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/encoding.go b/encoding.go new file mode 100644 index 0000000..ff07d2d --- /dev/null +++ b/encoding.go @@ -0,0 +1,194 @@ +package cache + +import ( + "bufio" + "encoding/binary" + "io" + "time" +) + +type Encoder struct { + *bufio.Writer + buf []byte +} + +func NewEncoder(w io.Writer) *Encoder { + return &Encoder{ + Writer: bufio.NewWriter(w), + buf: make([]byte, 8), + } +} + +func (e *Encoder) EncodeUint64(val uint64) error { + binary.LittleEndian.PutUint64(e.buf, val) + _, err := e.Write(e.buf) + return err +} + +func (e *Encoder) EncodeTime(val time.Time) error { + return e.EncodeUint64(uint64(val.Unix())) +} + +func (e *Encoder) EncodeBytes(val []byte) error { + if err := e.EncodeUint64(uint64(len(val))); err != nil { + return err + } + + _, err := e.Write(val) + return err +} + +func (e *Encoder) EncodeNode(n *Node) error { + if err := e.EncodeUint64(n.Hash); err != nil { + return err + } + + if err := e.EncodeTime(n.Expiration); err != nil { + return err + } + + if err := e.EncodeUint64(n.Access); err != nil { + return err + } + + if err := e.EncodeBytes(n.Key); err != nil { + return err + } + + if err := e.EncodeBytes(n.Value); err != nil { + return err + } + + return nil +} + +type Decoder struct { + *bufio.Reader + buf []byte +} + +func NewDecoder(r io.Reader) *Decoder { + return &Decoder{ + Reader: bufio.NewReader(r), + buf: make([]byte, 8), + } +} + +func (d *Decoder) DecodeUint64() (uint64, error) { + _, err := io.ReadFull(d, d.buf) + if err != nil { + return 0, err + } + return binary.LittleEndian.Uint64(d.buf), nil +} + +func (d *Decoder) DecodeTime() (time.Time, error) { + ts, err := d.DecodeUint64() + if err != nil { + return zero[time.Time](), err + } + return time.Unix(int64(ts), 0), nil +} + +func (d *Decoder) DecodeBytes() ([]byte, error) { + lenVal, err := d.DecodeUint64() + if err != nil { + return nil, err + } + data := make([]byte, lenVal) + _, err = io.ReadFull(d, data) + return data, err +} + +func (d *Decoder) DecodeNodes() (*Node, error) { + n := &Node{} + + hash, err := d.DecodeUint64() + if err != nil { + return nil, err + } + n.Hash = hash + + expiration, err := d.DecodeTime() + if err != nil { + return nil, err + } + n.Expiration = expiration + + access, err := d.DecodeUint64() + if err != nil { + return nil, err + } + n.Access = access + + n.Key, err = d.DecodeBytes() + if err != nil { + return nil, err + } + + n.Value, err = d.DecodeBytes() + if err != nil { + return nil, err + } + return n, err +} + +func (s *Store) Snapshot(w io.WriteSeeker) error { + s.mu.RLock() + defer s.mu.RUnlock() + + w.Seek(0, io.SeekStart) + wr := NewEncoder(w) + + wr.EncodeUint64(s.lenght) + + for v := s.evict.EvictNext; v != &s.evict; v = v.EvictNext { + if err := wr.EncodeNode(v); err != nil { + return err + } + } + wr.Flush() + return nil +} + +func (s *Store) LoadSnapshot(r io.ReadSeeker) error { + r.Seek(0, io.SeekStart) + rr := NewDecoder(r) + + lenght, err := rr.DecodeUint64() + if err != nil { + return err + } + s.lenght = lenght + + k := 128 + for k < int(s.lenght) { + k = k << 1 + } + + s.bucket = make([]Node, k) + for range s.lenght { + v, err := rr.DecodeNodes() + if err != nil { + return err + } + + idx := v.Hash % uint64(len(s.bucket)) + + bucket := &s.bucket[idx] + lazyInitBucket(bucket) + + v.HashPrev = bucket + v.HashNext = v.HashPrev.HashNext + v.HashNext.HashPrev = v + v.HashPrev.HashNext = v + + v.EvictPrev = &s.evict + v.EvictNext = v.EvictPrev.EvictNext + v.EvictNext.EvictPrev = v + v.EvictPrev.EvictNext = v + + s.cost = s.cost + uint64(len(v.Key)) + uint64(len(v.Value)) + } + return nil +} |