mirror of
https://github.com/json-iterator/go.git
synced 2025-01-20 18:48:32 +02:00
#65 make placeholder thread safe
This commit is contained in:
parent
839247df05
commit
365d399192
@ -6,6 +6,7 @@ import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Decoder is an internal type registered to cache as needed.
|
||||
@ -169,11 +170,12 @@ func (encoder *optionalEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
}
|
||||
|
||||
type placeholderEncoder struct {
|
||||
valueEncoder Encoder
|
||||
cfg *frozenConfig
|
||||
cacheKey reflect.Type
|
||||
}
|
||||
|
||||
func (encoder *placeholderEncoder) encode(ptr unsafe.Pointer, stream *Stream) {
|
||||
encoder.valueEncoder.encode(ptr, stream)
|
||||
encoder.getRealEncoder().encode(ptr, stream)
|
||||
}
|
||||
|
||||
func (encoder *placeholderEncoder) encodeInterface(val interface{}, stream *Stream) {
|
||||
@ -181,15 +183,39 @@ func (encoder *placeholderEncoder) encodeInterface(val interface{}, stream *Stre
|
||||
}
|
||||
|
||||
func (encoder *placeholderEncoder) isEmpty(ptr unsafe.Pointer) bool {
|
||||
return encoder.valueEncoder.isEmpty(ptr)
|
||||
return encoder.getRealEncoder().isEmpty(ptr)
|
||||
}
|
||||
|
||||
func (encoder *placeholderEncoder) getRealEncoder() Encoder {
|
||||
for i := 0; i < 30; i++ {
|
||||
realDecoder := encoder.cfg.getEncoderFromCache(encoder.cacheKey)
|
||||
_, isPlaceholder := realDecoder.(*placeholderEncoder)
|
||||
if isPlaceholder {
|
||||
time.Sleep(time.Second)
|
||||
} else {
|
||||
return realDecoder
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("real encoder not found for cache key: %v", encoder.cacheKey))
|
||||
}
|
||||
|
||||
type placeholderDecoder struct {
|
||||
valueDecoder Decoder
|
||||
cfg *frozenConfig
|
||||
cacheKey reflect.Type
|
||||
}
|
||||
|
||||
func (decoder *placeholderDecoder) decode(ptr unsafe.Pointer, iter *Iterator) {
|
||||
decoder.valueDecoder.decode(ptr, iter)
|
||||
for i := 0; i < 30; i++ {
|
||||
realDecoder := decoder.cfg.getDecoderFromCache(decoder.cacheKey)
|
||||
_, isPlaceholder := realDecoder.(*placeholderDecoder)
|
||||
if isPlaceholder {
|
||||
time.Sleep(time.Second)
|
||||
} else {
|
||||
realDecoder.decode(ptr, iter)
|
||||
return
|
||||
}
|
||||
}
|
||||
panic(fmt.Sprintf("real decoder not found for cache key: %v", decoder.cacheKey))
|
||||
}
|
||||
|
||||
// emptyInterface is the header for an interface{} value.
|
||||
@ -283,10 +309,9 @@ func decoderOfType(cfg *frozenConfig, typ reflect.Type) (Decoder, error) {
|
||||
if cachedDecoder != nil {
|
||||
return cachedDecoder, nil
|
||||
}
|
||||
placeholder := &placeholderDecoder{}
|
||||
placeholder := &placeholderDecoder{cfg: cfg, cacheKey: cacheKey}
|
||||
cfg.addDecoderToCache(cacheKey, placeholder)
|
||||
newDecoder, err := createDecoderOfType(cfg, typ)
|
||||
placeholder.valueDecoder = newDecoder
|
||||
cfg.addDecoderToCache(cacheKey, newDecoder)
|
||||
return newDecoder, err
|
||||
}
|
||||
@ -382,10 +407,9 @@ func encoderOfType(cfg *frozenConfig, typ reflect.Type) (Encoder, error) {
|
||||
if cachedEncoder != nil {
|
||||
return cachedEncoder, nil
|
||||
}
|
||||
placeholder := &placeholderEncoder{}
|
||||
placeholder := &placeholderEncoder{cfg: cfg, cacheKey: cacheKey}
|
||||
cfg.addEncoderToCache(cacheKey, placeholder)
|
||||
newEncoder, err := createEncoderOfType(cfg, typ)
|
||||
placeholder.valueEncoder = newEncoder
|
||||
cfg.addEncoderToCache(cacheKey, newEncoder)
|
||||
return newEncoder, err
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user