aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Polden <mpolden@mpolden.no>2020-01-10 18:53:49 +0100
committerMartin Polden <mpolden@mpolden.no>2020-01-11 12:25:42 +0100
commit86b038a9a3d0007b382f12816be4720dd776c8a9 (patch)
treeb9119f48b43fbbac026f279d80c7dfe0598959da
parentb51756462382c5dedba8020646c39fcc7e354ef5 (diff)
Support packing of cache value
-rw-r--r--cache/cache.go41
-rw-r--r--cache/cache_test.go21
2 files changed, 62 insertions, 0 deletions
diff --git a/cache/cache.go b/cache/cache.go
index 5d41bbe..3838212 100644
--- a/cache/cache.go
+++ b/cache/cache.go
@@ -2,7 +2,11 @@ package cache
import (
"encoding/binary"
+ "encoding/hex"
+ "fmt"
"hash/fnv"
+ "strconv"
+ "strings"
"sync"
"time"
@@ -41,6 +45,43 @@ func (v *Value) Answers() []string { return dnsutil.Answers(v.msg) }
// TTL returns the time to live of the cached value v.
func (v *Value) TTL() time.Duration { return dnsutil.MinTTL(v.msg) }
+// Pack returns a string representation of Value v.
+func (v *Value) Pack() (string, error) {
+ var sb strings.Builder
+ sb.WriteString(strconv.FormatInt(v.CreatedAt.Unix(), 10))
+ sb.WriteString(" ")
+ data, err := v.msg.Pack()
+ if err != nil {
+ return "", err
+ }
+ sb.WriteString(hex.EncodeToString(data))
+ return sb.String(), nil
+}
+
+// Unpack converts a string value into a Value type.
+func Unpack(value string) (Value, error) {
+ fields := strings.Fields(value)
+ if len(fields) < 2 {
+ return Value{}, fmt.Errorf("invalid number of fields: %q", value)
+ }
+ secs, err := strconv.ParseInt(fields[0], 10, 64)
+ if err != nil {
+ return Value{}, err
+ }
+ data, err := hex.DecodeString(fields[1])
+ if err != nil {
+ return Value{}, err
+ }
+ msg := &dns.Msg{}
+ if err := msg.Unpack(data); err != nil {
+ return Value{}, err
+ }
+ return Value{
+ CreatedAt: time.Unix(secs, 0),
+ msg: msg,
+ }, nil
+}
+
// New creates a new cache of given capacity.
//
// If client is non-nil, the cache will prefetch expired entries in an effort to serve results faster.
diff --git a/cache/cache_test.go b/cache/cache_test.go
index 7879d65..bf4c610 100644
--- a/cache/cache_test.go
+++ b/cache/cache_test.go
@@ -360,6 +360,27 @@ func TestCacheEvictAndUpdate(t *testing.T) {
}
}
+func TestPackValue(t *testing.T) {
+ v := Value{
+ CreatedAt: time.Now().Truncate(time.Second),
+ msg: newA("example.com.", 60, net.ParseIP("192.0.2.1")),
+ }
+ packed, err := v.Pack()
+ if err != nil {
+ t.Fatal(err)
+ }
+ unpacked, err := Unpack(packed)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got, want := unpacked.CreatedAt, v.CreatedAt; !want.Equal(got) {
+ t.Errorf("CreatedAt = %s, want %s", got, want)
+ }
+ if got, want := unpacked.msg.String(), v.msg.String(); want != got {
+ t.Errorf("msg = %s, want %s", got, want)
+ }
+}
+
func BenchmarkNewKey(b *testing.B) {
for n := 0; n < b.N; n++ {
NewKey("key", 1, 1)