[Util] Better world saving!

Discussion in 'Resources' started by GermanCoding, Oct 14, 2013.

Thread Status:
Not open for further replies.
  1. Offline

    GermanCoding

    So, my first thread here in the resource section :)

    The mostly servers have plugins or something else to make a auto save. In the auto save, player and world data is saved to the disk. While the save runs, the server "freezes" so that you can't build or chat. This takes normally just < 1 second so it's not a problem. But now I'm working at a really big server with so many loaded chunks that the save takes sometimes over 5 seconds! One time, my horse died in the save, because of the lag, so that I decided to remove the lag in the save. As solution I made a new thread which calls the save methods. So the main thread wasn't affected. Here is my code:

    Code:java
    1. public class GameSaveThread extends Thread{
    2.  
    3. public GameSaveThread()
    4. {
    5. super();
    6. }
    7.  
    8. @Override
    9. public void run()
    10. {
    11. try{
    12. //Clone the players and save the data
    13. Player[] players = Bukkit.getOnlinePlayers().clone();
    14. for(Player p: players)
    15. {
    16. p.saveData();
    17. }
    18.  
    19. //Get a list of all worlds
    20. List<World> worlds = Bukkit.getWorlds();
    21. //A loop trough all worlds
    22. for(World w: worlds)
    23. {
    24. //Check wheter we can cast the org.bukkit.World to org.bukkit.craftbukkit.v_16_R3.CraftWorld
    25. if(w instanceof CraftWorld)
    26. {
    27. //Cast the world to craftbukkit code. Isn't perfect but I don't know a alternative solution.
    28. CraftWorld world = (CraftWorld) w;
    29.  
    30. //Check wheter we could save the world. If not wait and try again.
    31. IChunkProvider provider = world.getHandle().chunkProvider;
    32. while(!provider.canSave())
    33. {
    34. Thread.sleep(1);
    35. }
    36.  
    37. //Now we can save so we will do it.
    38. world.save();
    39. }
    40. else
    41. {
    42. //Can't cast the world. Can't make a secure save of the world.
    43. }
    44. }
    45. //Just for fun. It isn't necessary to call the garbage collector
    46. Runtime.getRuntime().gc();
    47. }catch(Throwable e)
    48. {
    49. //An error occured while saving the world. Try again...
    50. run();
    51. }
    52. }
    53. }


    This code works for me. Tested it 2.000 times without errors. You can see that I use craftbukkit code, because I want to check wheter I can save. If I just call "save()" the server throws sometimes a exception.

    On my server it works. You can optimize this code and upload it as a plugin if you want. Of course here is missing a way how to create and start the thread. I used the BukkitScheduler for it (Make a repeating task and this task start the thread) And I don't know wheter this code it is 100% error free.

    Note: Because of the "canSave()" check sometimes the save takes a few seconds.

    I would be happy if you help me to improve this code!
     
    TheGreenGamerHD likes this.
  2. Offline

    SacredWaste

    This seems really useful, I'm going to integrate it into my private plugin API incase I need to auto-save/save. Thanks.
     
  3. Offline

    Cirno

    This isn't probably safe at all since majority of CB/NMS isn't thread-safe.
     
  4. Offline

    Eats_Rainbows

    How efficient would this be with a say... 250gb world?
     
  5. Offline

    Garris0n

    How on earth could a world file ever get that big?
     
  6. Offline

    Ultimate_n00b

    Why not extend BukkitRunnable, and run it as async?
     
  7. Offline

    GermanCoding

    I made this exactly for such big worlds. I know that CB & NMS is mostly not threadsave and yesterday I saw, that calling
    Code:java
    1. provider.canSave()
    is useless. I'm actually working on another solution. But, if the save fails because of a ConcurrentModification, I made a loop which try again if it fails.
     
Thread Status:
Not open for further replies.

Share This Page