using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using StackExchange.Redis; using ServerCore; using ServerBase; using ServerCommon; using ServerCommon.Cache; using META_ID = System.UInt32; using REQUESTOR_ID = System.String; namespace GameServer { public static class LandAuctionCacheHelper { public static async Task trySaveToCache(this LandAuction landAuction, REQUESTOR_ID requestorId) { var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var result = new Result(); var land_auction_action = landAuction.getEntityAction(); NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {landAuction.toBasicString()}"); var registry_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(registry_attribute, () => $"registry_attribute is null !!! - {landAuction.toBasicString()}"); var highest_bid_user_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(highest_bid_user_attribute, () => $"highest_bid_user_attribute is null !!! - {landAuction.toBasicString()}"); var land_auction_cache = new LandAuctionCache(); land_auction_cache.LandMetaId = registry_attribute.LandMetaId; land_auction_cache.AuctionNumber = registry_attribute.AuctionNumber; land_auction_cache.LandAuctionState = registry_attribute.LandAuctionState; land_auction_cache.LandAuctionResult = registry_attribute.LandAuctionResult; land_auction_cache.ProcessVersionTime = registry_attribute.ProcessVersionTime; var land_auction_cache_request = new LandAuctionCacheRequest(land_auction_cache, redis_connector); result = await land_auction_cache_request.upsertLandAuction(DateTimeHelper.toRemainingTimeMin(registry_attribute.AuctionEndTime)); if (result.isFail()) { return result; } if (LandAuctionState.Started == land_auction_cache.LandAuctionState) { await landAuction.tryRemoveLandAuctionTopBidderBlockFromCache(); } land_auction_action.resetCacheSaveStep(); var is_success = await landAuction.tryReleaseWriteLockWithLandAuction(requestorId); if (false == is_success) { var err_msg = $"Failed to tryReleaseWriteLockWithLandAuction() !!! - {landAuction.toBasicString()}"; Log.getLogger().warn(err_msg); } Log.getLogger().debug($"Called trySaveToCache() - {landAuction.toBasicString()}"); return result; } public static async Task tryAcquireWriteLockWithLandAuctionBidders(this LandAuction landAuction, REQUESTOR_ID requestorId, Int16 ttlSec) { var result = new Result(); var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var land_auction_registry_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(land_auction_registry_attribute, () => $"land_auction_registry_attribute is null !!! - requestorId:{requestorId}"); var land_meta_id = land_auction_registry_attribute.LandMetaId; var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector); var lock_key = $"lock:{bid_price_order_cache_request.toKey()}"; var locker_id = $"locker_id:{requestorId}"; var is_success = await redis_lua_executor.tryAcquireLock(lock_key, locker_id, ttlSec); if (false == is_success) { var err_msg = $"Failed to tryAcquireLock() !!! : LockKey:{lock_key}, LockerId:{locker_id}, TTLSec:{ttlSec} - {landAuction.toBasicString()}"; Log.getLogger().error(err_msg); return false; } return true; } public static async Task tryReleaseWriteLockWithLandAuctionBidders(this LandAuction landAuction, REQUESTOR_ID requestorId) { var result = new Result(); var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var land_auction_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requestorId:{requestorId}"); var land_meta_id = land_auction_attribute.LandMetaId; var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector); var lock_key = $"lock:{bid_price_order_cache_request.toKey()}"; var locker_id = $"locker_id:{requestorId}"; var is_success = await redis_lua_executor.tyrReleaseLock(lock_key, locker_id); if (false == is_success) { var err_msg = $"Failed to tyrReleaseLock() !!! : LockKey:{lock_key}, LockerId:{locker_id} - {landAuction.toBasicString()}"; Log.getLogger().warn(err_msg); return false; } return true; } public static async Task<(bool, LandAuctionTopBidderCache?, LandAuctionTopBidderCache?, bool)> tryRankLandAuctionTopBidderCache(this LandAuction landAuction, REQUESTOR_ID requestorId, double bidPrice) { var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var land_auction_action = landAuction.getEntityAction(); NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - requestorId:{requestorId}"); var land_meta_id = land_auction_action.getLandMetaId(); var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector); ( var is_success , var curr_ranker_id, var curr_ranker_score , var old_ranker_id, var old_ranker_score , var is_top_change ) = await redis_lua_executor.tryPlaceTopRankOnly( bid_price_order_cache_request.toKey() , requestorId , bidPrice, bid_price_order_cache_request.toBlockKey()); if (false == is_success) { var err_msg = $"Failed to tryPlaceTopRankOnly() !!! : {bid_price_order_cache_request.toKeyAll()} - {landAuction.toBasicString()}"; Log.getLogger().error(err_msg); return (false, null, null, false); } var curr_top_bidder = new LandAuctionTopBidderCache(); curr_top_bidder.LandMetaId = land_meta_id; curr_top_bidder.HighestBidUserGuid = curr_ranker_id; curr_top_bidder.HighestBidPrice = curr_ranker_score; if (true == is_top_change) { if(false == old_ranker_id.isNullOrWhiteSpace()) { var old_top_bidder = new LandAuctionTopBidderCache(); old_top_bidder.LandMetaId = land_meta_id; old_top_bidder.HighestBidUserGuid = old_ranker_id; old_top_bidder.HighestBidPrice = old_ranker_score; return (true, curr_top_bidder, old_top_bidder, is_top_change); } } return (true, curr_top_bidder, null, is_top_change); } public static async Task<(bool, LandAuctionTopBidderCache?)> tryGetLandAuctionTopBidderCacheWithBlock(this LandAuction landAuction) { var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var land_auction_action = landAuction.getEntityAction(); NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {landAuction.toBasicString()}"); var err_msg = string.Empty; var land_meta_id = land_auction_action.getLandMetaId(); var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector); ( var is_success , var is_top_found , var top_ranker_id, var top_ranker_score ) = await redis_lua_executor.tryGetTopRankAndSetBlock( bid_price_order_cache_request.toKey() , bid_price_order_cache_request.toBlockKey() ); if (false == is_success) { err_msg = $"Failed to tryGetTopRankAndSetBlock() !!! : {bid_price_order_cache_request.toKeyAll()} - {landAuction.toBasicString()}"; Log.getLogger().error(err_msg); return (false, null); } if (true == is_top_found) { var curr_top_bidder = new LandAuctionTopBidderCache(); curr_top_bidder.LandMetaId = land_meta_id; curr_top_bidder.HighestBidUserGuid = top_ranker_id; curr_top_bidder.HighestBidPrice = top_ranker_score; return (true, curr_top_bidder); } return (true, null); } public static async Task<(Result, LandAuctionTopBidderCache?)> tryGetLandAuctionTopBidderCache(this LandAuction landAuction) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_db = redis_connector.getDatabase(); NullReferenceCheckHelper.throwIfNull(redis_db, () => $"redis_db is null !!!"); var land_auction_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!!"); var top_bidder = new LandAuctionTopBidderCache(); var land_meta_id = land_auction_attribute.LandMetaId; var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector); try { var top_ranker = await redis_db.SortedSetRangeByRankWithScoresAsync(bid_price_order_cache_request.toKey(), 0, 0, Order.Descending); if (top_ranker.Length == 0) { return (result, null); } top_bidder.LandMetaId = land_meta_id; top_bidder.HighestBidUserGuid = top_ranker[0].Element.ToString(); top_bidder.HighestBidPrice = top_ranker[0].Score; return (result, top_bidder); } catch (Exception e) { var error_code = ServerErrorCode.TryCatchException; err_msg = $"Exception !!!, Failed to perfom in tryGetLandAuctionTopBidderCache() !!! : exception:{e}, errorCode:{error_code}, key:{bid_price_order_cache_request.toKey()} - {landAuction.toBasicString()}"; result.setFail(error_code, err_msg); Log.getLogger().error(result.toBasicString()); } return (result, null); } public static async Task tryRemoveLandAuctionTopBidderBlockFromCache(this LandAuction landAuction) { var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var err_msg = string.Empty; var land_auction_action = landAuction.getEntityAction(); NullReferenceCheckHelper.throwIfNull(land_auction_action, () => $"land_auction_action is null !!! - {landAuction.toBasicString()}"); var land_meta_id = land_auction_action.getLandMetaId(); var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector); var is_success = await redis_lua_executor.tryRemoveTopRankAndBlock( bid_price_order_cache_request.toKey() , bid_price_order_cache_request.toBlockKey() ); if (false == is_success) { err_msg = $"Failed to tryRemoveTopRankAndBlock() !!! : {bid_price_order_cache_request.toKeyAll()} - {landAuction.toBasicString()}"; Log.getLogger().warn(err_msg); return false; } return true; } public static async Task isExistTopBidderFromCache(this LandAuction landAuction) { var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var land_auction_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - {landAuction.toBasicString()}"); var land_meta_id = land_auction_attribute.LandMetaId; var bid_price_order_cache_request = new LandAuctionBidPriceOrderCacheRequest(land_meta_id, redis_connector); var is_exist_key = await bid_price_order_cache_request.isExistKey(); if (false == is_exist_key) { return false; } return true; } public static async Task IsExistLandAuctionFromCache(this LandAuction landAuction, REQUESTOR_ID requestorId) { var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var land_auction_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requstorId:{requestorId}"); var land_meta_id = land_auction_attribute.LandMetaId; var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector); var is_exist_key = await land_auction_cache_request.isExistKey(); if (false == is_exist_key) { return false; } return true; } public static async Task<(bool, string)> tryGetLandAuctionWithWriteLock(this LandAuction landAuction, REQUESTOR_ID requestorId, Int16 ttlSec) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var land_auction_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requstorId:{requestorId}"); var land_meta_id = land_auction_attribute.LandMetaId; var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector); var lock_key = $"lock:{land_auction_cache_request.toKey()}"; var locker_id = $"locker_id:{requestorId}"; (var is_success, var read_data) = await redis_lua_executor.tryReadWithLock( lock_key, locker_id , land_auction_cache_request.toKey(), ttlSec ); if (false == is_success) { err_msg = $"Failed to tryReadWithLock() !!! : LockKey:{land_auction_cache_request.toKey()}, LockerId:{locker_id}, TTLSec:{ttlSec} - {landAuction.toBasicString()}"; Log.getLogger().warn(err_msg); return (false, string.Empty); } if(null == read_data) { return (true, string.Empty); } return (true, read_data); } public static async Task tryAcquireWriteLockWithLandAuction(this LandAuction landAuction, REQUESTOR_ID requestorId, Int16 ttlSec) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var land_auction_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requestorId:{requestorId}"); var land_meta_id = land_auction_attribute.LandMetaId; var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector); var lock_key = $"lock:{land_auction_cache_request.toKey()}"; var locker_id = $"locker_id:{requestorId}"; var is_success = await redis_lua_executor.tryAcquireLock(lock_key, locker_id, ttlSec); if (false == is_success) { err_msg = $"Failed to tryAcquireLock() !!! : LockKey:{land_auction_cache_request.toKey()}, LockerId:{locker_id}, TTLSec:{ttlSec} - {landAuction.toBasicString()}"; Log.getLogger().warn(err_msg); return false; } return true; } public static async Task tryReleaseWriteLockWithLandAuction(this LandAuction landAuction, REQUESTOR_ID requestorid) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var land_auction_attribute = landAuction.getEntityAttribute(); NullReferenceCheckHelper.throwIfNull(land_auction_attribute, () => $"land_auction_attribute is null !!! - requstorId:{requestorid}"); var land_meta_id = land_auction_attribute.LandMetaId; var land_auction_cache_request = new LandAuctionCacheRequest(land_meta_id, redis_connector); var lock_key = $"lock:{land_auction_cache_request.toKey()}"; var locker_id = $"locker_id:{requestorid}"; var is_success = await redis_lua_executor.tyrReleaseLock(lock_key, locker_id); if (false == is_success) { err_msg = $"Failed to tyrReleaseLock() !!! : LockKey:{land_auction_cache_request.toKey()}, LockerId:{locker_id} - {landAuction.toBasicString()}"; Log.getLogger().warn(err_msg); return false; } return true; } public static async Task tryAcquireWriteLockWithLandAuctionReservation(REQUESTOR_ID requestorId, Int16 ttlSec) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisConnector(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var lock_key = $"land_auction_reservation:write_lock"; var locker_id = $"land_auction_reservation:locker_id:{requestorId}"; var is_success = await redis_lua_executor.tryAcquireLock(lock_key, locker_id, ttlSec); if (false == is_success) { err_msg = $"Failed to tryAcquireLock() !!! : LockKey:{lock_key}, LockerId:{locker_id}, TTLSec:{ttlSec} - requstorId:{requestorId}"; Log.getLogger().warn(err_msg); return false; } return true; } public static async Task tryReleaseWriteLockWithLandAuctionReservation(REQUESTOR_ID requestorId) { var result = new Result(); var err_msg = string.Empty; var server_logic = GameServerApp.getServerLogic(); var redis_connector = server_logic.getRedisDb(); var redis_lua_executor = server_logic.getRedisWithLuaScriptExecutor(); var lock_key = $"land_auction_reservation:write_lock"; var locker_id = $"land_auction_reservation:locker_id:{requestorId}"; var is_success = await redis_lua_executor.tyrReleaseLock(lock_key, locker_id); if (false == is_success) { err_msg = $"Failed to tyrReleaseLock() !!! : LockKey:{lock_key}, LockerId:{locker_id} - requstorId:{requestorId}"; Log.getLogger().warn(err_msg); return false; } return true; } } }