Skip to content

Commit 28452fc

Browse files
committed
cow cache is not same, as map read will modify the underlying map. use sync.Map for 1.9 and above, and mutex if sync.Map not available
1 parent ea8c330 commit 28452fc

File tree

3 files changed

+106
-56
lines changed

3 files changed

+106
-56
lines changed

feature_config.go

+1-56
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import (
55
"errors"
66
"io"
77
"reflect"
8-
"sync/atomic"
98
"unsafe"
109
)
1110

@@ -23,19 +22,6 @@ type Config struct {
2322
ObjectFieldMustBeSimpleString bool
2423
}
2524

26-
type frozenConfig struct {
27-
configBeforeFrozen Config
28-
sortMapKeys bool
29-
indentionStep int
30-
objectFieldMustBeSimpleString bool
31-
onlyTaggedField bool
32-
decoderCache unsafe.Pointer
33-
encoderCache unsafe.Pointer
34-
extensions []Extension
35-
streamPool chan *Stream
36-
iteratorPool chan *Iterator
37-
}
38-
3925
// API the public interface of this package.
4026
// Primary Marshal and Unmarshal.
4127
type API interface {
@@ -83,8 +69,7 @@ func (cfg Config) Froze() API {
8369
streamPool: make(chan *Stream, 16),
8470
iteratorPool: make(chan *Iterator, 16),
8571
}
86-
atomic.StorePointer(&frozenConfig.decoderCache, unsafe.Pointer(&map[string]ValDecoder{}))
87-
atomic.StorePointer(&frozenConfig.encoderCache, unsafe.Pointer(&map[string]ValEncoder{}))
72+
frozenConfig.initCache()
8873
if cfg.MarshalFloatWith6Digits {
8974
frozenConfig.marshalFloatWith6Digits()
9075
}
@@ -198,46 +183,6 @@ func (cfg *frozenConfig) escapeHTML() {
198183
cfg.addEncoderToCache(reflect.TypeOf((*string)(nil)).Elem(), &htmlEscapedStringEncoder{})
199184
}
200185

201-
func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder ValDecoder) {
202-
done := false
203-
for !done {
204-
ptr := atomic.LoadPointer(&cfg.decoderCache)
205-
cache := *(*map[reflect.Type]ValDecoder)(ptr)
206-
copied := map[reflect.Type]ValDecoder{}
207-
for k, v := range cache {
208-
copied[k] = v
209-
}
210-
copied[cacheKey] = decoder
211-
done = atomic.CompareAndSwapPointer(&cfg.decoderCache, ptr, unsafe.Pointer(&copied))
212-
}
213-
}
214-
215-
func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder ValEncoder) {
216-
done := false
217-
for !done {
218-
ptr := atomic.LoadPointer(&cfg.encoderCache)
219-
cache := *(*map[reflect.Type]ValEncoder)(ptr)
220-
copied := map[reflect.Type]ValEncoder{}
221-
for k, v := range cache {
222-
copied[k] = v
223-
}
224-
copied[cacheKey] = encoder
225-
done = atomic.CompareAndSwapPointer(&cfg.encoderCache, ptr, unsafe.Pointer(&copied))
226-
}
227-
}
228-
229-
func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) ValDecoder {
230-
ptr := atomic.LoadPointer(&cfg.decoderCache)
231-
cache := *(*map[reflect.Type]ValDecoder)(ptr)
232-
return cache[cacheKey]
233-
}
234-
235-
func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder {
236-
ptr := atomic.LoadPointer(&cfg.encoderCache)
237-
cache := *(*map[reflect.Type]ValEncoder)(ptr)
238-
return cache[cacheKey]
239-
}
240-
241186
func (cfg *frozenConfig) cleanDecoders() {
242187
typeDecoders = map[string]ValDecoder{}
243188
fieldDecoders = map[string]ValDecoder{}

feature_config_with_sync_map.go

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
//+build go1.9
2+
3+
package jsoniter
4+
5+
import (
6+
"reflect"
7+
"sync"
8+
)
9+
10+
type frozenConfig struct {
11+
configBeforeFrozen Config
12+
sortMapKeys bool
13+
indentionStep int
14+
objectFieldMustBeSimpleString bool
15+
onlyTaggedField bool
16+
decoderCache sync.Map
17+
encoderCache sync.Map
18+
extensions []Extension
19+
streamPool chan *Stream
20+
iteratorPool chan *Iterator
21+
}
22+
23+
func (cfg *frozenConfig) initCache() {
24+
cfg.decoderCache = sync.Map{}
25+
cfg.encoderCache = sync.Map{}
26+
}
27+
28+
29+
func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder ValDecoder) {
30+
cfg.decoderCache.Store(cacheKey, decoder)
31+
}
32+
33+
func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder ValEncoder) {
34+
cfg.encoderCache.Store(cacheKey, encoder)
35+
}
36+
37+
func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) ValDecoder {
38+
decoder, found := cfg.decoderCache.Load(cacheKey)
39+
if found {
40+
return decoder.(ValDecoder)
41+
}
42+
return nil
43+
}
44+
45+
func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder {
46+
encoder, found := cfg.encoderCache.Load(cacheKey)
47+
if found {
48+
return encoder.(ValEncoder)
49+
}
50+
return nil
51+
}

feature_config_without_sync_map.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
//+build !go1.9
2+
3+
package jsoniter
4+
5+
import (
6+
"reflect"
7+
"sync"
8+
)
9+
10+
type frozenConfig struct {
11+
configBeforeFrozen Config
12+
sortMapKeys bool
13+
indentionStep int
14+
objectFieldMustBeSimpleString bool
15+
onlyTaggedField bool
16+
cacheLock *sync.RWMutex
17+
decoderCache map[reflect.Type]ValDecoder
18+
encoderCache map[reflect.Type]ValEncoder
19+
extensions []Extension
20+
streamPool chan *Stream
21+
iteratorPool chan *Iterator
22+
}
23+
24+
func (cfg *frozenConfig) initCache() {
25+
cfg.cacheLock = &sync.RWMutex{}
26+
cfg.decoderCache = map[reflect.Type]ValDecoder{}
27+
cfg.encoderCache = map[reflect.Type]ValEncoder{}
28+
}
29+
30+
func (cfg *frozenConfig) addDecoderToCache(cacheKey reflect.Type, decoder ValDecoder) {
31+
cfg.cacheLock.Lock()
32+
cfg.decoderCache[cacheKey] = decoder
33+
cfg.cacheLock.Unlock()
34+
}
35+
36+
func (cfg *frozenConfig) addEncoderToCache(cacheKey reflect.Type, encoder ValEncoder) {
37+
cfg.cacheLock.Lock()
38+
cfg.encoderCache[cacheKey] = encoder
39+
cfg.cacheLock.Unlock()
40+
}
41+
42+
func (cfg *frozenConfig) getDecoderFromCache(cacheKey reflect.Type) ValDecoder {
43+
cfg.cacheLock.RLock()
44+
decoder, _ := cfg.decoderCache[cacheKey].(ValDecoder)
45+
cfg.cacheLock.RUnlock()
46+
return decoder
47+
}
48+
49+
func (cfg *frozenConfig) getEncoderFromCache(cacheKey reflect.Type) ValEncoder {
50+
cfg.cacheLock.RLock()
51+
encoder, _ := cfg.encoderCache[cacheKey].(ValEncoder)
52+
cfg.cacheLock.RUnlock()
53+
return encoder
54+
}

0 commit comments

Comments
 (0)