Skip to content

Commit dd6eb2f

Browse files
committed
Refactor: Improve counter management in localCache
- Replaced direct counter manipulation with a dedicated `incrCounter` method to enhance thread safety by introducing a mutex for counter updates. - Streamlined the retrieval of cache statistics by directly iterating over the counters map, eliminating the need for a separate method to manage counters. - This refactor aims to improve the clarity and maintainability of the caching logic while ensuring accurate tracking of cache operations.
1 parent c64431a commit dd6eb2f

1 file changed

Lines changed: 25 additions & 35 deletions

File tree

cache.go

Lines changed: 25 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -585,9 +585,10 @@ func (t *Thing[T]) CacheStats(ctx context.Context) CacheStats {
585585

586586
// localCache implements CacheClient using in-memory sync.Map.
587587
type localCache struct {
588-
store sync.Map // map[string]string
589-
locks sync.Map // map[string]struct{}
590-
counters sync.Map // map[string]int
588+
store sync.Map // map[string]string
589+
locks sync.Map // map[string]struct{}
590+
counters sync.Map // map[string]int, now each counter is a separate key
591+
countersMu sync.Mutex // protects counters increment
591592
}
592593

593594
// DefaultLocalCache is the default in-memory cache client for Thing ORM.
@@ -632,19 +633,18 @@ func (m *localCache) Exists(key string) bool {
632633
}
633634

634635
func (m *localCache) GetModel(ctx context.Context, key string, dest interface{}) error {
635-
counters := m.getCounters()
636-
counters["GetModel"]++
636+
m.incrCounter("GetModel")
637637

638638
raw, ok := m.store.Load(key)
639639
if !ok {
640-
counters["GetModelMiss"]++
640+
m.incrCounter("GetModelMiss")
641641
return common.ErrNotFound
642642
}
643643

644644
// Assuming raw is []byte from Gob encoding
645645
b, ok := raw.([]byte)
646646
if !ok {
647-
counters["GetModelError"]++
647+
m.incrCounter("GetModelError")
648648
log.Printf("ERROR: localCache.GetModel: value for key '%s' is not []byte, but %T", key, raw)
649649
return fmt.Errorf("localCache: cached value for key '%s' is not []byte (%T)", key, raw)
650650
}
@@ -672,7 +672,7 @@ func (m *localCache) GetModel(ctx context.Context, key string, dest interface{})
672672
return fmt.Errorf("localCache: Gob Unmarshal error for key '%s' (map decode error: %v, direct decode error: %w)", key, err, directDecodeErr)
673673
}
674674
// Direct decode successful
675-
counters["GetModelHit"]++
675+
m.incrCounter("GetModelHit")
676676
return nil
677677
}
678678

@@ -720,13 +720,12 @@ func (m *localCache) GetModel(ctx context.Context, key string, dest interface{})
720720
return fmt.Errorf("localCache.GetModel: inconsistent state for key '%s', decoded to map but dest is not struct", key)
721721
}
722722

723-
counters["GetModelHit"]++
723+
m.incrCounter("GetModelHit")
724724
return nil
725725
}
726726

727727
func (m *localCache) SetModel(ctx context.Context, key string, model interface{}, fieldsToCache []string, expiration time.Duration) error {
728-
counters := m.getCounters()
729-
counters["SetModel"]++
728+
m.incrCounter("SetModel")
730729

731730
val := reflect.ValueOf(model)
732731
if val.Kind() == reflect.Ptr {
@@ -777,18 +776,17 @@ func (m *localCache) DeleteModel(ctx context.Context, key string) error {
777776
}
778777

779778
func (m *localCache) GetQueryIDs(ctx context.Context, queryKey string) ([]int64, error) {
780-
counters := m.getCounters()
781-
counters["GetQueryIDs"]++
779+
m.incrCounter("GetQueryIDs")
782780

783781
raw, ok := m.store.Load(queryKey)
784782
if !ok {
785-
counters["GetQueryIDsMiss"]++
783+
m.incrCounter("GetQueryIDsMiss")
786784
return nil, common.ErrNotFound
787785
}
788786

789787
b, ok := raw.([]byte)
790788
if !ok {
791-
counters["GetQueryIDsError"]++
789+
m.incrCounter("GetQueryIDsError")
792790
return nil, fmt.Errorf("localCache: cached query IDs for key '%s' is not []byte (%T)", queryKey, raw)
793791
}
794792

@@ -798,13 +796,12 @@ func (m *localCache) GetQueryIDs(ctx context.Context, queryKey string) ([]int64,
798796
if err := decoder.Decode(&ids); err != nil {
799797
return nil, fmt.Errorf("localCache: Gob Unmarshal error for query key '%s': %w", queryKey, err)
800798
}
801-
counters["GetQueryIDsHit"]++
799+
m.incrCounter("GetQueryIDsHit")
802800
return ids, nil
803801
}
804802

805803
func (m *localCache) SetQueryIDs(ctx context.Context, queryKey string, ids []int64, expiration time.Duration) error {
806-
counters := m.getCounters()
807-
counters["SetQueryIDs"]++
804+
m.incrCounter("SetQueryIDs")
808805

809806
if ids == nil {
810807
ids = []int64{}
@@ -839,28 +836,21 @@ func (m *localCache) ReleaseLock(ctx context.Context, lockKey string) error {
839836
}
840837

841838
func (m *localCache) incrCounter(name string) {
839+
m.countersMu.Lock()
840+
defer m.countersMu.Unlock()
842841
val, _ := m.counters.LoadOrStore(name, 0)
843842
m.counters.Store(name, val.(int)+1)
844843
}
845844

846845
func (m *localCache) GetCacheStats(ctx context.Context) CacheStats {
847846
clonedCounters := make(map[string]int)
848-
counters := m.getCounters()
849-
for k, v := range counters {
850-
clonedCounters[k] = v
851-
}
852-
return CacheStats{Counters: clonedCounters}
853-
}
854-
855-
// Helper to get or initialize counters map for localCache
856-
func (m *localCache) getCounters() map[string]int {
857-
if v, ok := m.counters.Load("actual_counters"); ok {
858-
if casted, castOk := v.(map[string]int); castOk {
859-
return casted
847+
m.counters.Range(func(key, value any) bool {
848+
k, ok1 := key.(string)
849+
v, ok2 := value.(int)
850+
if ok1 && ok2 {
851+
clonedCounters[k] = v
860852
}
861-
}
862-
// Initialize if not found or wrong type
863-
newCounters := make(map[string]int)
864-
m.counters.Store("actual_counters", newCounters)
865-
return newCounters
853+
return true
854+
})
855+
return CacheStats{Counters: clonedCounters}
866856
}

0 commit comments

Comments
 (0)