Search Unity

Save on Suspend can Catastrophically Fail

Discussion in 'Android' started by Peacewise, Aug 14, 2017.

  1. Peacewise

    Peacewise

    Joined:
    Feb 27, 2014
    Posts:
    52
    I have a game with a home "Camp" that players spend a long time in, and I want to save any progress they make without having to write out save files after every single action, since that could be up to 1 time per second.

    Here is how save currently works in my game:
    1. If the player exits camp, a save is kicked off. This works fine, as the game is still running.
    2. If the app suspends (multitask, phone call, etc) Unity gets the OnApplicationPause event, and in this case, I also kick off a Save. This is important because the app can go into the background, and may get wiped from memory.
    3. When saving initiates, I manually write out save files in binary using EZ Save. They are written to a temporary location. There are only a few files to write, and the total size is pretty small, less than 50 kb.
    4. If there were no errors during writing the save files, then they are copied from the temp location to the real location.
    This actually works the vast majority of the time. On iOS, it is nearly flawless. On Android, there is an occasional problem.

    The Problem:
    • On rare occasions, the player ends up with one or more of the files in the save being truncated. The beginning of a file is written, and at some point, the rest is cut off. The player's game is corrupted.
    • My speculation on what happens is that the game is copying over save files from the temp location to the proper location, and the OS decides, "Okay, that's enough time, I'm shutting you down," or "I need your memory, stop whatever you're doing."
    Questions:
    1. Is there any way to guarantee that I can write out a save file on suspend without being interrupted?
    2. Is there something else I should be doing to guarantee all data gets saved, but without potential for corruption?
    3. Is there any kind of atomic file copy I could use, something that can't be interrupted?
    Any help or advice is appreciated!
     
    Last edited: Aug 16, 2017
  2. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    Are you copying files from temp to real instead of moving them?
    Can you show the code you use for copy/move?
     
  3. Peacewise

    Peacewise

    Joined:
    Feb 27, 2014
    Posts:
    52
    I already see what you're getting at, that a file copy would be time intensive compared to a move.

    I am indeed using an actual copy, not a move. It overwrites any older save file. Here is the relevant code:
    Code (CSharp):
    1.             System.IO.File.Copy(tempLocation, realLocation, true);
    So I should probably instead delete the old file, then use a System.IO.File.Move? Does that sound right?
     
  4. Peacewise

    Peacewise

    Joined:
    Feb 27, 2014
    Posts:
    52
    Update:

    I have now tested a file Move version, and compared it to the Copy version using System.Diagnostics.Stopwatch. I've done the comparison on device. The results are interesting.
    • Using System.IO.File.Copy x7 files (with file overwrite) takes ~5ms to run on average.
    • Using System.IO.File.Move x7 files also takes ~5ms to run on average.
    Each save has 7 files, so that's where the 7 comes from. And these are with the relatively small files I mentioned (most are just a few KB, which is perhaps why the times are similar). With this test these calls have no noticeable difference from each other.

    So I'm still left looking for a better solution for saving that uses less time or can in some way guaranteed the operation will complete. Any additional advice is welcome!
     
  5. Aurimas-Cernius

    Aurimas-Cernius

    Unity Technologies

    Joined:
    Jul 31, 2013
    Posts:
    3,735
    The better approach IMO would be to save new files alongside the old ones using a different extension. When done, delete original files and rename the new ones. Even if this process breaks at some point. you can simply look at what files you do have in that directory and either complete the process before loading or load old files assuming new ones might be corrupted (the case when ALL old files are still present).
     
  6. Peacewise

    Peacewise

    Joined:
    Feb 27, 2014
    Posts:
    52
    Thank you for your help Aurimas, I now have a revised solution that looks sound.