diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml index 36546fac3de98d34846292d0c4e8226d443b4511..4784a877a21e698af28f72aab473ac9c3cad605e 100644 --- a/examples/parameter_example.yml +++ b/examples/parameter_example.yml @@ -91,6 +91,7 @@ InitialConditions: # Parameters controlling restarts Restarts: enable: 1 # (Optional) whether to enable dumping restarts at fixed intervals. + save: 1 # (Optional) whether to save copies of the previous set of restart files (named .prev) onexit: 0 # (Optional) whether to dump restarts on exit (*needs enable*) subdir: restart # (Optional) name of subdirectory for restart files. basename: swift # (Optional) prefix used in naming restart files. diff --git a/src/engine.c b/src/engine.c index 96ebe7b093b81f9f716aead4dc45ea4f76d18f81..ffb4d752efcbf676685cefe83861c4335e3e1464 100644 --- a/src/engine.c +++ b/src/engine.c @@ -4546,6 +4546,9 @@ void engine_dump_restarts(struct engine *e, int drifted_all, int force) { MPI_Bcast(&dump, 1, MPI_INT, 0, MPI_COMM_WORLD); #endif if (dump) { + /* Clean out the previous saved files, if found. Do this now as we are + * MPI synchronized. */ + restart_remove_previous(e->restart_file); /* Drift all particles first (may have just been done). */ if (!drifted_all) engine_drift_all(e); @@ -5593,6 +5596,9 @@ void engine_config(int restart, struct engine *e, /* Whether restarts are enabled. Yes by default. Can be changed on restart. */ e->restart_dump = parser_get_opt_param_int(params, "Restarts:enable", 1); + /* Whether to save backup copies of the previous restart files. */ + e->restart_save = parser_get_opt_param_int(params, "Restarts:save", 1); + /* Whether restarts should be dumped on exit. Not by default. Can be changed * on restart. */ e->restart_onexit = parser_get_opt_param_int(params, "Restarts:onexit", 0); diff --git a/src/engine.h b/src/engine.h index c0bc93536cc7763467c891c66905b7c1ab86fd7d..3e29b9226ff6a0d2d62e1f36fe01c4c6d9b4fb52 100644 --- a/src/engine.h +++ b/src/engine.h @@ -299,6 +299,9 @@ struct engine { /* Whether to dump restart files. */ int restart_dump; + /* Whether to save previous generation of restart files. */ + int restart_save; + /* Whether to dump restart files after the last step. */ int restart_onexit; diff --git a/src/restart.c b/src/restart.c index 952df783626630c36dab410900c417461de07c04..6344e10e2480134959e18a76a2b6d2244531baec 100644 --- a/src/restart.c +++ b/src/restart.c @@ -128,6 +128,9 @@ void restart_locate_free(int nfiles, char **files) { */ void restart_write(struct engine *e, const char *filename) { + /* Save a backup the existing restart file, if requested. */ + if (e->restart_save) restart_save_previous(filename); + FILE *stream = fopen(filename, "w"); if (stream == NULL) error("Failed to open restart file: %s (%s)", filename, strerror(errno)); @@ -271,7 +274,7 @@ void restart_write_blocks(void *ptr, size_t size, size_t nblocks, FILE *stream, * @result 1 if the file was found. */ int restart_stop_now(const char *dir, int cleanup) { - static struct stat buf; + struct stat buf; char filename[FNAMELEN]; strcpy(filename, dir); strcat(filename, "/stop"); @@ -284,3 +287,47 @@ int restart_stop_now(const char *dir, int cleanup) { } return 0; } + +/** + * @brief check if a file with the given name exists and rename to + * {filename}.prev. Used to move old restart files before overwriting. + * + * Does nothing if the file does not exist. + * + * @param filename the name of the file to check. + */ +void restart_save_previous(const char *filename) { + struct stat buf; + if (stat(filename, &buf) == 0) { + char newname[FNAMELEN]; + strcpy(newname, filename); + strcat(newname, ".prev"); + if (rename(filename, newname) != 0) { + /* Worth a complaint, this should not happen. */ + message("Failed to rename file '%s' to '%s' (%s)", filename, newname, + strerror(errno)); + } + } +} + +/** + * @brief check if a saved file with the given prefix name exists and remove + * it. Used to remove old restart files before a save sequence + * so that old saved files are not mixed up with new ones. + * + * Does nothing if a saved file does not exist. + * + * @param filename the prefix used when the saved file was created. + */ +void restart_remove_previous(const char *filename) { + struct stat buf; + char newname[FNAMELEN]; + strcpy(newname, filename); + strcat(newname, ".prev"); + if (stat(newname, &buf) == 0) { + if (unlink(newname) != 0) { + /* Worth a complaint, this should not happen. */ + message("Failed to unlink file '%s' (%s)", newname, strerror(errno)); + } + } +} diff --git a/src/restart.h b/src/restart.h index 80e6c6755c09be4d3bda84860774b7da9e1a07cd..49d127492255364cbf0f48653c560494e83a2920 100644 --- a/src/restart.h +++ b/src/restart.h @@ -33,10 +33,12 @@ int restart_genname(const char *dir, const char *basename, int nodeID, void restart_read_blocks(void *ptr, size_t size, size_t nblocks, FILE *stream, char *label, const char *errstr); - void restart_write_blocks(void *ptr, size_t size, size_t nblocks, FILE *stream, const char *label, const char *errstr); int restart_stop_now(const char *dir, int cleanup); +void restart_save_previous(const char *filename); +void restart_remove_previous(const char *filename); + #endif /* SWIFT_RESTART_H */