github.com/rbisecke/kafka-go@v0.4.27/protocol/encode.go (about)

     1  package protocol
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"hash/crc32"
     8  	"io"
     9  	"reflect"
    10  	"sync"
    11  	"sync/atomic"
    12  )
    13  
    14  type encoder struct {
    15  	writer io.Writer
    16  	err    error
    17  	table  *crc32.Table
    18  	crc32  uint32
    19  	buffer [32]byte
    20  }
    21  
    22  type encoderChecksum struct {
    23  	reader  io.Reader
    24  	encoder *encoder
    25  }
    26  
    27  func (e *encoderChecksum) Read(b []byte) (int, error) {
    28  	n, err := e.reader.Read(b)
    29  	if n > 0 {
    30  		e.encoder.update(b[:n])
    31  	}
    32  	return n, err
    33  }
    34  
    35  func (e *encoder) Reset(w io.Writer) {
    36  	e.writer = w
    37  	e.err = nil
    38  	e.table = nil
    39  	e.crc32 = 0
    40  	e.buffer = [32]byte{}
    41  }
    42  
    43  func (e *encoder) ReadFrom(r io.Reader) (int64, error) {
    44  	if e.table != nil {
    45  		r = &encoderChecksum{
    46  			reader:  r,
    47  			encoder: e,
    48  		}
    49  	}
    50  	return io.Copy(e.writer, r)
    51  }
    52  
    53  func (e *encoder) Write(b []byte) (int, error) {
    54  	if e.err != nil {
    55  		return 0, e.err
    56  	}
    57  	n, err := e.writer.Write(b)
    58  	if n > 0 {
    59  		e.update(b[:n])
    60  	}
    61  	if err != nil {
    62  		e.err = err
    63  	}
    64  	return n, err
    65  }
    66  
    67  func (e *encoder) WriteByte(b byte) error {
    68  	e.buffer[0] = b
    69  	_, err := e.Write(e.buffer[:1])
    70  	return err
    71  }
    72  
    73  func (e *encoder) WriteString(s string) (int, error) {
    74  	// This implementation is an optimization to avoid the heap allocation that
    75  	// would occur when converting the string to a []byte to call crc32.Update.
    76  	//
    77  	// Strings are rarely long in the kafka protocol, so the use of a 32 byte
    78  	// buffer is a good comprise between keeping the encoder value small and
    79  	// limiting the number of calls to Write.
    80  	//
    81  	// We introduced this optimization because memory profiles on the benchmarks
    82  	// showed that most heap allocations were caused by this code path.
    83  	n := 0
    84  
    85  	for len(s) != 0 {
    86  		c := copy(e.buffer[:], s)
    87  		w, err := e.Write(e.buffer[:c])
    88  		n += w
    89  		if err != nil {
    90  			return n, err
    91  		}
    92  		s = s[c:]
    93  	}
    94  
    95  	return n, nil
    96  }
    97  
    98  func (e *encoder) setCRC(table *crc32.Table) {
    99  	e.table, e.crc32 = table, 0
   100  }
   101  
   102  func (e *encoder) update(b []byte) {
   103  	if e.table != nil {
   104  		e.crc32 = crc32.Update(e.crc32, e.table, b)
   105  	}
   106  }
   107  
   108  func (e *encoder) encodeBool(v value) {
   109  	b := int8(0)
   110  	if v.bool() {
   111  		b = 1
   112  	}
   113  	e.writeInt8(b)
   114  }
   115  
   116  func (e *encoder) encodeInt8(v value) {
   117  	e.writeInt8(v.int8())
   118  }
   119  
   120  func (e *encoder) encodeInt16(v value) {
   121  	e.writeInt16(v.int16())
   122  }
   123  
   124  func (e *encoder) encodeInt32(v value) {
   125  	e.writeInt32(v.int32())
   126  }
   127  
   128  func (e *encoder) encodeInt64(v value) {
   129  	e.writeInt64(v.int64())
   130  }
   131  
   132  func (e *encoder) encodeString(v value) {
   133  	e.writeString(v.string())
   134  }
   135  
   136  func (e *encoder) encodeVarString(v value) {
   137  	e.writeVarString(v.string())
   138  }
   139  
   140  func (e *encoder) encodeCompactString(v value) {
   141  	e.writeCompactString(v.string())
   142  }
   143  
   144  func (e *encoder) encodeNullString(v value) {
   145  	e.writeNullString(v.string())
   146  }
   147  
   148  func (e *encoder) encodeVarNullString(v value) {
   149  	e.writeVarNullString(v.string())
   150  }
   151  
   152  func (e *encoder) encodeCompactNullString(v value) {
   153  	e.writeCompactNullString(v.string())
   154  }
   155  
   156  func (e *encoder) encodeBytes(v value) {
   157  	e.writeBytes(v.bytes())
   158  }
   159  
   160  func (e *encoder) encodeVarBytes(v value) {
   161  	e.writeVarBytes(v.bytes())
   162  }
   163  
   164  func (e *encoder) encodeCompactBytes(v value) {
   165  	e.writeCompactBytes(v.bytes())
   166  }
   167  
   168  func (e *encoder) encodeNullBytes(v value) {
   169  	e.writeNullBytes(v.bytes())
   170  }
   171  
   172  func (e *encoder) encodeVarNullBytes(v value) {
   173  	e.writeVarNullBytes(v.bytes())
   174  }
   175  
   176  func (e *encoder) encodeCompactNullBytes(v value) {
   177  	e.writeCompactNullBytes(v.bytes())
   178  }
   179  
   180  func (e *encoder) encodeArray(v value, elemType reflect.Type, encodeElem encodeFunc) {
   181  	a := v.array(elemType)
   182  	n := a.length()
   183  	e.writeInt32(int32(n))
   184  
   185  	for i := 0; i < n; i++ {
   186  		encodeElem(e, a.index(i))
   187  	}
   188  }
   189  
   190  func (e *encoder) encodeCompactArray(v value, elemType reflect.Type, encodeElem encodeFunc) {
   191  	a := v.array(elemType)
   192  	n := a.length()
   193  	e.writeUnsignedVarInt(uint64(n + 1))
   194  
   195  	for i := 0; i < n; i++ {
   196  		encodeElem(e, a.index(i))
   197  	}
   198  }
   199  
   200  func (e *encoder) encodeNullArray(v value, elemType reflect.Type, encodeElem encodeFunc) {
   201  	a := v.array(elemType)
   202  	if a.isNil() {
   203  		e.writeInt32(-1)
   204  		return
   205  	}
   206  
   207  	n := a.length()
   208  	e.writeInt32(int32(n))
   209  
   210  	for i := 0; i < n; i++ {
   211  		encodeElem(e, a.index(i))
   212  	}
   213  }
   214  
   215  func (e *encoder) encodeCompactNullArray(v value, elemType reflect.Type, encodeElem encodeFunc) {
   216  	a := v.array(elemType)
   217  	if a.isNil() {
   218  		e.writeUnsignedVarInt(0)
   219  		return
   220  	}
   221  
   222  	n := a.length()
   223  	e.writeUnsignedVarInt(uint64(n + 1))
   224  	for i := 0; i < n; i++ {
   225  		encodeElem(e, a.index(i))
   226  	}
   227  }
   228  
   229  func (e *encoder) writeInt8(i int8) {
   230  	writeInt8(e.buffer[:1], i)
   231  	e.Write(e.buffer[:1])
   232  }
   233  
   234  func (e *encoder) writeInt16(i int16) {
   235  	writeInt16(e.buffer[:2], i)
   236  	e.Write(e.buffer[:2])
   237  }
   238  
   239  func (e *encoder) writeInt32(i int32) {
   240  	writeInt32(e.buffer[:4], i)
   241  	e.Write(e.buffer[:4])
   242  }
   243  
   244  func (e *encoder) writeInt64(i int64) {
   245  	writeInt64(e.buffer[:8], i)
   246  	e.Write(e.buffer[:8])
   247  }
   248  
   249  func (e *encoder) writeString(s string) {
   250  	e.writeInt16(int16(len(s)))
   251  	e.WriteString(s)
   252  }
   253  
   254  func (e *encoder) writeVarString(s string) {
   255  	e.writeVarInt(int64(len(s)))
   256  	e.WriteString(s)
   257  }
   258  
   259  func (e *encoder) writeCompactString(s string) {
   260  	e.writeUnsignedVarInt(uint64(len(s)) + 1)
   261  	e.WriteString(s)
   262  }
   263  
   264  func (e *encoder) writeNullString(s string) {
   265  	if s == "" {
   266  		e.writeInt16(-1)
   267  	} else {
   268  		e.writeInt16(int16(len(s)))
   269  		e.WriteString(s)
   270  	}
   271  }
   272  
   273  func (e *encoder) writeVarNullString(s string) {
   274  	if s == "" {
   275  		e.writeVarInt(-1)
   276  	} else {
   277  		e.writeVarInt(int64(len(s)))
   278  		e.WriteString(s)
   279  	}
   280  }
   281  
   282  func (e *encoder) writeCompactNullString(s string) {
   283  	if s == "" {
   284  		e.writeUnsignedVarInt(0)
   285  	} else {
   286  		e.writeUnsignedVarInt(uint64(len(s)) + 1)
   287  		e.WriteString(s)
   288  	}
   289  }
   290  
   291  func (e *encoder) writeBytes(b []byte) {
   292  	e.writeInt32(int32(len(b)))
   293  	e.Write(b)
   294  }
   295  
   296  func (e *encoder) writeVarBytes(b []byte) {
   297  	e.writeVarInt(int64(len(b)))
   298  	e.Write(b)
   299  }
   300  
   301  func (e *encoder) writeCompactBytes(b []byte) {
   302  	e.writeUnsignedVarInt(uint64(len(b)) + 1)
   303  	e.Write(b)
   304  }
   305  
   306  func (e *encoder) writeNullBytes(b []byte) {
   307  	if b == nil {
   308  		e.writeInt32(-1)
   309  	} else {
   310  		e.writeInt32(int32(len(b)))
   311  		e.Write(b)
   312  	}
   313  }
   314  
   315  func (e *encoder) writeVarNullBytes(b []byte) {
   316  	if b == nil {
   317  		e.writeVarInt(-1)
   318  	} else {
   319  		e.writeVarInt(int64(len(b)))
   320  		e.Write(b)
   321  	}
   322  }
   323  
   324  func (e *encoder) writeCompactNullBytes(b []byte) {
   325  	if b == nil {
   326  		e.writeUnsignedVarInt(0)
   327  	} else {
   328  		e.writeUnsignedVarInt(uint64(len(b)) + 1)
   329  		e.Write(b)
   330  	}
   331  }
   332  
   333  func (e *encoder) writeBytesFrom(b Bytes) error {
   334  	size := int64(b.Len())
   335  	e.writeInt32(int32(size))
   336  	n, err := io.Copy(e, b)
   337  	if err == nil && n != size {
   338  		err = fmt.Errorf("size of bytes does not match the number of bytes that were written (size=%d, written=%d): %w", size, n, io.ErrUnexpectedEOF)
   339  	}
   340  	return err
   341  }
   342  
   343  func (e *encoder) writeNullBytesFrom(b Bytes) error {
   344  	if b == nil {
   345  		e.writeInt32(-1)
   346  		return nil
   347  	} else {
   348  		size := int64(b.Len())
   349  		e.writeInt32(int32(size))
   350  		n, err := io.Copy(e, b)
   351  		if err == nil && n != size {
   352  			err = fmt.Errorf("size of nullable bytes does not match the number of bytes that were written (size=%d, written=%d): %w", size, n, io.ErrUnexpectedEOF)
   353  		}
   354  		return err
   355  	}
   356  }
   357  
   358  func (e *encoder) writeVarNullBytesFrom(b Bytes) error {
   359  	if b == nil {
   360  		e.writeVarInt(-1)
   361  		return nil
   362  	} else {
   363  		size := int64(b.Len())
   364  		e.writeVarInt(size)
   365  		n, err := io.Copy(e, b)
   366  		if err == nil && n != size {
   367  			err = fmt.Errorf("size of nullable bytes does not match the number of bytes that were written (size=%d, written=%d): %w", size, n, io.ErrUnexpectedEOF)
   368  		}
   369  		return err
   370  	}
   371  }
   372  
   373  func (e *encoder) writeCompactNullBytesFrom(b Bytes) error {
   374  	if b == nil {
   375  		e.writeUnsignedVarInt(0)
   376  		return nil
   377  	} else {
   378  		size := int64(b.Len())
   379  		e.writeUnsignedVarInt(uint64(size + 1))
   380  		n, err := io.Copy(e, b)
   381  		if err == nil && n != size {
   382  			err = fmt.Errorf("size of compact nullable bytes does not match the number of bytes that were written (size=%d, written=%d): %w", size, n, io.ErrUnexpectedEOF)
   383  		}
   384  		return err
   385  	}
   386  }
   387  
   388  func (e *encoder) writeVarInt(i int64) {
   389  	e.writeUnsignedVarInt(uint64((i << 1) ^ (i >> 63)))
   390  }
   391  
   392  func (e *encoder) writeUnsignedVarInt(i uint64) {
   393  	b := e.buffer[:]
   394  	n := 0
   395  
   396  	for i >= 0x80 && n < len(b) {
   397  		b[n] = byte(i) | 0x80
   398  		i >>= 7
   399  		n++
   400  	}
   401  
   402  	if n < len(b) {
   403  		b[n] = byte(i)
   404  		n++
   405  	}
   406  
   407  	e.Write(b[:n])
   408  }
   409  
   410  type encodeFunc func(*encoder, value)
   411  
   412  var (
   413  	_ io.ReaderFrom   = (*encoder)(nil)
   414  	_ io.Writer       = (*encoder)(nil)
   415  	_ io.ByteWriter   = (*encoder)(nil)
   416  	_ io.StringWriter = (*encoder)(nil)
   417  
   418  	writerTo = reflect.TypeOf((*io.WriterTo)(nil)).Elem()
   419  )
   420  
   421  func encodeFuncOf(typ reflect.Type, version int16, flexible bool, tag structTag) encodeFunc {
   422  	if reflect.PtrTo(typ).Implements(writerTo) {
   423  		return writerEncodeFuncOf(typ)
   424  	}
   425  	switch typ.Kind() {
   426  	case reflect.Bool:
   427  		return (*encoder).encodeBool
   428  	case reflect.Int8:
   429  		return (*encoder).encodeInt8
   430  	case reflect.Int16:
   431  		return (*encoder).encodeInt16
   432  	case reflect.Int32:
   433  		return (*encoder).encodeInt32
   434  	case reflect.Int64:
   435  		return (*encoder).encodeInt64
   436  	case reflect.String:
   437  		return stringEncodeFuncOf(flexible, tag)
   438  	case reflect.Struct:
   439  		return structEncodeFuncOf(typ, version, flexible)
   440  	case reflect.Slice:
   441  		if typ.Elem().Kind() == reflect.Uint8 { // []byte
   442  			return bytesEncodeFuncOf(flexible, tag)
   443  		}
   444  		return arrayEncodeFuncOf(typ, version, flexible, tag)
   445  	default:
   446  		panic("unsupported type: " + typ.String())
   447  	}
   448  }
   449  
   450  func stringEncodeFuncOf(flexible bool, tag structTag) encodeFunc {
   451  	switch {
   452  	case flexible && tag.Nullable:
   453  		// In flexible messages, all strings are compact
   454  		return (*encoder).encodeCompactNullString
   455  	case flexible:
   456  		// In flexible messages, all strings are compact
   457  		return (*encoder).encodeCompactString
   458  	case tag.Nullable:
   459  		return (*encoder).encodeNullString
   460  	default:
   461  		return (*encoder).encodeString
   462  	}
   463  }
   464  
   465  func bytesEncodeFuncOf(flexible bool, tag structTag) encodeFunc {
   466  	switch {
   467  	case flexible && tag.Nullable:
   468  		// In flexible messages, all arrays are compact
   469  		return (*encoder).encodeCompactNullBytes
   470  	case flexible:
   471  		// In flexible messages, all arrays are compact
   472  		return (*encoder).encodeCompactBytes
   473  	case tag.Nullable:
   474  		return (*encoder).encodeNullBytes
   475  	default:
   476  		return (*encoder).encodeBytes
   477  	}
   478  }
   479  
   480  func structEncodeFuncOf(typ reflect.Type, version int16, flexible bool) encodeFunc {
   481  	type field struct {
   482  		encode encodeFunc
   483  		index  index
   484  		tagID  int
   485  	}
   486  
   487  	var fields []field
   488  	var taggedFields []field
   489  
   490  	forEachStructField(typ, func(typ reflect.Type, index index, tag string) {
   491  		if typ.Size() != 0 { // skip struct{}
   492  			forEachStructTag(tag, func(tag structTag) bool {
   493  				if tag.MinVersion <= version && version <= tag.MaxVersion {
   494  					f := field{
   495  						encode: encodeFuncOf(typ, version, flexible, tag),
   496  						index:  index,
   497  						tagID:  tag.TagID,
   498  					}
   499  
   500  					if tag.TagID < -1 {
   501  						// Normal required field
   502  						fields = append(fields, f)
   503  					} else {
   504  						// Optional tagged field (flexible messages only)
   505  						taggedFields = append(taggedFields, f)
   506  					}
   507  					return false
   508  				}
   509  				return true
   510  			})
   511  		}
   512  	})
   513  
   514  	return func(e *encoder, v value) {
   515  		for i := range fields {
   516  			f := &fields[i]
   517  			f.encode(e, v.fieldByIndex(f.index))
   518  		}
   519  
   520  		if flexible {
   521  			// See https://cwiki.apache.org/confluence/display/KAFKA/KIP-482%3A+The+Kafka+Protocol+should+Support+Optional+Tagged+Fields
   522  			// for details of tag buffers in "flexible" messages.
   523  			e.writeUnsignedVarInt(uint64(len(taggedFields)))
   524  
   525  			for i := range taggedFields {
   526  				f := &taggedFields[i]
   527  				e.writeUnsignedVarInt(uint64(f.tagID))
   528  
   529  				buf := &bytes.Buffer{}
   530  				se := &encoder{writer: buf}
   531  				f.encode(se, v.fieldByIndex(f.index))
   532  				e.writeUnsignedVarInt(uint64(buf.Len()))
   533  				e.Write(buf.Bytes())
   534  			}
   535  		}
   536  	}
   537  }
   538  
   539  func arrayEncodeFuncOf(typ reflect.Type, version int16, flexible bool, tag structTag) encodeFunc {
   540  	elemType := typ.Elem()
   541  	elemFunc := encodeFuncOf(elemType, version, flexible, tag)
   542  	switch {
   543  	case flexible && tag.Nullable:
   544  		// In flexible messages, all arrays are compact
   545  		return func(e *encoder, v value) { e.encodeCompactNullArray(v, elemType, elemFunc) }
   546  	case flexible:
   547  		// In flexible messages, all arrays are compact
   548  		return func(e *encoder, v value) { e.encodeCompactArray(v, elemType, elemFunc) }
   549  	case tag.Nullable:
   550  		return func(e *encoder, v value) { e.encodeNullArray(v, elemType, elemFunc) }
   551  	default:
   552  		return func(e *encoder, v value) { e.encodeArray(v, elemType, elemFunc) }
   553  	}
   554  }
   555  
   556  func writerEncodeFuncOf(typ reflect.Type) encodeFunc {
   557  	typ = reflect.PtrTo(typ)
   558  	return func(e *encoder, v value) {
   559  		// Optimization to write directly into the buffer when the encoder
   560  		// does no need to compute a crc32 checksum.
   561  		w := io.Writer(e)
   562  		if e.table == nil {
   563  			w = e.writer
   564  		}
   565  		_, err := v.iface(typ).(io.WriterTo).WriteTo(w)
   566  		if err != nil {
   567  			e.err = err
   568  		}
   569  	}
   570  }
   571  
   572  func writeInt8(b []byte, i int8) {
   573  	b[0] = byte(i)
   574  }
   575  
   576  func writeInt16(b []byte, i int16) {
   577  	binary.BigEndian.PutUint16(b, uint16(i))
   578  }
   579  
   580  func writeInt32(b []byte, i int32) {
   581  	binary.BigEndian.PutUint32(b, uint32(i))
   582  }
   583  
   584  func writeInt64(b []byte, i int64) {
   585  	binary.BigEndian.PutUint64(b, uint64(i))
   586  }
   587  
   588  func Marshal(version int16, value interface{}) ([]byte, error) {
   589  	typ := typeOf(value)
   590  	cache, _ := marshalers.Load().(map[versionedType]encodeFunc)
   591  	key := versionedType{typ: typ, version: version}
   592  	encode := cache[key]
   593  
   594  	if encode == nil {
   595  		encode = encodeFuncOf(reflect.TypeOf(value), version, false, structTag{
   596  			MinVersion: -1,
   597  			MaxVersion: -1,
   598  			TagID:      -2,
   599  			Compact:    true,
   600  			Nullable:   true,
   601  		})
   602  
   603  		newCache := make(map[versionedType]encodeFunc, len(cache)+1)
   604  		newCache[key] = encode
   605  
   606  		for typ, fun := range cache {
   607  			newCache[typ] = fun
   608  		}
   609  
   610  		marshalers.Store(newCache)
   611  	}
   612  
   613  	e, _ := encoders.Get().(*encoder)
   614  	if e == nil {
   615  		e = &encoder{writer: new(bytes.Buffer)}
   616  	}
   617  
   618  	b, _ := e.writer.(*bytes.Buffer)
   619  	defer func() {
   620  		b.Reset()
   621  		e.Reset(b)
   622  		encoders.Put(e)
   623  	}()
   624  
   625  	encode(e, nonAddressableValueOf(value))
   626  
   627  	if e.err != nil {
   628  		return nil, e.err
   629  	}
   630  
   631  	buf := b.Bytes()
   632  	out := make([]byte, len(buf))
   633  	copy(out, buf)
   634  	return out, nil
   635  }
   636  
   637  type versionedType struct {
   638  	typ     _type
   639  	version int16
   640  }
   641  
   642  var (
   643  	encoders   sync.Pool    // *encoder
   644  	marshalers atomic.Value // map[versionedType]encodeFunc
   645  )