getOfflinePlayer(String) is blocking yet not thread-safe

    • Type: Bug
    • Resolution: Fixed
    • Priority: Minor
    • None
    • Affects Version/s: None

      Spoke to md_5 on IRC about getOfflinePlayer(String) not being thread-safe. If a method is blocking, it is supposed to be thread-safe otherwise he says it is considered to be a bug.

      I wrote a simple plugin to observe failed attempts to invoke getOfflinePlayer() from multiple async tasks:

      GetOfflinePlayerAsyncTest.java
      package net.minelink.gopat;
      
      import org.bukkit.Bukkit;
      import org.bukkit.command.Command;
      import org.bukkit.command.CommandSender;
      import org.bukkit.plugin.java.JavaPlugin;
      
      import java.util.UUID;
      
      public class GetOfflinePlayerAsyncTest extends JavaPlugin {
      
          @Override
          public boolean onCommand(final CommandSender sender, Command command, String label, String[] args) {
              for (int i = 0; i < 3; ++i) {
                  Bukkit.getScheduler().runTaskLaterAsynchronously(this, new Runnable() {
                      @Override
                      public void run() {
                          Bukkit.getOfflinePlayer(UUID.randomUUID().toString().substring(0, 15));
                      }
                  }, 1);
              }
              return true;
          }
      
      }
      

      Invoking the above code will produce one of three outcomes:

      • It will simply work
      • It will throw a ConcurrentModificationException
      • It will throw a NullPointerException

      The stack traces observed in the console are as follows:

      ConcurrentModificationException

      [23:55:17 WARN]: Exception in thread "Craft Scheduler Thread - 0"
      [23:55:17 WARN]: org.apache.commons.lang.UnhandledException: Plugin GetOfflinePlayerAsyncTest v0.0.1-SNAPSHOT generated an exception while executing task 28
              at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:56)
              at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
              at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
              at java.lang.Thread.run(Thread.java:745)
      Caused by: java.util.ConcurrentModificationException
              at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:953)
              at java.util.LinkedList$ListItr.next(LinkedList.java:886)
              at com.google.common.collect.Iterators$9.next(Iterators.java:939)
              at com.google.common.collect.Iterators.addAll(Iterators.java:357)
              at com.google.common.collect.Lists.newArrayList(Lists.java:147)
              at net.minecraft.server.v1_8_R1.UserCache.a(UserCache.java:213)
              at net.minecraft.server.v1_8_R1.UserCache.c(UserCache.java:194)
              at net.minecraft.server.v1_8_R1.UserCache.getProfile(UserCache.java:123)
              at org.bukkit.craftbukkit.v1_8_R1.CraftServer.getOfflinePlayer(CraftServer.java:1288)
              at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741)
              at net.minelink.gopat.GetOfflinePlayerAsyncTest$1.run(GetOfflinePlayerAsyncTest.java:19)
              at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftTask.run(CraftTask.java:71)
              at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)
      

      NullPointerException

      [23:55:22 WARN]: Exception in thread "Craft Scheduler Thread - 3"
      [23:55:22 WARN]: org.apache.commons.lang.UnhandledException: Plugin GetOfflinePlayerAsyncTest v0.0.1-SNAPSHOT generated an exception while executing task 35
              at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:56)
              at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
              at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
              at java.lang.Thread.run(Thread.java:745)
      Caused by: java.lang.NullPointerException
              at java.util.LinkedList$ListItr.next(LinkedList.java:891)
              at com.google.common.collect.Iterators$9.next(Iterators.java:939)
              at com.google.common.collect.Iterators.addAll(Iterators.java:357)
              at com.google.common.collect.Lists.newArrayList(Lists.java:147)
              at net.minecraft.server.v1_8_R1.UserCache.a(UserCache.java:213)
              at net.minecraft.server.v1_8_R1.UserCache.c(UserCache.java:194)
              at net.minecraft.server.v1_8_R1.UserCache.getProfile(UserCache.java:123)
              at org.bukkit.craftbukkit.v1_8_R1.CraftServer.getOfflinePlayer(CraftServer.java:1288)
              at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741)
              at net.minelink.gopat.GetOfflinePlayerAsyncTest$1.run(GetOfflinePlayerAsyncTest.java:19)
              at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftTask.run(CraftTask.java:71)
              at org.bukkit.craftbukkit.v1_8_R1.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:53)
      

          [SPIGOT-461] getOfflinePlayer(String) is blocking yet not thread-safe

          Any update to this? Still an on-going issue with 1.8.6.

          Spigot 1.8.6 git-Spigot-6a6b839-b0e81a4
          ChestShop v3.8.8

          [23:10:18] [Server thread/INFO]: [ChestShop] Enabling ChestShop v3.8.8
          [23:10:18] [Server thread/ERROR]: Error occurred while enabling ChestShop v3.8.8 (Is it up to date?)
          java.util.ConcurrentModificationException
          	at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966) ~[?:1.8.0_45]
          	at java.util.LinkedList$ListItr.next(LinkedList.java:888) ~[?:1.8.0_45]
          	at com.google.common.collect.Iterators$9.next(Iterators.java:939) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at com.google.common.collect.Iterators.addAll(Iterators.java:357) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at com.google.common.collect.Lists.newArrayList(Lists.java:147) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at net.minecraft.server.v1_8_R3.UserCache.a(UserCache.java:235) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at net.minecraft.server.v1_8_R3.UserCache.c(UserCache.java:216) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at net.minecraft.server.v1_8_R3.UserCache.getProfile(UserCache.java:152) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at org.bukkit.craftbukkit.v1_8_R3.CraftServer.getOfflinePlayer(CraftServer.java:1304) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at com.Acrobot.ChestShop.UUIDs.NameManager.load(NameManager.java:234) ~[?:?]
          	at com.Acrobot.ChestShop.ChestShop.onEnable(ChestShop.java:95) ~[?:?]
          	at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:321) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:340) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:405) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at org.bukkit.craftbukkit.v1_8_R3.CraftServer.loadPlugin(CraftServer.java:356) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at org.bukkit.craftbukkit.v1_8_R3.CraftServer.enablePlugins(CraftServer.java:316) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at net.minecraft.server.v1_8_R3.MinecraftServer.s(MinecraftServer.java:418) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at net.minecraft.server.v1_8_R3.MinecraftServer.k(MinecraftServer.java:382) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at net.minecraft.server.v1_8_R3.MinecraftServer.a(MinecraftServer.java:337) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at net.minecraft.server.v1_8_R3.DedicatedServer.init(DedicatedServer.java:256) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:528) [spigot.jar:git-Spigot-6a6b839-b0e81a4]
          	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_45]
          

          Also occasionally occurs with EnjinMinecraftPlugin v2.7.2 at startup.

          [19:30:44] [Server thread/WARN]: [EnjinMinecraftPlugin] Task #79 for EnjinMinecraftPlugin v2.7.2-bukkit generated an exception
          java.util.ConcurrentModificationException
          	at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966) ~[?:1.8.0_40]
          	at java.util.LinkedList$ListItr.next(LinkedList.java:888) ~[?:1.8.0_40]
          	at com.google.common.collect.Iterators$9.next(Iterators.java:939) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at com.google.common.collect.Iterators.addAll(Iterators.java:357) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at com.google.common.collect.Lists.newArrayList(Lists.java:147) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at net.minecraft.server.v1_8_R2.UserCache.a(UserCache.java:243) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at net.minecraft.server.v1_8_R2.UserCache.c(UserCache.java:224) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at net.minecraft.server.v1_8_R2.UserCache.getProfile(UserCache.java:153) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at org.bukkit.craftbukkit.v1_8_R2.CraftServer.getOfflinePlayer(CraftServer.java:1304) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at com.enjin.officialplugin.EnjinMinecraftPlugin$1.run(EnjinMinecraftPlugin.java:862) ~[?:?]
          	at org.bukkit.craftbukkit.v1_8_R2.scheduler.CraftTask.run(CraftTask.java:71) ~[spigot.jar:git-Spigot-c136710-350cb99]
          	at org.bukkit.craftbukkit.v1_8_R2.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:350) [spigot.jar:git-Spigot-c136710-350cb99]
          	at net.minecraft.server.v1_8_R2.MinecraftServer.A(MinecraftServer.java:718) [spigot.jar:git-Spigot-c136710-350cb99]
          	at net.minecraft.server.v1_8_R2.DedicatedServer.A(DedicatedServer.java:368) [spigot.jar:git-Spigot-c136710-350cb99]
          	at net.minecraft.server.v1_8_R2.MinecraftServer.z(MinecraftServer.java:651) [spigot.jar:git-Spigot-c136710-350cb99]
          	at net.minecraft.server.v1_8_R2.MinecraftServer.run(MinecraftServer.java:554) [spigot.jar:git-Spigot-c136710-350cb99]
          	at java.lang.Thread.run(Thread.java:745) [?:1.8.0_40]
          

          mibby mibster added a comment - Any update to this? Still an on-going issue with 1.8.6. Spigot 1.8.6 git-Spigot-6a6b839-b0e81a4 ChestShop v3.8.8 [23:10:18] [Server thread/INFO]: [ChestShop] Enabling ChestShop v3.8.8 [23:10:18] [Server thread/ERROR]: Error occurred while enabling ChestShop v3.8.8 (Is it up to date?) java.util.ConcurrentModificationException at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966) ~[?:1.8.0_45] at java.util.LinkedList$ListItr.next(LinkedList.java:888) ~[?:1.8.0_45] at com.google.common.collect.Iterators$9.next(Iterators.java:939) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at com.google.common.collect.Iterators.addAll(Iterators.java:357) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at com.google.common.collect.Lists.newArrayList(Lists.java:147) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at net.minecraft.server.v1_8_R3.UserCache.a(UserCache.java:235) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at net.minecraft.server.v1_8_R3.UserCache.c(UserCache.java:216) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at net.minecraft.server.v1_8_R3.UserCache.getProfile(UserCache.java:152) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at org.bukkit.craftbukkit.v1_8_R3.CraftServer.getOfflinePlayer(CraftServer.java:1304) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at com.Acrobot.ChestShop.UUIDs.NameManager.load(NameManager.java:234) ~[?:?] at com.Acrobot.ChestShop.ChestShop.onEnable(ChestShop.java:95) ~[?:?] at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:321) ~[spigot.jar:git-Spigot-6a6b839-b0e81a4] at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:340) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:405) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at org.bukkit.craftbukkit.v1_8_R3.CraftServer.loadPlugin(CraftServer.java:356) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at org.bukkit.craftbukkit.v1_8_R3.CraftServer.enablePlugins(CraftServer.java:316) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at net.minecraft.server.v1_8_R3.MinecraftServer.s(MinecraftServer.java:418) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at net.minecraft.server.v1_8_R3.MinecraftServer.k(MinecraftServer.java:382) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at net.minecraft.server.v1_8_R3.MinecraftServer.a(MinecraftServer.java:337) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at net.minecraft.server.v1_8_R3.DedicatedServer.init(DedicatedServer.java:256) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at net.minecraft.server.v1_8_R3.MinecraftServer.run(MinecraftServer.java:528) [spigot.jar:git-Spigot-6a6b839-b0e81a4] at java.lang. Thread .run( Thread .java:745) [?:1.8.0_45] Also occasionally occurs with EnjinMinecraftPlugin v2.7.2 at startup. [19:30:44] [Server thread/WARN]: [EnjinMinecraftPlugin] Task #79 for EnjinMinecraftPlugin v2.7.2-bukkit generated an exception java.util.ConcurrentModificationException at java.util.LinkedList$ListItr.checkForComodification(LinkedList.java:966) ~[?:1.8.0_40] at java.util.LinkedList$ListItr.next(LinkedList.java:888) ~[?:1.8.0_40] at com.google.common.collect.Iterators$9.next(Iterators.java:939) ~[spigot.jar:git-Spigot-c136710-350cb99] at com.google.common.collect.Iterators.addAll(Iterators.java:357) ~[spigot.jar:git-Spigot-c136710-350cb99] at com.google.common.collect.Lists.newArrayList(Lists.java:147) ~[spigot.jar:git-Spigot-c136710-350cb99] at net.minecraft.server.v1_8_R2.UserCache.a(UserCache.java:243) ~[spigot.jar:git-Spigot-c136710-350cb99] at net.minecraft.server.v1_8_R2.UserCache.c(UserCache.java:224) ~[spigot.jar:git-Spigot-c136710-350cb99] at net.minecraft.server.v1_8_R2.UserCache.getProfile(UserCache.java:153) ~[spigot.jar:git-Spigot-c136710-350cb99] at org.bukkit.craftbukkit.v1_8_R2.CraftServer.getOfflinePlayer(CraftServer.java:1304) ~[spigot.jar:git-Spigot-c136710-350cb99] at org.bukkit.Bukkit.getOfflinePlayer(Bukkit.java:741) ~[spigot.jar:git-Spigot-c136710-350cb99] at com.enjin.officialplugin.EnjinMinecraftPlugin$1.run(EnjinMinecraftPlugin.java:862) ~[?:?] at org.bukkit.craftbukkit.v1_8_R2.scheduler.CraftTask.run(CraftTask.java:71) ~[spigot.jar:git-Spigot-c136710-350cb99] at org.bukkit.craftbukkit.v1_8_R2.scheduler.CraftScheduler.mainThreadHeartbeat(CraftScheduler.java:350) [spigot.jar:git-Spigot-c136710-350cb99] at net.minecraft.server.v1_8_R2.MinecraftServer.A(MinecraftServer.java:718) [spigot.jar:git-Spigot-c136710-350cb99] at net.minecraft.server.v1_8_R2.DedicatedServer.A(DedicatedServer.java:368) [spigot.jar:git-Spigot-c136710-350cb99] at net.minecraft.server.v1_8_R2.MinecraftServer.z(MinecraftServer.java:651) [spigot.jar:git-Spigot-c136710-350cb99] at net.minecraft.server.v1_8_R2.MinecraftServer.run(MinecraftServer.java:554) [spigot.jar:git-Spigot-c136710-350cb99] at java.lang. Thread .run( Thread .java:745) [?:1.8.0_40]

          Would very much greatly appreciate getOfflinePlayer check becoming async and thread safe to prevent ConcurrentModificationExceptions on server startup.

          As I'm still experiencing this issue myself with Spigot 1.8.3 (git-Spigot-ea179b3-6e0120a) and ChestShops 3.8.5.
          https://hub.spigotmc.org/jira/browse/SPIGOT-646

          mibby mibster added a comment - Would very much greatly appreciate getOfflinePlayer check becoming async and thread safe to prevent ConcurrentModificationExceptions on server startup. As I'm still experiencing this issue myself with Spigot 1.8.3 (git-Spigot-ea179b3-6e0120a) and ChestShops 3.8.5. https://hub.spigotmc.org/jira/browse/SPIGOT-646

          Any update to making this thread-safe?

          https://hub.spigotmc.org/jira/browse/SPIGOT-646

          mibby mibster added a comment - Any update to making this thread-safe? https://hub.spigotmc.org/jira/browse/SPIGOT-646

            Assignee:
            md_5
            Reporter:
            Matt Harris
            Votes:
            4 Vote for this issue
            Watchers:
            5 Start watching this issue

              Created:
              Updated:
              Resolved: