@@ -32,6 +32,8 @@ import (
3232
3333// Group is the user facing interface for a group
3434type Group interface {
35+ // TODO: deprecate the hotCache boolean in Set(). It is not needed
36+
3537 Set (context.Context , string , []byte , time.Time , bool ) error
3638 Get (context.Context , string , transport.Sink ) error
3739 Remove (context.Context , string ) error
@@ -60,10 +62,10 @@ func (f GetterFunc) Get(ctx context.Context, key string, dest transport.Sink) er
6062// A Group is a cache namespace and associated data loaded spread over
6163// a group of 1 or more machines.
6264type group struct {
63- name string
64- getter Getter
65- instance * Instance
66- cacheBytes int64 // limit for sum of mainCache and hotCache size
65+ name string
66+ getter Getter
67+ instance * Instance
68+ maxCacheBytes int64 // max size of both mainCache and hotCache
6769
6870 // mainCache is a cache of the keys for which this process
6971 // (amongst its peers) is authoritative. That is, this cache
@@ -135,27 +137,56 @@ func (g *group) Get(ctx context.Context, key string, dest transport.Sink) error
135137 return transport .SetSinkView (dest , value )
136138}
137139
138- func (g * group ) Set (ctx context.Context , key string , value []byte , expire time.Time , hotCache bool ) error {
140+ func (g * group ) Set (ctx context.Context , key string , value []byte , expire time.Time , _ bool ) error {
139141 if key == "" {
140142 return errors .New ("empty Set() key not allowed" )
141143 }
142144
145+ if g .maxCacheBytes <= 0 {
146+ return nil
147+ }
148+
143149 _ , err := g .setGroup .Do (key , func () (interface {}, error ) {
144150 // If remote peer owns this key
145151 owner , isRemote := g .instance .PickPeer (key )
146152 if isRemote {
147- if err := g .setFromPeer (ctx , owner , key , value , expire ); err != nil {
153+ // Set the key/value on the remote peer
154+ if err := g .setPeer (ctx , owner , key , value , expire ); err != nil {
148155 return nil , err
149156 }
150- // TODO(thrawn01): Not sure if this is useful outside of tests...
151- // maybe we should ALWAYS update the local cache?
152- if hotCache {
153- g .localSet (key , value , expire , g .hotCache )
157+ }
158+ // Update the local caches
159+ bv := transport .ByteViewWithExpire (value , expire )
160+ g .loadGroup .Lock (func () {
161+ g .mainCache .Add (key , bv )
162+ g .hotCache .Remove (key )
163+ })
164+
165+ // Update all peers in the cluster
166+ var wg sync.WaitGroup
167+ for _ , p := range g .instance .getAllPeers () {
168+ if p .PeerInfo ().IsSelf {
169+ continue // Skip self
170+ }
171+
172+ // Do not update the owner again, we already updated them
173+ if p .HashKey () == owner .HashKey () {
174+ continue
154175 }
155- return nil , nil
176+
177+ wg .Add (1 )
178+ go func (p peer.Client ) {
179+ if err := g .setPeer (ctx , p , key , value , expire ); err != nil {
180+ g .instance .opts .Logger .Error ("Failed to update peer" ,
181+ "peer" , p .PeerInfo ().Address ,
182+ "key" , key ,
183+ "err" , err )
184+ }
185+ wg .Done ()
186+ }(p )
156187 }
157- // We own this key
158- g . localSet ( key , value , expire , g . mainCache )
188+ wg . Wait ()
189+
159190 return nil , nil
160191 })
161192 return err
@@ -340,7 +371,7 @@ func (g *group) getFromPeer(ctx context.Context, peer peer.Client, key string) (
340371 return value , nil
341372}
342373
343- func (g * group ) setFromPeer (ctx context.Context , peer peer.Client , k string , v []byte , e time.Time ) error {
374+ func (g * group ) setPeer (ctx context.Context , peer peer.Client , k string , v []byte , e time.Time ) error {
344375 var expire int64
345376 if ! e .IsZero () {
346377 expire = e .UnixNano ()
@@ -363,7 +394,7 @@ func (g *group) removeFromPeer(ctx context.Context, peer peer.Client, key string
363394}
364395
365396func (g * group ) lookupCache (key string ) (value transport.ByteView , ok bool ) {
366- if g .cacheBytes <= 0 {
397+ if g .maxCacheBytes <= 0 {
367398 return
368399 }
369400 value , ok = g .mainCache .Get (key )
@@ -374,26 +405,30 @@ func (g *group) lookupCache(key string) (value transport.ByteView, ok bool) {
374405 return
375406}
376407
377- func (g * group ) LocalSet (key string , value []byte , expire time.Time ) {
378- g .localSet (key , value , expire , g .mainCache )
379- }
380-
381- func (g * group ) localSet (key string , value []byte , expire time.Time , cache Cache ) {
382- if g .cacheBytes <= 0 {
408+ // RemoteSet is called by the transport to set values in the local and hot caches when
409+ // a remote peer sends us a pb.SetRequest
410+ func (g * group ) RemoteSet (key string , value []byte , expire time.Time ) {
411+ if g .maxCacheBytes <= 0 {
383412 return
384413 }
385414
386- bv := transport .ByteViewWithExpire (value , expire )
387-
388- // Ensure no requests are in flight
415+ // Lock all load operations until this function returns
389416 g .loadGroup .Lock (func () {
390- g .populateCache (key , bv , cache )
417+ // This instance could take over ownership of this key at any moment after
418+ // the set is made. In order to avoid accidental propagation of the previous
419+ // value should this instance become owner of the key, we always set key in
420+ // the main cache.
421+ bv := transport .ByteViewWithExpire (value , expire )
422+ g .mainCache .Add (key , bv )
423+
424+ // It's possible the value could be in the hot cache.
425+ g .hotCache .Remove (key )
391426 })
392427}
393428
394429func (g * group ) LocalRemove (key string ) {
395430 // Clear key from our local cache
396- if g .cacheBytes <= 0 {
431+ if g .maxCacheBytes <= 0 {
397432 return
398433 }
399434
@@ -405,7 +440,7 @@ func (g *group) LocalRemove(key string) {
405440}
406441
407442func (g * group ) populateCache (key string , value transport.ByteView , cache Cache ) {
408- if g .cacheBytes <= 0 {
443+ if g .maxCacheBytes <= 0 {
409444 return
410445 }
411446 cache .Add (key , value )
@@ -440,7 +475,7 @@ func (g *group) CacheStats(which CacheType) CacheStats {
440475// ResetCacheSize changes the maxBytes allowed and resets both the main and hot caches.
441476// It is mostly intended for testing and is not thread safe.
442477func (g * group ) ResetCacheSize (maxBytes int64 ) error {
443- g .cacheBytes = maxBytes
478+ g .maxCacheBytes = maxBytes
444479 var (
445480 hotCache int64
446481 mainCache int64
0 commit comments