github.com/aacfactory/avro@v1.2.12/internal/base/config.go (about)

     1  package base
     2  
     3  import (
     4  	"encoding/binary"
     5  	"errors"
     6  	"golang.org/x/sync/singleflight"
     7  	"io"
     8  	"sync"
     9  	"unsafe"
    10  
    11  	"github.com/modern-go/reflect2"
    12  )
    13  
    14  const maxByteSliceSize = 1024 * 1024
    15  
    16  // DefaultConfig is the default API.
    17  var DefaultConfig = Config{}.Freeze()
    18  
    19  // Config customises how the codec should behave.
    20  type Config struct {
    21  	// TagKey is the struct tag key used when en/decoding structs.
    22  	// This defaults to "avro".
    23  	TagKey string
    24  
    25  	// BlockLength is the length of blocks for maps and arrays.
    26  	// This defaults to 100.
    27  	BlockLength int
    28  
    29  	// DisableBlockSizeHeader disables encoding of an array/map size in bytes.
    30  	// Encoded array/map will be prefixed with only the number of elements in
    31  	// contrast with default behavior which prefixes them with the number of elements
    32  	// and the total number of bytes in the array/map. Both approaches are valid according to the
    33  	// Avro specification, however not all decoders support the latter.
    34  	DisableBlockSizeHeader bool
    35  
    36  	// UnionResolutionError determines if an error will be returned
    37  	// when a type cannot be resolved while decoding a union.
    38  	UnionResolutionError bool
    39  
    40  	// PartialUnionTypeResolution dictates if the union type resolution
    41  	// should be attempted even when not all union types are registered.
    42  	// When enabled, the underlying type will get resolved if it is registered
    43  	// even if other types of the union are not. If resolution fails, logic
    44  	// falls back to default union resolution behavior based on the value of
    45  	// UnionResolutionError.
    46  	PartialUnionTypeResolution bool
    47  
    48  	// Disable caching layer for encoders and decoders, forcing them to get rebuilt on every
    49  	// call to Marshal() and Unmarshal()
    50  	DisableCaching bool
    51  
    52  	// MaxByteSliceSize is the maximum size of `bytes` or `string` types the Reader will create, defaulting to 1MiB.
    53  	// If this size is exceeded, the Reader returns an error. This can be disabled by setting a negative number.
    54  	MaxByteSliceSize int
    55  }
    56  
    57  // Freeze makes the configuration immutable.
    58  func (c Config) Freeze() API {
    59  	api := &frozenConfig{
    60  		config:   c,
    61  		resolver: NewTypeResolver(),
    62  	}
    63  
    64  	api.readerPool = &sync.Pool{
    65  		New: func() any {
    66  			return &Reader{
    67  				cfg:    api,
    68  				reader: nil,
    69  				buf:    nil,
    70  				head:   0,
    71  				tail:   0,
    72  			}
    73  		},
    74  	}
    75  	api.writerPool = &sync.Pool{
    76  		New: func() any {
    77  			return &Writer{
    78  				cfg:   api,
    79  				out:   nil,
    80  				buf:   make([]byte, 0, 512),
    81  				Error: nil,
    82  			}
    83  		},
    84  	}
    85  
    86  	api.processingGroup = new(singleflight.Group)
    87  	api.processingGroupKeys = &sync.Pool{}
    88  
    89  	return api
    90  }
    91  
    92  // API represents a frozen Config.
    93  type API interface {
    94  	// Marshal returns the Avro encoding of v.
    95  	Marshal(schema Schema, v any) ([]byte, error)
    96  
    97  	// Unmarshal parses the Avro encoded data and stores the result in the value pointed to by v.
    98  	// If v is nil or not a pointer, Unmarshal returns an error.
    99  	Unmarshal(schema Schema, data []byte, v any) error
   100  
   101  	// NewEncoder returns a new encoder that writes to w using schema.
   102  	NewEncoder(schema Schema, w io.Writer) *Encoder
   103  
   104  	// NewDecoder returns a new decoder that reads from reader r using schema.
   105  	NewDecoder(schema Schema, r io.Reader) *Decoder
   106  
   107  	// DecoderOf returns the value decoder for a given schema and type.
   108  	DecoderOf(schema Schema, typ reflect2.Type) ValDecoder
   109  
   110  	// EncoderOf returns the value encoder for a given schema and type.
   111  	EncoderOf(schema Schema, tpy reflect2.Type) ValEncoder
   112  
   113  	// Register registers names to their types for resolution. All primitive types are pre-registered.
   114  	Register(name string, obj any)
   115  }
   116  
   117  type frozenConfig struct {
   118  	config Config
   119  
   120  	decoderCache sync.Map // map[cacheKey]ValDecoder
   121  	encoderCache sync.Map // map[cacheKey]ValEncoder
   122  
   123  	processingDecoderCache sync.Map // map[cacheKey]ValDecoder
   124  	processingEncoderCache sync.Map // map[cacheKey]ValEncoder
   125  
   126  	processingGroup     *singleflight.Group
   127  	processingGroupKeys *sync.Pool
   128  
   129  	readerPool *sync.Pool
   130  	writerPool *sync.Pool
   131  
   132  	resolver *TypeResolver
   133  }
   134  
   135  func (c *frozenConfig) Marshal(schema Schema, v any) ([]byte, error) {
   136  	writer := c.borrowWriter()
   137  
   138  	writer.WriteVal(schema, v)
   139  	if err := writer.Error; err != nil {
   140  		c.returnWriter(writer)
   141  		return nil, err
   142  	}
   143  
   144  	result := writer.Buffer()
   145  	copied := make([]byte, len(result))
   146  	copy(copied, result)
   147  
   148  	c.returnWriter(writer)
   149  	return copied, nil
   150  }
   151  
   152  func (c *frozenConfig) borrowWriter() *Writer {
   153  	writer := c.writerPool.Get().(*Writer)
   154  	writer.Reset(nil)
   155  	return writer
   156  }
   157  
   158  func (c *frozenConfig) returnWriter(writer *Writer) {
   159  	writer.out = nil
   160  	writer.Error = nil
   161  
   162  	c.writerPool.Put(writer)
   163  }
   164  
   165  func (c *frozenConfig) Unmarshal(schema Schema, data []byte, v any) error {
   166  	reader := c.borrowReader(data)
   167  
   168  	reader.ReadVal(schema, v)
   169  	err := reader.Error
   170  	c.returnReader(reader)
   171  
   172  	if errors.Is(err, io.EOF) {
   173  		return nil
   174  	}
   175  
   176  	return err
   177  }
   178  
   179  func (c *frozenConfig) borrowReader(data []byte) *Reader {
   180  	reader := c.readerPool.Get().(*Reader)
   181  	reader.Reset(data)
   182  	return reader
   183  }
   184  
   185  func (c *frozenConfig) returnReader(reader *Reader) {
   186  	reader.Error = nil
   187  	c.readerPool.Put(reader)
   188  }
   189  
   190  func (c *frozenConfig) NewEncoder(schema Schema, w io.Writer) *Encoder {
   191  	writer, ok := w.(*Writer)
   192  	if !ok {
   193  		writer = NewWriter(w, 512, WithWriterConfig(c))
   194  	}
   195  	return &Encoder{
   196  		s: schema,
   197  		w: writer,
   198  	}
   199  }
   200  
   201  func (c *frozenConfig) NewDecoder(schema Schema, r io.Reader) *Decoder {
   202  	reader := NewReader(r, 512, WithReaderConfig(c))
   203  	return &Decoder{
   204  		s: schema,
   205  		r: reader,
   206  	}
   207  }
   208  
   209  func (c *frozenConfig) Register(name string, obj any) {
   210  	c.resolver.Register(name, obj)
   211  }
   212  
   213  type cacheKey struct {
   214  	fingerprint [32]byte
   215  	rtype       uintptr
   216  }
   217  
   218  func (c *frozenConfig) addDecoderToCache(fingerprint [32]byte, rtype uintptr, dec ValDecoder) {
   219  	if c.config.DisableCaching {
   220  		return
   221  	}
   222  	key := cacheKey{fingerprint: fingerprint, rtype: rtype}
   223  	c.decoderCache.Store(key, dec)
   224  }
   225  
   226  func (c *frozenConfig) getDecoderFromCache(fingerprint [32]byte, rtype uintptr) ValDecoder {
   227  	if c.config.DisableCaching {
   228  		return nil
   229  	}
   230  	key := cacheKey{fingerprint: fingerprint, rtype: rtype}
   231  	if dec, ok := c.decoderCache.Load(key); ok {
   232  		return dec.(ValDecoder)
   233  	}
   234  
   235  	return nil
   236  }
   237  
   238  func (c *frozenConfig) addEncoderToCache(fingerprint [32]byte, rtype uintptr, enc ValEncoder) {
   239  	if c.config.DisableCaching {
   240  		return
   241  	}
   242  	key := cacheKey{fingerprint: fingerprint, rtype: rtype}
   243  	c.encoderCache.Store(key, enc)
   244  }
   245  
   246  func (c *frozenConfig) getEncoderFromCache(fingerprint [32]byte, rtype uintptr) ValEncoder {
   247  	if c.config.DisableCaching {
   248  		return nil
   249  	}
   250  	key := cacheKey{fingerprint: fingerprint, rtype: rtype}
   251  	if enc, ok := c.encoderCache.Load(key); ok {
   252  		return enc.(ValEncoder)
   253  	}
   254  
   255  	return nil
   256  }
   257  
   258  func (c *frozenConfig) addProcessingDecoderToCache(fingerprint [32]byte, rtype uintptr, dec ValDecoder) {
   259  	key := cacheKey{fingerprint: fingerprint, rtype: rtype}
   260  	c.processingDecoderCache.Store(key, dec)
   261  }
   262  
   263  func (c *frozenConfig) getProcessingDecoderFromCache(fingerprint [32]byte, rtype uintptr) ValDecoder {
   264  	key := cacheKey{fingerprint: fingerprint, rtype: rtype}
   265  	if !c.config.DisableCaching {
   266  		if dec, ok := c.decoderCache.Load(key); ok {
   267  			return dec.(ValDecoder)
   268  		}
   269  	}
   270  	if dec, ok := c.processingDecoderCache.Load(key); ok {
   271  		return dec.(ValDecoder)
   272  	}
   273  	return nil
   274  }
   275  
   276  func (c *frozenConfig) addProcessingEncoderToCache(fingerprint [32]byte, rtype uintptr, enc ValEncoder) {
   277  	key := cacheKey{fingerprint: fingerprint, rtype: rtype}
   278  	c.processingEncoderCache.Store(key, enc)
   279  }
   280  
   281  func (c *frozenConfig) getProcessingEncoderFromCache(fingerprint [32]byte, rtype uintptr) ValEncoder {
   282  	key := cacheKey{fingerprint: fingerprint, rtype: rtype}
   283  	if !c.config.DisableCaching {
   284  		if enc, ok := c.encoderCache.Load(key); ok {
   285  			return enc.(ValEncoder)
   286  		}
   287  	}
   288  	if enc, ok := c.processingEncoderCache.Load(key); ok {
   289  		return enc.(ValEncoder)
   290  	}
   291  	return nil
   292  }
   293  
   294  var (
   295  	encoderProcessingKeyType = []byte{1}
   296  	decoderProcessingKeyType = []byte{2}
   297  )
   298  
   299  func (c *frozenConfig) borrowProcessEncoderGroupKey(schema Schema, typ reflect2.Type) (key []byte) {
   300  	k := c.processingGroupKeys.Get()
   301  	if k != nil {
   302  		key = *(k.(*[]byte))
   303  	} else {
   304  		key = make([]byte, 64)
   305  	}
   306  	fingerprint := schema.Fingerprint()
   307  	copy(key[:32], fingerprint[:])
   308  	binary.LittleEndian.PutUint64(key[32:], uint64(typ.RType()))
   309  	copy(key[63:], encoderProcessingKeyType)
   310  	return
   311  }
   312  
   313  func (c *frozenConfig) borrowProcessDecoderGroupKey(schema Schema, typ reflect2.Type) (key []byte) {
   314  	k := c.processingGroupKeys.Get()
   315  	if k != nil {
   316  		key = *(k.(*[]byte))
   317  	} else {
   318  		key = make([]byte, 64)
   319  	}
   320  	fingerprint := schema.Fingerprint()
   321  	copy(key[:32], fingerprint[:])
   322  	binary.LittleEndian.PutUint64(key[32:], uint64(typ.RType()))
   323  	copy(key[63:], decoderProcessingKeyType)
   324  	return
   325  }
   326  
   327  func (c *frozenConfig) returnProcessGroupKey(key []byte) {
   328  	c.processingGroup.Forget(unsafe.String(unsafe.SliceData(key), len(key)))
   329  	c.processingGroupKeys.Put(&key)
   330  }
   331  
   332  func (c *frozenConfig) getTagKey() string {
   333  	tagKey := c.config.TagKey
   334  	if tagKey == "" {
   335  		return "avro"
   336  	}
   337  	return tagKey
   338  }
   339  
   340  func (c *frozenConfig) getBlockLength() int {
   341  	blockSize := c.config.BlockLength
   342  	if blockSize <= 0 {
   343  		return 100
   344  	}
   345  	return blockSize
   346  }
   347  
   348  func (c *frozenConfig) getMaxByteSliceSize() int {
   349  	size := c.config.MaxByteSliceSize
   350  	if size == 0 {
   351  		return maxByteSliceSize
   352  	}
   353  	return size
   354  }