How are these methods allowing / causing data to be lost on disk?

北战南征 提交于 2019-12-08 12:37:42

问题


I have a program that writes its settings and data out to disk every so often (15 seconds or so).

If the program is running and the computer is shut off abruptly -- for example, with the power being cut at the wall -- somehow all of my data files on disk are changed to empty files.

Here is my code, which I thought I designed to protect against this failure, but based on testing the failure still exists:

SaveAllData -- Called every so often, and also when JavaFX.Application.stop() is called.

public void saveAllData () {
    createNecessaryFolders();
    saveAlbumsAndTracks();
    saveSources();
    saveCurrentList();
    saveQueue();
    saveHistory();
    saveLibraryPlaylists();
    saveSettings();
    saveHotkeys();
}

CreateNecessaryFolders

private void createNecessaryFolders () {
    if ( !playlistsDirectory.exists() ) {
        boolean playlistDir = playlistsDirectory.mkdirs();
    }
}

Save Functions -- they all look just like this

public void saveCurrentList () {
    File tempCurrentFile = new File ( currentFile.toString() + ".temp" );
    try ( ObjectOutputStream currentListOut = new ObjectOutputStream( new FileOutputStream( tempCurrentFile ) ) ) {
        currentListOut.writeObject( player.getCurrentList().getState() );
        currentListOut.flush();
        currentListOut.close();

        Files.move( tempCurrentFile.toPath(), currentFile.toPath(), StandardCopyOption.REPLACE_EXISTING );

    } catch ( Exception e ) {
        LOGGER.warning( e.getClass().getCanonicalName() + ": Unable to save current list to disk, continuing." );
    }
}

Github repository to commit where this problem exists. See Persister.java.

As I said, when the power is cut abruptly all setting files saved by this method are blanked. This makes particularly no sense to me, since they are called in sequence and I am making sure the file is written to disk and flushed before calling move().

Any idea how this could be happening? I thought by calling flush, close, then move, I would ensure that the data is written to disk before overwriting the old data. Somehow, this isn't the case, but I am clueless. Any suggestions?

Note: these files are only written to by these functions, and only read from by corresponding load() functions. There is no other access to the files any where else in my program.

Note 2: I am experiencing this on Ubuntu Linux 16.10. I have not tested it on other platforms yet.


回答1:


Adding StandardCopyOption.ATOMIC_MOVE to the Files.move() call solves the problem:

public void saveCurrentList () {
    File tempCurrentFile = new File ( currentFile.toString() + ".temp" );
    try ( ObjectOutputStream currentListOut = new ObjectOutputStream( new FileOutputStream( tempCurrentFile ) ) ) {
        currentListOut.writeObject( player.getCurrentList().getState() );
        currentListOut.flush();
        currentListOut.close();

        Files.move( tempCurrentFile.toPath(), currentFile.toPath(), StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.ATOMIC_MOVE );

    } catch ( Exception e ) {
        LOGGER.warning( e.getClass().getCanonicalName() + ": Unable to save current list to disk, continuing." );
    }
}


来源:https://stackoverflow.com/questions/47126465/how-are-these-methods-allowing-causing-data-to-be-lost-on-disk

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!