Race condition with table creation and querying against it
Closed this issue · 0 comments
I added a new table to make it so players can vote by hitting a block. ("blocks", see PR #124 — I'm still not sure if this is the best way to do it since I'm fairly new to Minecraft plugin coding & Java).
On first run, when the Sqlite database and tables are created, the first time the code queries the table (in my case during command registration), I get the following "table does not exist" error. On subsequent runs, or on the first run if I do the query from another thread (i.e. while handling player join event), it works correctly.
The root cause is that the table is created asynchronously (see the implementation of Table.create()), so that it hasn't yet been created when the command registration runs and queries the table. I'm surprised that this isn't causing more issues with the existing tables, but maybe nothing is querying them right away.
[19:09:15 WARN]: org.sqlite.SQLiteException: [SQLITE_ERROR] SQL error or missing database (no such table: blocks)
[19:09:15 WARN]: at org.sqlite.core.DB.newSQLException(DB.java:1179)
[19:09:15 WARN]: at org.sqlite.core.DB.newSQLException(DB.java:1190)
[19:09:15 WARN]: at org.sqlite.core.DB.throwex(DB.java:1150)
[19:09:15 WARN]: at org.sqlite.core.NativeDB.prepare_utf8(Native Method)
[19:09:15 WARN]: at org.sqlite.core.NativeDB.prepare(NativeDB.java:126)
[19:09:15 WARN]: at org.sqlite.core.DB.prepare(DB.java:264)
[19:09:15 WARN]: at org.sqlite.jdbc3.JDBC3Statement.lambda$executeQuery$1(JDBC3Statement.java:81)
[19:09:15 WARN]: at org.sqlite.jdbc3.JDBC3Statement.withConnectionTimeout(JDBC3Statement.java:454)
[19:09:15 WARN]: at org.sqlite.jdbc3.JDBC3Statement.executeQuery(JDBC3Statement.java:79)
[19:09:15 WARN]: at elections-spigot.jar//me.lorenzo0111.elections.database.DatabaseManager.lambda$getElectionBlocks$11(DatabaseManager.java:399)
[19:09:15 WARN]: at org.bukkit.craftbukkit.v1_19_R3.scheduler.CraftTask.run(CraftTask.java:101)
[19:09:15 WARN]: at org.bukkit.craftbukkit.v1_19_R3.scheduler.CraftAsyncTask.run(CraftAsyncTask.java:57)
[19:09:15 WARN]: at com.destroystokyo.paper.ServerSchedulerReportingWrapper.run(ServerSchedulerReportingWrapper.java:22)
[19:09:15 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
[19:09:15 WARN]: at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
[19:09:15 WARN]: at java.base/java.lang.Thread.run(Thread.java:833)
There are two solutions I can think of:
- Pass the error back up the stack so the caller can decide what to do (i.e. wait and retry)
- Wait for the table to be created
I implemented the 2nd option in PR #124, and the issue no longer happens for me...