github.com/m3db/m3@v1.5.0/src/x/serialize/decoder.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package serialize
    22  
    23  import (
    24  	"errors"
    25  	"fmt"
    26  
    27  	"github.com/m3db/m3/src/x/checked"
    28  	"github.com/m3db/m3/src/x/ident"
    29  )
    30  
    31  var (
    32  	// ErrIncorrectHeader is an error when encoded tag byte sequence doesn't start with
    33  	// an expected magic number.
    34  	ErrIncorrectHeader               = errors.New("header magic number does not match expected value")
    35  	errInvalidByteStreamIDDecoding   = errors.New("internal error, invalid byte stream while decoding ID")
    36  	errInvalidByteStreamUintDecoding = errors.New("internal error, invalid byte stream while decoding uint")
    37  )
    38  
    39  type decoder struct {
    40  	checkedData checked.Bytes
    41  	data        []byte
    42  	nextCalls   int
    43  	length      int
    44  	remaining   int
    45  	err         error
    46  
    47  	current         ident.Tag
    48  	currentTagName  checked.Bytes
    49  	currentTagValue checked.Bytes
    50  
    51  	opts TagDecoderOptions
    52  	pool TagDecoderPool
    53  }
    54  
    55  func newTagDecoder(opts TagDecoderOptions, pool TagDecoderPool) TagDecoder {
    56  	tagName := opts.CheckedBytesWrapperPool().Get(nil)
    57  	tagValue := opts.CheckedBytesWrapperPool().Get(nil)
    58  	tag := ident.Tag{
    59  		Name:  ident.BinaryID(tagName),
    60  		Value: ident.BinaryID(tagValue),
    61  	}
    62  	return &decoder{
    63  		opts:            opts,
    64  		pool:            pool,
    65  		current:         tag,
    66  		currentTagName:  tagName,
    67  		currentTagValue: tagValue,
    68  	}
    69  }
    70  
    71  func (d *decoder) Reset(b checked.Bytes) {
    72  	d.resetForReuse()
    73  	d.checkedData = b
    74  	d.checkedData.IncRef()
    75  	d.data = d.checkedData.Bytes()
    76  
    77  	header, err := d.decodeUInt16()
    78  	if err != nil {
    79  		d.err = err
    80  		return
    81  	}
    82  
    83  	if header != HeaderMagicNumber {
    84  		d.err = ErrIncorrectHeader
    85  		return
    86  	}
    87  
    88  	length, err := d.decodeUInt16()
    89  	if err != nil {
    90  		d.err = err
    91  		return
    92  	}
    93  
    94  	if limit := d.opts.TagSerializationLimits().MaxNumberTags(); length > limit {
    95  		d.err = fmt.Errorf("too many tags [ limit = %d, observed = %d ]", limit, length)
    96  		return
    97  	}
    98  
    99  	d.length = int(length)
   100  	d.remaining = int(length)
   101  }
   102  
   103  func (d *decoder) Next() bool {
   104  	d.releaseCurrent()
   105  	d.nextCalls++
   106  	if d.err != nil || d.remaining <= 0 {
   107  		return false
   108  	}
   109  
   110  	if err := d.decodeTag(); err != nil {
   111  		d.err = err
   112  		return false
   113  	}
   114  
   115  	d.remaining--
   116  	return true
   117  }
   118  
   119  func (d *decoder) Current() ident.Tag {
   120  	return d.current
   121  }
   122  
   123  func (d *decoder) CurrentIndex() int {
   124  	return d.Len() - d.Remaining()
   125  }
   126  
   127  func (d *decoder) decodeTag() error {
   128  	if err := d.decodeIDInto(d.currentTagName); err != nil {
   129  		return err
   130  	}
   131  	// safe to call Bytes() as d.current.Name has inc'd a ref
   132  	if len(d.currentTagName.Bytes()) == 0 {
   133  		d.releaseCurrent()
   134  		return ErrEmptyTagNameLiteral
   135  	}
   136  
   137  	if err := d.decodeIDInto(d.currentTagValue); err != nil {
   138  		d.releaseCurrent()
   139  		return err
   140  	}
   141  
   142  	return nil
   143  }
   144  
   145  func (d *decoder) decodeIDInto(b checked.Bytes) error {
   146  	l, err := d.decodeUInt16()
   147  	if err != nil {
   148  		return err
   149  	}
   150  
   151  	if limit := d.opts.TagSerializationLimits().MaxTagLiteralLength(); l > limit {
   152  		return fmt.Errorf("tag literal too long [ limit = %d, observed = %d ]", limit, int(l))
   153  	}
   154  
   155  	if len(d.data) < int(l) {
   156  		return errInvalidByteStreamIDDecoding
   157  	}
   158  
   159  	// incRef to indicate another checked.Bytes has a
   160  	// reference to the original bytes
   161  	d.checkedData.IncRef()
   162  	b.IncRef()
   163  	b.Reset(d.data[:l])
   164  	b.DecRef()
   165  	d.data = d.data[l:]
   166  
   167  	return nil
   168  }
   169  
   170  func (d *decoder) decodeUInt16() (uint16, error) {
   171  	if len(d.data) < 2 {
   172  		return 0, errInvalidByteStreamUintDecoding
   173  	}
   174  
   175  	n := decodeUInt16(d.data)
   176  	d.data = d.data[2:]
   177  	return n, nil
   178  }
   179  
   180  func (d *decoder) Err() error {
   181  	return d.err
   182  }
   183  
   184  func (d *decoder) Len() int {
   185  	return d.length
   186  }
   187  
   188  func (d *decoder) Remaining() int {
   189  	return d.remaining
   190  }
   191  
   192  func (d *decoder) releaseCurrent() {
   193  	d.currentTagName.IncRef()
   194  	if b := d.currentTagName.Bytes(); b != nil {
   195  		d.checkedData.DecRef()
   196  	}
   197  	d.currentTagName.Reset(nil)
   198  	d.currentTagName.DecRef()
   199  
   200  	d.currentTagValue.IncRef()
   201  	if b := d.currentTagValue.Bytes(); b != nil {
   202  		d.checkedData.DecRef()
   203  	}
   204  	d.currentTagValue.Reset(nil)
   205  	d.currentTagValue.DecRef()
   206  }
   207  
   208  func (d *decoder) resetForReuse() {
   209  	d.releaseCurrent()
   210  	d.data = nil
   211  	d.err = nil
   212  	d.remaining = 0
   213  	d.nextCalls = 0
   214  	if d.checkedData != nil {
   215  		d.checkedData.DecRef()
   216  		if d.checkedData.NumRef() == 0 {
   217  			d.checkedData.Finalize()
   218  		}
   219  		d.checkedData = nil
   220  	}
   221  }
   222  
   223  func (d *decoder) Close() {
   224  	d.resetForReuse()
   225  	if d.pool == nil {
   226  		return
   227  	}
   228  	d.pool.Put(d)
   229  }
   230  
   231  func (d *decoder) Duplicate() ident.TagIterator {
   232  	iter := d.pool.Get()
   233  	if d.checkedData == nil {
   234  		return iter
   235  	}
   236  	iter.Reset(d.checkedData)
   237  	for i := 0; i < d.nextCalls; i++ {
   238  		iter.Next()
   239  	}
   240  	return iter
   241  }
   242  
   243  func (d *decoder) Rewind() {
   244  	if d.checkedData == nil {
   245  		return
   246  	}
   247  	d.checkedData.IncRef()
   248  	d.Reset(d.checkedData)
   249  	d.checkedData.DecRef()
   250  }