From 9ed958664494788b48e170545bf22946b92a4106 Mon Sep 17 00:00:00 2001 From: "marcins78@gmail.com" Date: Sat, 19 Jan 2013 14:01:18 +0000 Subject: [PATCH] Long-Polling is now more robust and requires less CPU resources. --- .../async/handler/ChatRequestHandler.java | 9 --- .../async/handler/GameRequestHandler.java | 13 --- .../async/handler/HallRequestHandler.java | 11 --- .../src/main/web/js/gemp-016/hallUi.js | 8 +- .../polling/LongPollableResource.java | 10 ++- .../gempukku/polling/LongPollingResource.java | 2 - .../gempukku/polling/LongPollingSystem.java | 81 +++++++++++++------ .../com/gempukku/polling/WaitingRequest.java | 5 ++ .../game/state/GameCommunicationChannel.java | 23 +++--- .../draft/DraftCommunicationChannel.java | 26 +++--- .../lotro/game/ChatCommunicationChannel.java | 20 +++-- .../lotro/hall/HallCommunicationChannel.java | 20 +++-- 12 files changed, 128 insertions(+), 100 deletions(-) create mode 100644 gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/WaitingRequest.java diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/ChatRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/ChatRequestHandler.java index adfc69a7c..332860a4e 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/ChatRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/ChatRequestHandler.java @@ -90,15 +90,6 @@ public class ChatRequestHandler extends LotroServerRequestHandler implements Uri _responseWriter = responseWriter; } - @Override - public boolean isChanged() { - try { - return _chatRoom.getChatRoomListener(_playerId).hasMessages(); - } catch (SubscriptionExpiredException e) { - return true; - } - } - @Override public synchronized boolean wasProcessed() { return _processed; diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/GameRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/GameRequestHandler.java index 6b2056b6e..7906be92f 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/GameRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/GameRequestHandler.java @@ -112,19 +112,6 @@ public class GameRequestHandler extends LotroServerRequestHandler implements Uri _responseWriter = responseWriter; } - @Override - public boolean isChanged() { - try { - return _gameMediator.getCommunicationChannel(_resourceOwner, _channelNumber).hasGameEvents(); - } catch (PrivateInformationException e) { - return true; - } catch (SubscriptionExpiredException e) { - return true; - } catch (SubscriptionConflictException e) { - return true; - } - } - @Override public synchronized boolean wasProcessed() { return _processed; diff --git a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/HallRequestHandler.java b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/HallRequestHandler.java index 60dcbf0c2..c9aad8de7 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/HallRequestHandler.java +++ b/gemp-lotr/gemp-lotr-async/src/main/java/com/gempukku/lotro/async/handler/HallRequestHandler.java @@ -465,17 +465,6 @@ public class HallRequestHandler extends LotroServerRequestHandler implements Uri _responseWriter = responseWriter; } - @Override - public boolean isChanged() { - try { - return _hallServer.getCommunicationChannel(_resourceOwner, _channelNumber).hasChangesInCommunicationChannel(); - } catch (SubscriptionExpiredException e) { - return true; - } catch (SubscriptionConflictException e) { - return true; - } - } - @Override public synchronized boolean wasProcessed() { return _processed; diff --git a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-016/hallUi.js b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-016/hallUi.js index a4a843c44..249c4fa59 100644 --- a/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-016/hallUi.js +++ b/gemp-lotr/gemp-lotr-async/src/main/web/js/gemp-016/hallUi.js @@ -11,6 +11,7 @@ var GempLotrHallUI = Class.extend({ buttonsDiv:null, pocketDiv:null, + pocketValue:null, hallChannelId: null, init:function (div, url, chat) { @@ -422,8 +423,11 @@ var GempLotrHallUI = Class.extend({ if (root.tagName == "hall") { this.hallChannelId = root.getAttribute("channelNumber"); - var currency = root.getAttribute("currency"); - this.pocketDiv.html(formatPrice(currency)); + var currency = parseInt(root.getAttribute("currency")); + if (currency != this.pocketValue) { + this.pocketValue = currency; + this.pocketDiv.html(formatPrice(currency)); + } var motd = root.getAttribute("motd"); if (motd != null) diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollableResource.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollableResource.java index a91b7297b..fa45babec 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollableResource.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollableResource.java @@ -1,7 +1,13 @@ package com.gempukku.polling; public interface LongPollableResource { - public void registerForChanges(LongPollingResource longPollingResource); + /** + * Registers the request for changes, however if there are any changes that can be consumed immediatelly, then + * true is returned. + * @param waitingRequest + * @return + */ + public boolean registerRequest(WaitingRequest waitingRequest); - public void deregisterResource(LongPollingResource longPollingResource); + public void deregisterRequest(WaitingRequest waitingRequest); } diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollingResource.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollingResource.java index 5ac4e8040..f3af5b6a5 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollingResource.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollingResource.java @@ -1,8 +1,6 @@ package com.gempukku.polling; public interface LongPollingResource { - public boolean isChanged(); - public boolean wasProcessed(); public void processIfNotProcessed(); diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollingSystem.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollingSystem.java index f52426dce..a176ddb09 100644 --- a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollingSystem.java +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/LongPollingSystem.java @@ -2,33 +2,40 @@ package com.gempukku.polling; import org.apache.log4j.Logger; +import java.util.Collections; +import java.util.HashSet; import java.util.Iterator; -import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.Set; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; public class LongPollingSystem { private static Logger _log = Logger.getLogger(LongPollingSystem.class); - private ConcurrentLinkedQueue _waitingActions = new ConcurrentLinkedQueue(); + private final Set _waitingActions = Collections.synchronizedSet(new HashSet()); + private long _pollingInterval = 1000; private long _pollingLength = 10000; - private ProcessingRunnable _processingRunnable; + + private ProcessingRunnable _timeoutRunnable; + private ExecutorService _executorService = Executors.newCachedThreadPool(); public LongPollingSystem() { } public void start() { - _processingRunnable = new ProcessingRunnable(); - Thread thr = new Thread(_processingRunnable); + _timeoutRunnable = new ProcessingRunnable(); + Thread thr = new Thread(_timeoutRunnable); thr.start(); } public void processLongPollingResource(LongPollingResource resource, LongPollableResource pollableResource) { - if (resource.isChanged()) - resource.processIfNotProcessed(); - else - pollableResource.registerForChanges(resource); - - _waitingActions.add(new TimeoutResource(resource, pollableResource, System.currentTimeMillis())); + ResourceWaitingRequest request = new ResourceWaitingRequest(pollableResource, resource, System.currentTimeMillis()); + if (pollableResource.registerRequest(request)) { + execute(resource); + } else { + _waitingActions.add(request); + } } private void pause() { @@ -39,21 +46,38 @@ public class LongPollingSystem { } } + private void processWaitingRequest(final ResourceWaitingRequest request) { + _waitingActions.remove(request); + execute(request.getLongPollingResource()); + } + + private void execute(final LongPollingResource resource) { + _executorService.submit( + new Runnable() { + @Override + public void run() { + resource.processIfNotProcessed(); + } + }); + } + private class ProcessingRunnable implements Runnable { @Override public void run() { while (true) { - long now = System.currentTimeMillis(); - Iterator iterator = _waitingActions.iterator(); - while (iterator.hasNext()) { - TimeoutResource resource = iterator.next(); - if (resource.getLongPollingResource().wasProcessed()) - iterator.remove(); - else { - if (resource.getStart() + _pollingLength < now) { - resource.getLongPollableResource().deregisterResource(resource.getLongPollingResource()); - resource.getLongPollingResource().processIfNotProcessed(); + synchronized (_waitingActions) { + long now = System.currentTimeMillis(); + Iterator iterator = _waitingActions.iterator(); + while (iterator.hasNext()) { + ResourceWaitingRequest waitingRequest = iterator.next(); + if (waitingRequest.getLongPollingResource().wasProcessed()) iterator.remove(); + else { + if (waitingRequest.getStart() + _pollingLength < now) { + waitingRequest.getLongPollableResource().deregisterRequest(waitingRequest); + iterator.remove(); + execute(waitingRequest.getLongPollingResource()); + } } } } @@ -62,17 +86,22 @@ public class LongPollingSystem { } } - private class TimeoutResource { - private long _start; - private LongPollableResource _longPollableResource; + private class ResourceWaitingRequest implements WaitingRequest { private LongPollingResource _longPollingResource; + private LongPollableResource _longPollableResource; + private long _start; - private TimeoutResource(LongPollingResource longPollingResource, LongPollableResource longPollableResource, long start) { - _longPollingResource = longPollingResource; + private ResourceWaitingRequest(LongPollableResource longPollableResource, LongPollingResource longPollingResource, long start) { _longPollableResource = longPollableResource; + _longPollingResource = longPollingResource; _start = start; } + @Override + public void processRequest() { + processWaitingRequest(this); + } + public LongPollableResource getLongPollableResource() { return _longPollableResource; } diff --git a/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/WaitingRequest.java b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/WaitingRequest.java new file mode 100644 index 000000000..c269e9a8d --- /dev/null +++ b/gemp-lotr/gemp-lotr-common/src/main/java/com/gempukku/polling/WaitingRequest.java @@ -0,0 +1,5 @@ +package com.gempukku.polling; + +public interface WaitingRequest { + public void processRequest(); +} diff --git a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameCommunicationChannel.java b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameCommunicationChannel.java index a3a182da6..ab2ef1eb8 100644 --- a/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-logic/src/main/java/com/gempukku/lotro/game/state/GameCommunicationChannel.java @@ -3,21 +3,20 @@ package com.gempukku.lotro.game.state; import com.gempukku.lotro.common.Token; import com.gempukku.lotro.communication.GameStateListener; import com.gempukku.lotro.game.PhysicalCard; +import static com.gempukku.lotro.game.state.GameEvent.Type.*; import com.gempukku.lotro.logic.decisions.AwaitingDecision; import com.gempukku.lotro.logic.timing.GameStats; import com.gempukku.polling.LongPollableResource; -import com.gempukku.polling.LongPollingResource; +import com.gempukku.polling.WaitingRequest; import java.util.*; -import static com.gempukku.lotro.game.state.GameEvent.Type.*; - public class GameCommunicationChannel implements GameStateListener, LongPollableResource { private List _events = new LinkedList(); private String _self; private long _lastConsumed = System.currentTimeMillis(); private int _channelNumber; - private LongPollingResource _longPollingResource; + private WaitingRequest _waitingRequest; public GameCommunicationChannel(String self, int channelNumber) { _self = self; @@ -37,19 +36,23 @@ public class GameCommunicationChannel implements GameStateListener, LongPollable } @Override - public synchronized void deregisterResource(LongPollingResource longPollingResource) { - _longPollingResource = null; + public synchronized void deregisterRequest(WaitingRequest waitingRequest) { + _waitingRequest = null; } @Override - public synchronized void registerForChanges(LongPollingResource longPollingResource) { - _longPollingResource = longPollingResource; + public synchronized boolean registerRequest(WaitingRequest waitingRequest) { + if (_events.size()>0) + return true; + + _waitingRequest = waitingRequest; + return false; } private synchronized void appendEvent(GameEvent event) { _events.add(event); - if (_longPollingResource != null) - _longPollingResource.processIfNotProcessed(); + if (_waitingRequest != null) + _waitingRequest.processRequest(); } private int[] getCardIds(Collection cards) { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft/DraftCommunicationChannel.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft/DraftCommunicationChannel.java index c256a794d..1dfe6c8cb 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft/DraftCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/draft/DraftCommunicationChannel.java @@ -2,14 +2,15 @@ package com.gempukku.lotro.draft; import com.gempukku.lotro.game.CardCollection; import com.gempukku.polling.LongPollableResource; -import com.gempukku.polling.LongPollingResource; +import com.gempukku.polling.WaitingRequest; public class DraftCommunicationChannel implements LongPollableResource { private int _channelNumber; private long _lastAccessed; + private boolean _changed; private String _cardChoiceOnClient; - private LongPollingResource _longPollingResource; + private WaitingRequest _waitingRequest; public DraftCommunicationChannel(int channelNumber) { _channelNumber = channelNumber; @@ -28,18 +29,23 @@ public class DraftCommunicationChannel implements LongPollableResource { } @Override - public void deregisterResource(LongPollingResource longPollingResource) { - _longPollingResource = null; + public synchronized void deregisterRequest(WaitingRequest waitingRequest) { + _waitingRequest = null; } @Override - public void registerForChanges(LongPollingResource longPollingResource) { - _longPollingResource = longPollingResource; + public boolean registerRequest(WaitingRequest waitingRequest) { + if (_changed) + return true; + + _waitingRequest = waitingRequest; + return false; } public synchronized void draftChanged() { - if (_longPollingResource != null) - _longPollingResource.processIfNotProcessed(); + _changed = true; + if (_waitingRequest != null) + _waitingRequest.processRequest(); } public boolean hasChangesInCommunicationChannel(DraftCardChoice draftCardChoice) { @@ -59,7 +65,7 @@ public class DraftCommunicationChannel implements LongPollableResource { return sb.toString(); } - public void processCommunicationChannel(DraftCardChoice draftCardChoice, CardCollection chosenCards, DraftChannelVisitor draftChannelVisitor) { + public synchronized void processCommunicationChannel(DraftCardChoice draftCardChoice, CardCollection chosenCards, DraftChannelVisitor draftChannelVisitor) { updateLastAccess(); CardCollection cardCollection = draftCardChoice.getCardCollection(); @@ -72,5 +78,7 @@ public class DraftCommunicationChannel implements LongPollableResource { _cardChoiceOnClient = null; } draftChannelVisitor.chosenCards(chosenCards); + + _changed = false; } } diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ChatCommunicationChannel.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ChatCommunicationChannel.java index 22bb02166..b2ba858e8 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ChatCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/game/ChatCommunicationChannel.java @@ -3,7 +3,7 @@ package com.gempukku.lotro.game; import com.gempukku.lotro.chat.ChatMessage; import com.gempukku.lotro.chat.ChatRoomListener; import com.gempukku.polling.LongPollableResource; -import com.gempukku.polling.LongPollingResource; +import com.gempukku.polling.WaitingRequest; import java.util.LinkedList; import java.util.List; @@ -11,23 +11,27 @@ import java.util.List; public class ChatCommunicationChannel implements ChatRoomListener, LongPollableResource { private List _messages = new LinkedList(); private long _lastConsumed = System.currentTimeMillis(); - private LongPollingResource _longPollingResource; + private WaitingRequest _waitingRequest; @Override - public synchronized void deregisterResource(LongPollingResource longPollingResource) { - _longPollingResource = null; + public synchronized void deregisterRequest(WaitingRequest waitingRequest) { + _waitingRequest = null; } @Override - public synchronized void registerForChanges(LongPollingResource longPollingResource) { - _longPollingResource = longPollingResource; + public synchronized boolean registerRequest(WaitingRequest waitingRequest) { + if (_messages.size()>0) + return true; + + _waitingRequest = waitingRequest; + return false; } @Override public synchronized void messageReceived(ChatMessage message) { _messages.add(message); - if (_longPollingResource != null) - _longPollingResource.processIfNotProcessed(); + if (_waitingRequest != null) + _waitingRequest.processRequest(); } public synchronized List consumeMessages() { diff --git a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java index 5dbfe53a1..3a67c3c6d 100644 --- a/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java +++ b/gemp-lotr/gemp-lotr-server/src/main/java/com/gempukku/lotro/hall/HallCommunicationChannel.java @@ -2,7 +2,7 @@ package com.gempukku.lotro.hall; import com.gempukku.lotro.game.Player; import com.gempukku.polling.LongPollableResource; -import com.gempukku.polling.LongPollingResource; +import com.gempukku.polling.WaitingRequest; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.mutable.MutableObject; @@ -17,26 +17,30 @@ public class HallCommunicationChannel implements LongPollableResource { private Map> _tablePropsOnClient = new LinkedHashMap>(); private Set _playedGames = new HashSet(); private boolean _changed; - private LongPollingResource _longPollingResource; + private WaitingRequest _waitingRequest; public HallCommunicationChannel(int channelNumber) { _channelNumber = channelNumber; } @Override - public synchronized void deregisterResource(LongPollingResource longPollingResource) { - _longPollingResource = null; + public synchronized void deregisterRequest(WaitingRequest waitingRequest) { + _waitingRequest = null; } @Override - public synchronized void registerForChanges(LongPollingResource longPollingResource) { - _longPollingResource = longPollingResource; + public boolean registerRequest(WaitingRequest waitingRequest) { + if (_changed) + return true; + + _waitingRequest = waitingRequest; + return false; } public synchronized void hallChanged() { _changed = true; - if (_longPollingResource != null) - _longPollingResource.processIfNotProcessed(); + if (_waitingRequest != null) + _waitingRequest.processRequest(); } public int getChannelNumber() {