summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLuke Shumaker <lukeshu@lukeshu.com>2020-01-27 19:35:32 -0500
committerLuke Shumaker <lukeshu@lukeshu.com>2020-01-27 19:35:32 -0500
commita047b135ca416584178a6adde64cc156ab637431 (patch)
treeeffbe114ece44bb30fa73c73ff25de98fcaa5fb2
parent496fca7357463f6ca05acab688018e8a1dc11855 (diff)
Have RRD.UnmarshalBinary() avoid parsing things repeatedly
-rw-r--r--rrdformat/format.go1
-rw-r--r--rrdformat/rrdbinary/decode.go (renamed from rrdformat/rrdbinary/unmarshal.go)38
-rw-r--r--rrdformat/unmarshal_binary.go79
3 files changed, 76 insertions, 42 deletions
diff --git a/rrdformat/format.go b/rrdformat/format.go
index f9b8504..2900ce8 100644
--- a/rrdformat/format.go
+++ b/rrdformat/format.go
@@ -70,7 +70,6 @@ type TimeWithUsec struct {
type TimeWithoutUsec struct {
Sec rrdbinary.Time
- Usec rrdbinary.Int `rrdbinary:"-"`
}
type PDPPrep struct {
diff --git a/rrdformat/rrdbinary/unmarshal.go b/rrdformat/rrdbinary/decode.go
index 00f1222..f3ae80e 100644
--- a/rrdformat/rrdbinary/unmarshal.go
+++ b/rrdformat/rrdbinary/decode.go
@@ -15,21 +15,27 @@ type Decoder struct {
data []byte
}
+func NewDecoder(arch Architecture, data []byte) *Decoder {
+ return &Decoder{
+ arch: arch,
+ pos: 0,
+ data: data,
+ }
+}
+
type unmarshaler interface {
unmarshalRRD(d *Decoder, tag string) error
}
func Unmarshal(arch Architecture, data []byte, ptr interface{}) error {
- ptrValue := reflect.ValueOf(ptr)
- if ptrValue.Kind() != reflect.Ptr {
- return typeErrorf("ptr is a %v, not a pointer", ptrValue.Kind())
+ decoder := NewDecoder(arch, data)
+ if err := decoder.Decode(ptr, ""); err != nil {
+ return err
}
- decoder := &Decoder{
- arch: arch,
- pos: 0,
- data: data,
+ if err := decoder.Decode(&EOF{}, ""); err != nil {
+ return err
}
- return decoder.Decode(ptrValue, "")
+ return nil
}
func (d *Decoder) binError(ctxLen int, msg string) error {
@@ -40,7 +46,15 @@ func (d *Decoder) binErrorf(ctxLen int, format string, a ...interface{}) error {
return d.binError(ctxLen, fmt.Sprintf(format, a...))
}
-func (d *Decoder) Decode(v reflect.Value, tag string) error {
+func (d *Decoder) Decode(ptr interface{}, tag string) error {
+ ptrValue := reflect.ValueOf(ptr)
+ if ptrValue.Kind() != reflect.Ptr {
+ return typeErrorf("ptr is a %v, not a pointer", ptrValue.Kind())
+ }
+ return d.decode(ptrValue, tag)
+}
+
+func (d *Decoder) decode(v reflect.Value, tag string) error {
if v.CanInterface() {
if u, ok := v.Interface().(unmarshaler); ok {
return u.unmarshalRRD(d, tag)
@@ -52,7 +66,7 @@ func (d *Decoder) Decode(v reflect.Value, tag string) error {
case reflect.Array, reflect.Slice:
return d.decodeList(v, tag)
default:
- return typeErrorf("invalid type for rrdbinary.Decoder.Decode: %v", v.Type())
+ return typeErrorf("invalid type for rrdbinary.Decoder: %v", v.Type())
}
}
@@ -70,7 +84,7 @@ func (d *Decoder) decodeStruct(v reflect.Value, tag string) error {
if tag == "-" {
continue
}
- if err := d.Decode(v.Field(i), tag); err != nil {
+ if err := d.decode(v.Field(i), tag); err != nil {
return fmt.Errorf("field %s: %w", fieldInfo.Name, err)
}
}
@@ -82,7 +96,7 @@ func (d *Decoder) decodeList(v reflect.Value, tag string) error {
panicUnless(v.CanSet())
for i := 0; i < v.Len(); i++ {
- if err := d.Decode(v.Index(i), tag); err != nil {
+ if err := d.decode(v.Index(i), tag); err != nil {
return fmt.Errorf("index %d: %w", i, err)
}
}
diff --git a/rrdformat/unmarshal_binary.go b/rrdformat/unmarshal_binary.go
index b9bafde..70c06b7 100644
--- a/rrdformat/unmarshal_binary.go
+++ b/rrdformat/unmarshal_binary.go
@@ -2,6 +2,7 @@ package rrdformat
import (
"encoding"
+ "fmt"
"git.lukeshu.com/go/librrd/rrdformat/rrdbinary"
)
@@ -16,44 +17,64 @@ func (rrd *RRD) UnmarshalBinary(data []byte) error {
if err != nil {
return err
}
- var header Header
- if err := rrdbinary.Unmarshal(arch, data, &header); err != nil {
- return err
- }
+ decoder := rrdbinary.NewDecoder(arch, data)
var parsed RRDv0005
- parsed.DSDefs = make([]DSDef, header.DSCnt)
- parsed.DSDefs = make([]DSDef, header.DSCnt)
- parsed.RRADefs = make([]RRADef, header.RRACnt)
- //LastUpdated
- parsed.PDPPreps = make([]PDPPrep, header.DSCnt)
- parsed.CDPPreps = make([]CDPPrep, header.DSCnt*header.RRACnt)
- parsed.RRAPtrs = make([]RRAPtr, header.RRACnt)
- //Values
- switch header.Version {
+ if err := decoder.Decode(&parsed.Header, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "Header", err)
+ }
+ // allocate memory based on .Header values
+ parsed.DSDefs = make([]DSDef, parsed.Header.DSCnt)
+ parsed.DSDefs = make([]DSDef, parsed.Header.DSCnt)
+ parsed.RRADefs = make([]RRADef, parsed.Header.RRACnt)
+ parsed.PDPPreps = make([]PDPPrep, parsed.Header.DSCnt)
+ parsed.CDPPreps = make([]CDPPrep, parsed.Header.DSCnt*parsed.Header.RRACnt)
+ parsed.RRAPtrs = make([]RRAPtr, parsed.Header.RRACnt)
+ // resume decoding
+ if err := decoder.Decode(&parsed.DSDefs, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "DSDefs", err)
+ }
+ if err := decoder.Decode(&parsed.RRADefs, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "RRADefs", err)
+ }
+ // allocate memory based on .RRADefs
+ val_cnt := 0
+ for i := range parsed.RRADefs {
+ val_cnt += int(parsed.RRADefs[i].RowCnt * parsed.Header.DSCnt)
+ }
+ parsed.Values = make([]RRDValue, val_cnt)
+ // resume decoding
+ var lastUpdatedPtr interface{}
+ switch parsed.Header.Version {
case "0001", "0002":
- _parsed := &RRDv0001{} //(*RRDv0001)(&parsed)
- if err := rrdbinary.Unmarshal(arch, data, _parsed); err != nil {
- return err
- }
+ lastUpdatedPtr = &parsed.LastUpdated.Sec
case "0003", "0004", "0005":
- if err := rrdbinary.Unmarshal(arch, data, &parsed); err != nil {
- return err
- }
+ lastUpdatedPtr = &parsed.LastUpdated
default:
- // version number already validated by
- // SniffArchitecture
+ // version number already validated by SniffArchitecture
panic("should not happen")
}
-
- val_cnt := 0
- for i := range parsed.RRADefs {
- val_cnt += int(parsed.RRADefs[i].RowCnt * header.DSCnt)
+ if err := decoder.Decode(lastUpdatedPtr, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "LastUpdated", err)
}
- parsed.Values = make([]RRDValue, val_cnt)
- if err := rrdbinary.Unmarshal(arch, data, &parsed.Values); err != nil {
- return err
+ if err := decoder.Decode(&parsed.LastUpdated, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "LastUpdated", err)
+ }
+ if err := decoder.Decode(&parsed.PDPPreps, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "PDPPreps", err)
+ }
+ if err := decoder.Decode(&parsed.CDPPreps, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "CDPPreps", err)
+ }
+ if err := decoder.Decode(&parsed.RRAPtrs, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "RRAPtrs", err)
+ }
+ if err := decoder.Decode(&parsed.Values, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "Values", err)
+ }
+ if err := decoder.Decode(&rrdbinary.EOF{}, ""); err != nil {
+ return fmt.Errorf("field %s: %w", "EOF", err)
}
*rrd = RRD{