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 }