If we get GetSize
, can we also get methods for getting a keys position and getting a key at a position? Would be useful for showing a player their current position globally, and showing the player above a player currently playing ie "You are at position x, only 1000 coins behind player! "
Instead of just scanning each partition for the hash map, why not just keep a running total and perform a full scan as a background process during off peak times? How would something like this work you might ask? Well, itās actually quite simpleā¦
For each map instance, create a new long long variable (64-bit signed integer in C/C++, also a int64_t) that contains the count (referred to as an item counter). Upon creation of a new hash map, itās initialized to 0. Since everything is executing asynchronously, this value would need to be protected by a read/write lock that favors readers since the only time a read lock is active is when GetSize() is called.
MemoryStoryHashMap:SetAsync()
- Check if the specified key already exists. If it does not then increment the item counter, else leave it alone. This would use a write lock.MemoryStoreHashMap:UpdateAsync()
- Do nothing with the item counter since the existing data that is associated with the specified key is being updated.MemoryStoreHashMap:RemoveAsync()
- If the specified key exists, remove that key and decrement the item counter. If the key does not exist, then leave the item counter alone. This would use a write lock.MemoryStoreHashMap:GetAsync()
- Do not touch the item counter.MemoryStoreHashMap:ListItemsAsync()
- This has the potential of performing an audit every time it is called. This would use a write lock.MemoryStoreHashMap:GetSize()
- Returns the public item counter value or nil if there is an error. This would use a read lock.- The item expiration code would have to decrement the item counter based on how many entries have been removed. This would use a write lock.
Upon reading, some sanity checks would be made to the value (canāt be negative or exceed the maximum number of records). If the sanity check fails, fork off a new thread to audit the data and return nil. The audit would be a background thread that performs the following tasks:
- Acquire the write lock to the entire hash map and the item counter.
- Create a new item counter as a temporary value which is different than the public item counter that GetSize() returns.
- Walk through each item in the hash map, incrementing the temporary item counter for each valid item found.
- When finished, update the public item counter with the new value.
- Release the write lock.
A periodic audit could be tied into the code that removes expired items from the hash map.
What Iām using the memory store service for is to allow game world servers to send information about their environment to the lobby servers. Information such as game type, variants, map, player list, access code, etc⦠Game servers update their data every 15 seconds. The key is the game world serverās Game.JobId property which is a guaranteed unique GUID. When the game server completes and teleports all players back into the lobby, it erases itās own data from the memory store. Since the game server needs to know which map (and other parameters) was selected in the lobby, teleport data (through the client) is used. This data, since it also contains the private server ID and the private server access code, full AES-256-CBC with a random initialization vector along with full HMAC-SHA-256 authentication. With this in place, an exploiter cannot even read the data let alone tamper with it. If they do, they get kicked. The game world server aggregates this data from all players (data from each player must also match every other player) is sent back to the lobby in the memory store.
Thereās my suggestion on how to implement GetSize() for a hash map. At least thatās how I have done it when I wrote chained hash map modules for network server software.