agones.dev/agones@v1.53.0/pkg/gameserverallocations/cache.go (about)

     1  // Copyright 2019 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 gameserverallocations
    16  
    17  import (
    18  	"sync"
    19  
    20  	agonesv1 "agones.dev/agones/pkg/apis/agones/v1"
    21  )
    22  
    23  // gameserver cache to keep the Ready state gameserver.
    24  //
    25  //nolint:govet // ignore fieldalignment, singleton embedded in AllocationCache
    26  type gameServerCache struct {
    27  	mu    sync.RWMutex
    28  	cache map[string]*agonesv1.GameServer
    29  }
    30  
    31  // Store saves the data in the cache.
    32  // If there is already a value for this key, the incoming gs object is ignored
    33  // if its Generation metadata is less than the existing one, or if its Generation
    34  // is equal and its ResourceVersion is the same as the existing one.
    35  // Otherwise, the incoming gs object replaces the existing one.
    36  func (e *gameServerCache) Store(key string, gs *agonesv1.GameServer) {
    37  	e.mu.Lock()
    38  	defer e.mu.Unlock()
    39  	if e.cache == nil {
    40  		e.cache = map[string]*agonesv1.GameServer{}
    41  	}
    42  
    43  	// Check if there's already a value for this key
    44  	if existingGS, ok := e.cache[key]; ok {
    45  		// If the incoming gs object's Generation is less than the existing one, ignore it, but also check the ResourceVersion
    46  		// saves us a deep copy if we don't need to
    47  		if gs.ObjectMeta.Generation < existingGS.ObjectMeta.Generation || gs.ObjectMeta.ResourceVersion == existingGS.ObjectMeta.ResourceVersion {
    48  			return
    49  		}
    50  	}
    51  	// If the incoming gs object's Generation is greater, store it
    52  	e.cache[key] = gs.DeepCopy()
    53  }
    54  
    55  // Delete deletes the data. If it exists returns true.
    56  func (e *gameServerCache) Delete(key string) bool {
    57  	e.mu.Lock()
    58  	defer e.mu.Unlock()
    59  	ret := false
    60  	if e.cache != nil {
    61  		if _, ok := e.cache[key]; ok {
    62  			delete(e.cache, key)
    63  			ret = true
    64  		}
    65  	}
    66  
    67  	return ret
    68  }
    69  
    70  // Load returns the data from cache. It return true if the value exists in the cache
    71  func (e *gameServerCache) Load(key string) (*agonesv1.GameServer, bool) {
    72  	e.mu.RLock()
    73  	defer e.mu.RUnlock()
    74  	val, ok := e.cache[key]
    75  
    76  	return val, ok
    77  }
    78  
    79  // Range extracts data from the cache based on provided function f.
    80  func (e *gameServerCache) Range(f func(key string, gs *agonesv1.GameServer) bool) {
    81  	e.mu.RLock()
    82  	defer e.mu.RUnlock()
    83  	for k, v := range e.cache {
    84  		if !f(k, v) {
    85  			break
    86  		}
    87  	}
    88  }
    89  
    90  // Len returns the current length of the cache
    91  func (e *gameServerCache) Len() int {
    92  	e.mu.RLock()
    93  	defer e.mu.RUnlock()
    94  	return len(e.cache)
    95  }