mojira.dev
MC-10204

MemoryConnection has an extremly poor collection choice

I'm sure these variables have other names internal to minecraft, but i'll refer to them by their MCP name.

readPacketCache is a synchronized array list. Items are removed from it in a read function by readPacketCache.remove(0). This a) blocks all access to the object and b) causes every element to be copied into a lower index, making this an order N operation.
This makes reading N items from the "queue" an O(N^2) operation, holding a lock for each O(N) operation.
This means that under high load, insert to the queue is an O(N) operation, with a high overhead, while it waits for the lock.

the java concurrentLinkedQueue is an unbounded queue designed for exactly this situation with constant time, lock-free push/pull concurrently (several threads can push and pull at the same time without causing any of them to block).

Changing this code does not cause any other code to need to be changed, as it is a private variable, and INetworkManager's are ALWAYS accessed via their interface, because it could be a Memory or a TCP connection, and the code doesn't know which.

this is cross-posted as a patch to fml - https://github.com/MinecraftForge/FML/issues/189

I have tested this in my MCP install, with both buildcraft and other mods active, with no problems.

package net.minecraft.network;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import net.minecraft.network.packet.NetHandler;
import net.minecraft.network.packet.Packet;

public class MemoryConnection implements INetworkManager
{
    private static final SocketAddress mySocketAddress = new InetSocketAddress("127.0.0.1", 0);
    private final Queue<Packet> readPacketCache = new ConcurrentLinkedQueue<Packet>();
    private MemoryConnection pairedConnection;
    private NetHandler myNetHandler;

    /** set to true by {server,network}Shutdown */
    private boolean shuttingDown = false;
    private String shutdownReason = "";
    private Object[] field_74439_g;
    private boolean gamePaused = false;

<snip - unchanged functions removed>
    /**
     * Checks timeouts and processes all pending read packets.
     */
    public void processReadPackets()
    {
        int var1 = 2500;

        while (var1-- >= 0 && !this.readPacketCache.isEmpty())
        {
            Packet var2 = this.readPacketCache.poll();
            var2.processPacket(this.myNetHandler);
        }

        if (this.readPacketCache.size() > var1)
        {
            System.out.println("Memory connection overburdened; after processing 2500 packets, we still have " + this.readPacketCache.size() + " to go!");
        }

        if (this.shuttingDown && this.readPacketCache.isEmpty())
        {
            this.myNetHandler.handleErrorMessage(this.shutdownReason, this.field_74439_g);
        }
    }
<snip - more unchanged functions removed>
}
--

@@ -7,7 +7,7 @@
 import java.net.InetSocketAddress;
 import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
 import net.minecraft.network.packet.NetHandler;
 import net.minecraft.network.packet.Packet;
@@ -16,5 +16,5 @@
 {
     private static final SocketAddress mySocketAddress = new InetSocketAddress("127.0.0.1", 0);
-    private final List readPacketCache = Collections.synchronizedList(new ArrayList());
+    private final Queue<Packet> readPacketCache = new ConcurrentLinkedQueue<Packet>();
     private MemoryConnection pairedConnection;
     private NetHandler myNetHandler;
@@ -77,5 +77,5 @@
         while (var1-- >= 0 && !this.readPacketCache.isEmpty())
         {
-            Packet var2 = (Packet)this.readPacketCache.remove(0);
+            Packet var2 = this.readPacketCache.poll();
             var2.processPacket(this.myNetHandler);
         }

Linked issues

Comments 15

Please put the code in {noformat}

Also, this is a feature request, technically. Not a bug.

Not a feature request. Feature request is intended to change the functionality. This suggestion intends to improve a very bad implementation without any change to functionality.

This as close to a bug one can get without it being fully one. Lets just say, one would not pass the relevant exercise in university programming course if this mistake had been done.

In addition to wrapping the code inside {code}, I'd add a significant missing info in the begin of the descriptions: "readPacketCache is a synchronized array list".

Ok fine, but this still isn't a bug. A bug is something that is broken about the game, not something that is badly implemented. This site is for bugs. In fact, you labeled it as a bug!

Also, the {noformat} tags don't turn it into an IDE like environment, all it does is make it so that Tabs are actually tabs, not bullet points.

5 more comments

Still valid for 1.5 (has the same piece of code).

Deleted account

Is this still a concern in the current Minecraft version 14w11b / Launcher version 1.3.11 or later? If so, please update the affected versions in order to best aid Mojang ensuring bugs are still valid in the latest releases/pre-releases.

Considering that there is now another bug for getting exceptions with single player mode, apparently caused by firewall blocking localhost connection, it would seem that the memory connection might not be currently used. However, I haven't checked this assumption. And without access to an up to date MCP, I can not confirm the situation in any meaningful way. (Or well, I could, but it would take hours, while Mojang could both check and fix this in less than few minutes... so... yeah, better ask Mojang about the status.)

Is this still a concern in the current Minecraft version 1.8.1 Prerelease 3 / Launcher version 1.5.3 or later? If so, please update the affected versions in order to best aid Mojang ensuring bugs are still valid in the latest releases/pre-releases.

No response for over a year.

Andrew Hill

(Unassigned)

Unconfirmed

cpu, performance, singleplayer

Minecraft 1.4.7, Minecraft 1.5

Retrieved