@@ -122,6 +122,10 @@ func (c *Cache[K, _]) Keys() []K {
122122// NumberCache is a in-memory cache which is able to store only Number constraint.
123123type NumberCache [K comparable , V Number ] struct {
124124 * Cache [K , V ]
125+ // nmu is used to do lock in Increment/Decrement process.
126+ // Note that this must be here as a separate mutex because mu in Cache struct is Locked in GetItem,
127+ // and if we call mu.Lock in Increment/Decrement, it will cause deadlock.
128+ nmu sync.Mutex
125129}
126130
127131// NewNumber creates a new cache for Number constraint.
@@ -135,6 +139,9 @@ func NewNumber[K comparable, V Number]() *NumberCache[K, V] {
135139// Returns an error if the item was not found or expired. If there is no error, the
136140// incremented value is returned.
137141func (nc * NumberCache [K , V ]) Increment (k K , n V ) (val V , err error ) {
142+ // In order to avoid lost update, we must lock whole Increment/Decrement process.
143+ nc .nmu .Lock ()
144+ defer nc .nmu .Unlock ()
138145 got , err := nc .Cache .GetItem (k )
139146 if err != nil {
140147 return val , err
@@ -151,6 +158,8 @@ func (nc *NumberCache[K, V]) Increment(k K, n V) (val V, err error) {
151158// Returns an error if the item was not found or expired. If there is no error, the
152159// decremented value is returned.
153160func (nc * NumberCache [K , V ]) Decrement (k K , n V ) (val V , err error ) {
161+ nc .nmu .Lock ()
162+ defer nc .nmu .Unlock ()
154163 got , err := nc .Cache .GetItem (k )
155164 if err != nil {
156165 return val , err
0 commit comments