From 1b8fe6bba830cfa803e8aea4b263488ad9210331 Mon Sep 17 00:00:00 2001 From: Mike Primm Date: Fri, 9 Dec 2011 13:21:36 +0800 Subject: [PATCH] Scrub obsolete events from update queue (reduce traffic) --- src/main/java/org/dynmap/Client.java | 59 ++++++++++++ src/main/java/org/dynmap/UpdateQueue.java | 96 +++++++++++++++---- .../dynmap/markers/impl/MarkerAPIImpl.java | 38 ++++++++ 3 files changed, 172 insertions(+), 21 deletions(-) diff --git a/src/main/java/org/dynmap/Client.java b/src/main/java/org/dynmap/Client.java index 5f7e905f..fe76663c 100644 --- a/src/main/java/org/dynmap/Client.java +++ b/src/main/java/org/dynmap/Client.java @@ -39,6 +39,18 @@ public class Client { this.account = playeraccount; this.channel = channel; } + @Override + public boolean equals(Object o) { + if(o instanceof ChatMessage) { + ChatMessage m = (ChatMessage)o; + return m.source.equals(source) && m.playerName.equals(playerName) && m.message.equals(message); + } + return false; + } + @Override + public int hashCode() { + return source.hashCode() ^ playerName.hashCode() ^ message.hashCode(); + } } public static class PlayerJoinMessage extends Update { @@ -49,6 +61,18 @@ public class Client { this.playerName = ChatColor.stripColor(playerName); this.account = playeraccount; } + @Override + public boolean equals(Object o) { + if(o instanceof PlayerJoinMessage) { + PlayerJoinMessage m = (PlayerJoinMessage)o; + return m.playerName.equals(playerName); + } + return false; + } + @Override + public int hashCode() { + return playerName.hashCode(); + } } public static class PlayerQuitMessage extends Update { @@ -59,6 +83,18 @@ public class Client { this.playerName = ChatColor.stripColor(playerName); this.account = playeraccount; } + @Override + public boolean equals(Object o) { + if(o instanceof PlayerQuitMessage) { + PlayerQuitMessage m = (PlayerQuitMessage)o; + return m.playerName.equals(playerName); + } + return false; + } + @Override + public int hashCode() { + return playerName.hashCode(); + } } public static class Tile extends Update { @@ -68,6 +104,18 @@ public class Client { public Tile(String name) { this.name = name; } + @Override + public boolean equals(Object o) { + if(o instanceof Tile) { + Tile m = (Tile)o; + return m.name.equals(name); + } + return false; + } + @Override + public int hashCode() { + return name.hashCode(); + } } public static class DayNight extends Update { @@ -77,6 +125,17 @@ public class Client { public DayNight(boolean isday) { this.isday = isday; } + @Override + public boolean equals(Object o) { + if(o instanceof DayNight) { + return true; + } + return false; + } + @Override + public int hashCode() { + return 12345; + } } public static class ComponentMessage extends Update { diff --git a/src/main/java/org/dynmap/UpdateQueue.java b/src/main/java/org/dynmap/UpdateQueue.java index 96870707..64728d82 100644 --- a/src/main/java/org/dynmap/UpdateQueue.java +++ b/src/main/java/org/dynmap/UpdateQueue.java @@ -1,31 +1,56 @@ package org.dynmap; import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; +import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.ListIterator; public class UpdateQueue { public Object lock = new Object(); - private LinkedList updateQueue = new LinkedList(); - + private HashMap updateSet = new HashMap(); + private UpdateRec orderedlist = null; /* Oldest to youngest */ private static final long maxUpdateAge = 120000; private static final long ageOutPeriod = 5000; - private long lastageout = 0; + private static class UpdateRec { + Client.Update u; + UpdateRec next; + UpdateRec prev; + + @Override + public boolean equals(Object o) { + if(o instanceof UpdateRec) + return u.equals(((UpdateRec)o).u); + return false; + } + @Override + public int hashCode() { + return u.hashCode(); + } + } + private void doAgeOut(long now) { /* If we're due */ if((now < lastageout) || (now > (lastageout + ageOutPeriod))) { lastageout = now; long deadline = now - maxUpdateAge; - ListIterator i = updateQueue.listIterator(0); - while (i.hasNext()) { - Client.Update u = i.next(); - if (u.timestamp < deadline) - i.remove(); - else - break; + while((orderedlist != null) && (orderedlist.u.timestamp < deadline)) { + UpdateRec r = orderedlist; + + updateSet.remove(r); /* Remove record from set */ + if(r.next == r) { + orderedlist = null; + } + else { + orderedlist = r.next; + r.next.prev = r.prev; + r.prev.next = r.next; + } + r.next = r.prev = null; } } } @@ -35,7 +60,33 @@ public class UpdateQueue { /* Do inside lock - prevent delay between time and actual work */ long now = System.currentTimeMillis(); doAgeOut(now); /* Consider age out */ - updateQueue.addLast(obj); + UpdateRec r = new UpdateRec(); + r.u = obj; + UpdateRec oldr = updateSet.remove(r); /* Try to remove redundant event */ + if(oldr != null) { /* If found, remove from ordered list too */ + if(oldr.next == oldr) { /* Only one? */ + orderedlist = null; + } + else { + if(orderedlist == oldr) { /* We're oldest? */ + orderedlist = oldr.next; + } + oldr.next.prev = oldr.prev; + oldr.prev.next = oldr.next; + } + oldr.next = oldr.prev = null; + } + updateSet.put(r, r); + /* Add to end of ordered list */ + if(orderedlist == null) { + orderedlist = r; + r.next = r.prev = r; + } + else { + r.next = orderedlist; + r.prev = orderedlist.prev; + r.next.prev = r.prev.next = r; + } } } @@ -48,18 +99,21 @@ public class UpdateQueue { doAgeOut(now); /* Consider age out */ tmpupdates.clear(); - Iterator it = updateQueue.descendingIterator(); - while (it.hasNext()) { - Client.Update u = it.next(); - if (u.timestamp >= since) { - // Tile is new. - tmpupdates.add(u); - } - else { - break; + if(orderedlist != null) { + UpdateRec r = orderedlist.prev; /* Get newest */ + while(r != null) { + if(r.u.timestamp >= since) { + tmpupdates.add(r.u); + if(r == orderedlist) + r = null; + else + r = r.prev; + } + else { + r = null; + } } } - // Reverse output. updates = new Client.Update[tmpupdates.size()]; for (int i = 0; i < updates.length; i++) { diff --git a/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java index e8c504b3..ac3e25a9 100644 --- a/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java +++ b/src/main/java/org/dynmap/markers/impl/MarkerAPIImpl.java @@ -37,6 +37,7 @@ import org.dynmap.Event; import org.dynmap.Log; import org.dynmap.MapManager; import org.dynmap.Client.ComponentMessage; +import org.dynmap.Client.PlayerJoinMessage; import org.dynmap.markers.AreaMarker; import org.dynmap.markers.Marker; import org.dynmap.markers.MarkerAPI; @@ -104,6 +105,19 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { else msg = "markerupdated"; } + @Override + public boolean equals(Object o) { + if(o instanceof MarkerUpdated) { + MarkerUpdated m = (MarkerUpdated)o; + return m.id.equals(id) && m.set.equals(set); + } + return false; + } + @Override + public int hashCode() { + return id.hashCode() ^ set.hashCode(); + } + } public static class AreaMarkerUpdated extends MarkerComponentMessage { @@ -146,6 +160,18 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { else msg = "areaupdated"; } + @Override + public boolean equals(Object o) { + if(o instanceof AreaMarkerUpdated) { + AreaMarkerUpdated m = (AreaMarkerUpdated)o; + return m.id.equals(id) && m.set.equals(set); + } + return false; + } + @Override + public int hashCode() { + return id.hashCode() ^ set.hashCode(); + } } public static class MarkerSetUpdated extends MarkerComponentMessage { @@ -160,6 +186,18 @@ public class MarkerAPIImpl implements MarkerAPI, Event.Listener { else msg = "setupdated"; } + @Override + public boolean equals(Object o) { + if(o instanceof MarkerSetUpdated) { + MarkerSetUpdated m = (MarkerSetUpdated)o; + return m.id.equals(id); + } + return false; + } + @Override + public int hashCode() { + return id.hashCode(); + } } private boolean stop = false;