agones.dev/agones@v1.53.0/pkg/gameserversets/gameserver_state_cache.go (about) 1 // Copyright 2018 Google LLC All Rights Reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package gameserversets 16 17 import ( 18 "sync" 19 20 agonesv1 "agones.dev/agones/pkg/apis/agones/v1" 21 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 22 ) 23 24 // gameServerSetCacheEntry manages a list of items created and deleted locally for a single game server set. 25 type gameServerSetCacheEntry struct { 26 pendingCreation map[string]*agonesv1.GameServer 27 pendingDeletion map[string]*agonesv1.GameServer 28 mu sync.Mutex 29 } 30 31 func (e *gameServerSetCacheEntry) created(gs *agonesv1.GameServer) { 32 e.mu.Lock() 33 defer e.mu.Unlock() 34 if e.pendingCreation == nil { 35 e.pendingCreation = map[string]*agonesv1.GameServer{} 36 } 37 e.pendingCreation[gs.Name] = gs.DeepCopy() 38 } 39 40 func (e *gameServerSetCacheEntry) deleted(gs *agonesv1.GameServer) { 41 e.mu.Lock() 42 defer e.mu.Unlock() 43 44 if e.pendingDeletion == nil { 45 e.pendingDeletion = map[string]*agonesv1.GameServer{} 46 } 47 48 // Was pending creation, but deleted already. 49 delete(e.pendingCreation, gs.Name) 50 51 gsClone := gs.DeepCopy() 52 t := metav1.Now() 53 gsClone.ObjectMeta.DeletionTimestamp = &t 54 e.pendingDeletion[gs.Name] = gsClone 55 } 56 57 // reconcileWithUpdatedServerList returns a list of game servers for a game server set taking into account 58 // the complete list of game servers passed as parameter and a list of pending creations and deletions. 59 func (e *gameServerSetCacheEntry) reconcileWithUpdatedServerList(list []*agonesv1.GameServer) []*agonesv1.GameServer { 60 e.mu.Lock() 61 defer e.mu.Unlock() 62 63 var result []*agonesv1.GameServer 64 65 found := map[string]bool{} 66 67 for _, gs := range list { 68 if d := e.pendingDeletion[gs.Name]; d != nil { 69 if !gs.ObjectMeta.DeletionTimestamp.IsZero() { 70 // has deletion timestamp - return theirs 71 result = append(result, d) 72 delete(e.pendingDeletion, gs.Name) 73 } else { 74 result = append(result, d) 75 } 76 } else { 77 // object not deleted locally, trust the list. 78 result = append(result, gs) 79 } 80 81 if e.pendingCreation[gs.Name] != nil { 82 // object was pending creation and now showed up in list results, remove local overlay. 83 delete(e.pendingCreation, gs.Name) 84 } 85 86 found[gs.Name] = true 87 } 88 89 // now delete from 'pendingDeletion' all the items that were not found in the result. 90 for gsName := range e.pendingDeletion { 91 if !found[gsName] { 92 // ("GSSC: %v is now fully deleted", gsName) 93 delete(e.pendingDeletion, gsName) 94 } 95 } 96 97 // add all game servers that are pending creation which were not in the list 98 for _, gs := range e.pendingCreation { 99 result = append(result, gs) 100 } 101 102 return result 103 } 104 105 // gameServerStateCache manages per-GSS cache of items created and deleted by this controller process 106 // to compensate for latency due to eventual consistency between client actions and K8s API server. 107 type gameServerStateCache struct { 108 cache sync.Map 109 } 110 111 func (c *gameServerStateCache) forGameServerSet(gsSet *agonesv1.GameServerSet) *gameServerSetCacheEntry { 112 v, _ := c.cache.LoadOrStore(gsSet.ObjectMeta.Namespace+"/"+gsSet.ObjectMeta.Name, &gameServerSetCacheEntry{}) 113 return v.(*gameServerSetCacheEntry) 114 } 115 116 func (c *gameServerStateCache) deleteGameServerSet(gsSet *agonesv1.GameServerSet) { 117 c.cache.Delete(gsSet.ObjectMeta.Namespace + "/" + gsSet.ObjectMeta.Name) 118 }