Don't use own thread for drive syncing to disk, use Minecraft's background executor instead

This commit is contained in:
DBotThePony 2023-08-16 19:39:12 +07:00
parent 8e03b4363d
commit 4430fdcb6b
Signed by: DBot
GPG Key ID: DCC23B5715498507
3 changed files with 7 additions and 54 deletions

View File

@ -142,8 +142,6 @@ public final class OverdriveThatMatters {
} }
private void setup(final FMLCommonSetupEvent event) { private void setup(final FMLCommonSetupEvent event) {
EVENT_BUS.addListener(EventPriority.HIGHEST, DrivePool.INSTANCE::serverStopEvent);
EVENT_BUS.addListener(EventPriority.LOWEST, DrivePool.INSTANCE::serverStartEvent);
EVENT_BUS.addListener(EventPriority.NORMAL, DrivePool.INSTANCE::onWorldSave); EVENT_BUS.addListener(EventPriority.NORMAL, DrivePool.INSTANCE::onWorldSave);
EVENT_BUS.addListener(EventPriority.HIGHEST, GlobalEventHandlerKt::onServerStopped); EVENT_BUS.addListener(EventPriority.HIGHEST, GlobalEventHandlerKt::onServerStopped);

View File

@ -6,6 +6,7 @@ import net.minecraft.ReportedException
import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.CompoundTag
import net.minecraft.nbt.NbtIo import net.minecraft.nbt.NbtIo
import net.minecraft.CrashReport import net.minecraft.CrashReport
import net.minecraft.Util
import net.minecraft.world.level.storage.LevelResource import net.minecraft.world.level.storage.LevelResource
import java.util.concurrent.locks.LockSupport import java.util.concurrent.locks.LockSupport
import net.minecraftforge.event.server.ServerAboutToStartEvent import net.minecraftforge.event.server.ServerAboutToStartEvent
@ -14,6 +15,7 @@ import net.minecraftforge.event.level.LevelEvent
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER import ru.dbotthepony.mc.otm.NULLABLE_MINECRAFT_SERVER
import ru.dbotthepony.mc.otm.SERVER_IS_LIVE import ru.dbotthepony.mc.otm.SERVER_IS_LIVE
import ru.dbotthepony.mc.otm.isServerThread
import java.io.File import java.io.File
import java.lang.ref.WeakReference import java.lang.ref.WeakReference
import java.util.ArrayList import java.util.ArrayList
@ -61,14 +63,10 @@ object DrivePool {
private val resource = LevelResource("otm_drives") private val resource = LevelResource("otm_drives")
private val LOGGER = LogManager.getLogger() private val LOGGER = LogManager.getLogger()
private val pool = Object2ObjectOpenHashMap<UUID, WeakDriveReference>() private val pool = Object2ObjectOpenHashMap<UUID, WeakDriveReference>()
private var thread: Thread? = null
private var stopping = false
private val backlog = ConcurrentLinkedQueue<BacklogLine>() private val backlog = ConcurrentLinkedQueue<BacklogLine>()
private var knownBaseDirectory: File? = null private var knownBaseDirectory: File? = null
private var serverThread: Thread? = null
private val baseDirectory: File? get() { private val baseDirectory: File? get() {
val server = NULLABLE_MINECRAFT_SERVER ?: return null val server = NULLABLE_MINECRAFT_SERVER ?: return null
@ -83,7 +81,7 @@ object DrivePool {
} }
operator fun <T : IMatteryDrive<*>> get(id: UUID, deserializer: (CompoundTag) -> T, factory: () -> T): T { operator fun <T : IMatteryDrive<*>> get(id: UUID, deserializer: (CompoundTag) -> T, factory: () -> T): T {
if (!isLegalAccess()) if (!isServerThread())
throw IllegalAccessException("Can not access drive pool from outside of server thread.") throw IllegalAccessException("Can not access drive pool from outside of server thread.")
if (!SERVER_IS_LIVE) if (!SERVER_IS_LIVE)
@ -115,47 +113,11 @@ object DrivePool {
} }
fun markDirty(id: UUID) { fun markDirty(id: UUID) {
if (isLegalAccess()) { if (isServerThread()) {
pool[id]?.access() pool[id]?.access()
} }
} }
/**
* Returns whenever running on server thread. Calling [get], [put] or [markDirty] will throw an exception if this returns false.
*
* If you are making your own drive for your own storage stack, feed code outside of server thread (e.g. client code) dummy disk.
*/
fun isLegalAccess(): Boolean {
return serverThread != null && Thread.currentThread() === serverThread
}
fun serverStartEvent(event: ServerAboutToStartEvent) {
if (thread?.isAlive == true) {
LOGGER.error("FMLServerStartedEvent fired twice.")
LOGGER.error("Attempting to start another DrivePool I/O thread when already running one!")
return
}
pool.clear()
serverThread = Thread.currentThread()
stopping = false
thread = Thread(null, this::run, "Overdrive That Matters DrivePool IO").also { it.start() }
}
fun serverStopEvent(event: ServerStoppingEvent) {
val thread = thread
if (thread != null && thread.isAlive) {
stopping = true
LockSupport.unpark(thread)
}
writeBacklog()
sync()
pool.clear()
}
fun onWorldSave(event: LevelEvent.Save) { fun onWorldSave(event: LevelEvent.Save) {
writeBacklog() writeBacklog()
} }
@ -185,14 +147,7 @@ object DrivePool {
} }
if (needsSync) { if (needsSync) {
LockSupport.unpark(thread) Util.backgroundExecutor().execute(::sync)
}
}
private fun run() {
while (!stopping) {
sync()
LockSupport.park()
} }
} }

View File

@ -1,6 +1,5 @@
package ru.dbotthepony.mc.otm.item package ru.dbotthepony.mc.otm.item
import ru.dbotthepony.mc.otm.capability.drive.DrivePool.isLegalAccess
import net.minecraft.world.item.ItemStack import net.minecraft.world.item.ItemStack
import net.minecraftforge.common.capabilities.ICapabilityProvider import net.minecraftforge.common.capabilities.ICapabilityProvider
import net.minecraftforge.common.util.LazyOptional import net.minecraftforge.common.util.LazyOptional
@ -24,6 +23,7 @@ import ru.dbotthepony.mc.otm.container.ItemFilter
import ru.dbotthepony.mc.otm.core.nbt.map import ru.dbotthepony.mc.otm.core.nbt.map
import ru.dbotthepony.mc.otm.core.nbt.set import ru.dbotthepony.mc.otm.core.nbt.set
import ru.dbotthepony.mc.otm.core.tagNotNull import ru.dbotthepony.mc.otm.core.tagNotNull
import ru.dbotthepony.mc.otm.isServerThread
import java.math.BigInteger import java.math.BigInteger
import java.util.* import java.util.*
@ -35,7 +35,7 @@ class PortableCondensationDriveItem(capacity: Int) :
private var uuid: UUID? = null private var uuid: UUID? = null
private val resolver = LazyOptional.of<IMatteryDrive<*>> { private val resolver = LazyOptional.of<IMatteryDrive<*>> {
if (!isLegalAccess()) { if (!isServerThread()) {
return@of ItemMatteryDrive.DUMMY return@of ItemMatteryDrive.DUMMY
} }