From 74809121fa16b7561749de1d474ba9e2e47dbbea Mon Sep 17 00:00:00 2001 From: Danny van Heumen Date: Sat, 16 Aug 2014 01:52:04 +0200 Subject: [PATCH] Timer now activates to clean up outdated chat room list cache. --- .../impl/protocol/irc/IrcStack.java | 112 +++++++++++++++++- 1 file changed, 109 insertions(+), 3 deletions(-) diff --git a/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java b/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java index 60308eadb..4d336afe5 100644 --- a/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java +++ b/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java @@ -40,6 +40,18 @@ */ public class IrcStack { + /** + * Clean-up delay. The clean up task clears any remaining chat room list + * cache. Since there's no pointing in timing it exactly, delay the clean up + * until after expiration. + */ + private static final long CACHE_CLEAN_UP_DELAY = 1000L; + + /** + * Ratio of milliseconds to nanoseconds for conversions. + */ + private static final long RATIO_MILLISECONDS_TO_NANOSECONDS = 1000000L; + /** * Expiration time for chat room list cache. */ @@ -519,10 +531,11 @@ public List getServerChatRoomList() } list = listSignal.getValue(); this.channellist.set(list); - // TODO Set a timer for past channel expiration delay and clean - // up outdated cached channel list. Because it won't be cleaned - // up if a user won't list server chat rooms again. LOGGER.trace("Finished retrieving server chat room list."); + + // Set timer to clean up the cache after use, since otherwise it + // could stay in memory for a long time. + createCleanUpJob(this.channellist); } else { @@ -532,6 +545,24 @@ public List getServerChatRoomList() } } + /** + * Create a clean up job that checks the container after the cache has + * expired. If the container is still populated, then remove it. This clean + * up makes sure that there are no references left to an otherwise useless + * list of channels. + * + * @param channellist the container carrying the list of channel names + */ + private static void createCleanUpJob( + final Container> channellist) + { + final Timer cleanUpJob = new Timer(); + final long timestamp = channellist.getTimestamp(); + cleanUpJob.schedule(new ChannelListCacheCleanUpTask(channellist, + timestamp), CHAT_ROOM_LIST_CACHE_EXPIRATION + / RATIO_MILLISECONDS_TO_NANOSECONDS + CACHE_CLEAN_UP_DELAY); + } + /** * Join a particular chat room. * @@ -2409,5 +2440,80 @@ public void set(final T instance) this.instance = instance; this.time = System.nanoTime(); } + + /** + * Get the timestamp from when the instance was set. + * + * @return returns the timestamp + */ + public long getTimestamp() + { + return this.time; + } + } + + /** + * Task for cleaning up old channel list caches. + * + * @author Danny van Heumen + */ + private static final class ChannelListCacheCleanUpTask + extends TimerTask + { + /** + * Expected timestamp on which the list cache was created. It is used as + * an indicator to see whether the cache has been refreshed in the mean + * time. + */ + private final long timestamp; + + /** + * Container holding the channel list cache. + */ + private final Container> container; + + /** + * Construct new clean up job definition. + * + * @param listContainer container that holds the channel list cache + * @param timestamp expected timestamp of list cache creation + */ + private ChannelListCacheCleanUpTask( + final Container> listContainer, final long timestamp) + { + if (listContainer == null) + { + throw new IllegalArgumentException( + "listContainer cannot be null"); + } + this.container = listContainer; + this.timestamp = timestamp; + } + + /** + * Remove the list reference from the container. But only if the + * timestamp matches. This makes sure that only one clean up job will + * clean up a list. + */ + @Override + public void run() + { + synchronized (this.container) + { + // Only clean up old cache if this is the dedicated task for it. + // If the timestamp has changed, another job is responsible for + // the clean up. + if (this.container.getTimestamp() != this.timestamp) + { + LOGGER.trace("Not cleaning up channel list cache. The " + + "timestamp does not match."); + return; + } + this.container.set(null); + } + // We cannot clear the list itself, since the contents might still + // be in use by the UI, inside the immutable wrapper. + LOGGER.debug("Old channel list cache has been cleared."); + } } }