From 1b070f4e2a660a79ee8b5a310893a36c28aaf51c Mon Sep 17 00:00:00 2001 From: Adrian Siekierka Date: Sat, 3 Jun 2023 16:38:47 +0200 Subject: [PATCH] fix #3013 --- changelog.md | 3 ++- src/main/resources/application.conf | 4 ++++ src/main/scala/li/cil/oc/Settings.scala | 3 +++ .../scala/li/cil/oc/server/PacketSender.scala | 23 +++++++++++-------- 4 files changed, 23 insertions(+), 10 deletions(-) diff --git a/changelog.md b/changelog.md index 37b3f029e..974dc824b 100644 --- a/changelog.md +++ b/changelog.md @@ -1,6 +1,7 @@ ## Fixes/improvements * [#3620] Fixed OC 1.8.0+ regression involving API arguments and numbers. +* [#3013] Fixed rare server-side deadlock when sending disk activity update packets. ## OpenOS fixes/improvements @@ -9,4 +10,4 @@ ## List of contributors -asie, Possseidon +asie, ds84182, Possseidon diff --git a/src/main/resources/application.conf b/src/main/resources/application.conf index 15e178148..d00e362e9 100644 --- a/src/main/resources/application.conf +++ b/src/main/resources/application.conf @@ -1401,6 +1401,10 @@ opencomputers { # operation, it will block the computer for a duration matching the # limit set in this config option. transposerFluidTransferRate=4000 + + # Disk activity update packet delay specified in milliseconds. + # If set to -1, no disk activity update packets are sent. + diskActivityPacketDelay=500 } # Settings for mod integration (the mod previously known as OpenComponents). diff --git a/src/main/scala/li/cil/oc/Settings.scala b/src/main/scala/li/cil/oc/Settings.scala index c8cbac26d..81a3cea77 100644 --- a/src/main/scala/li/cil/oc/Settings.scala +++ b/src/main/scala/li/cil/oc/Settings.scala @@ -478,6 +478,9 @@ class Settings(val config: Config) { } val bitbltCost: Double = if (config.hasPath("gpu.bitbltCost")) config.getDouble("gpu.bitbltCost") else 0.5 + + // >= 1.8.2 + val diskActivityPacketDelay: Int = config.getInt("misc.diskActivityPacketDelay") max -1 } object Settings { diff --git a/src/main/scala/li/cil/oc/server/PacketSender.scala b/src/main/scala/li/cil/oc/server/PacketSender.scala index bf4ec0d47..bf0549c93 100644 --- a/src/main/scala/li/cil/oc/server/PacketSender.scala +++ b/src/main/scala/li/cil/oc/server/PacketSender.scala @@ -1,7 +1,7 @@ package li.cil.oc.server -import li.cil.oc.api -import li.cil.oc.api.event.{NetworkActivityEvent, FileSystemAccessEvent} +import li.cil.oc.{Settings, api} +import li.cil.oc.api.event.{FileSystemAccessEvent, NetworkActivityEvent} import li.cil.oc.api.network.EnvironmentHost import li.cil.oc.api.network.Node import li.cil.oc.common._ @@ -20,6 +20,7 @@ import net.minecraft.world.World import net.minecraftforge.common.MinecraftForge import net.minecraftforge.common.util.ForgeDirection +import java.util.concurrent.ConcurrentHashMap import scala.collection.mutable object PacketSender { @@ -125,19 +126,22 @@ object PacketSender { } // Avoid spamming the network with disk activity notices. - val fileSystemAccessTimeouts = mutable.WeakHashMap.empty[Node, mutable.Map[String, Long]] + private val fileSystemAccessTimeouts = mutable.WeakHashMap.empty[Node, ConcurrentHashMap[String, Long]] - def sendFileSystemActivity(node: Node, host: EnvironmentHost, name: String) = fileSystemAccessTimeouts.synchronized { - fileSystemAccessTimeouts.get(node) match { - case Some(hostTimeouts) if hostTimeouts.getOrElse(name, 0L) > System.currentTimeMillis() => // Cooldown. - case _ => + def sendFileSystemActivity(node: Node, host: EnvironmentHost, name: String) = { + val diskActivityPacketDelay = Settings.get.diskActivityPacketDelay + if (diskActivityPacketDelay >= 0) { + val hostTimeouts = fileSystemAccessTimeouts.synchronized { + fileSystemAccessTimeouts.getOrElseUpdate(node, new ConcurrentHashMap[String, Long](16, 0.75f, Settings.get.threads)) + } + if (hostTimeouts.getOrDefault(name, 0L) <= System.currentTimeMillis()) { val event = host match { case t: net.minecraft.tileentity.TileEntity => new FileSystemAccessEvent.Server(name, t, node) case _ => new FileSystemAccessEvent.Server(name, host.world, host.xPosition, host.yPosition, host.zPosition, node) } MinecraftForge.EVENT_BUS.post(event) if (!event.isCanceled) { - fileSystemAccessTimeouts.getOrElseUpdate(node, mutable.Map.empty) += name -> (System.currentTimeMillis() + 500) + hostTimeouts.put(name, System.currentTimeMillis() + diskActivityPacketDelay) val pb = new SimplePacketBuilder(PacketType.FileSystemActivity) @@ -157,8 +161,9 @@ object PacketSender { pb.sendToPlayersNearHost(host, Option(64)) } + } } - } +} def sendNetworkActivity(node: Node, host: EnvironmentHost) = {