Author: cazfi
Date: Mon Jan 11 12:43:53 2016
New Revision: 31444

URL: http://svn.gna.org/viewcvs/freeciv?rev=31444&view=rev
Log:
Made it possible to run savegame compressing and writing it to a file in a 
separate thread

See patch #6802

Modified:
    trunk/common/game.h
    trunk/server/edithand.c
    trunk/server/savegame.c
    trunk/server/savegame.h
    trunk/server/scripting/api_server_base.c
    trunk/server/settings.c
    trunk/server/srv_main.c
    trunk/server/srv_main.h

Modified: trunk/common/game.h
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/common/game.h?rev=31444&r1=31443&r2=31444&view=diff
==============================================================================
--- trunk/common/game.h (original)
+++ trunk/common/game.h Mon Jan 11 12:43:53 2016
@@ -167,6 +167,7 @@
       int razechance;
       unsigned revealmap;
       int revolution_length;
+      bool threaded_save;
       int save_compress_level;
       enum fz_method save_compress_type;
       int save_nturns;
@@ -589,6 +590,8 @@
 
 #define GAME_DEFAULT_AUTOSAVES       (1 << AS_TURN | 1 << AS_GAME_OVER | 1 << 
AS_QUITIDLE | 1 << AS_INTERRUPT)
 
+#define GAME_DEFAULT_THREADED_SAVE   FALSE
+
 #define GAME_DEFAULT_SKILL_LEVEL     AI_LEVEL_EASY
 #define GAME_HARDCODED_DEFAULT_SKILL_LEVEL 3 /* that was 'easy' in old saves */
 #define GAME_OLD_DEFAULT_SKILL_LEVEL 5  /* normal; for oldest save games */

Modified: trunk/server/edithand.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/edithand.c?rev=31444&r1=31443&r2=31444&view=diff
==============================================================================
--- trunk/server/edithand.c     (original)
+++ trunk/server/edithand.c     Mon Jan 11 12:43:53 2016
@@ -49,7 +49,7 @@
 #include "plrhand.h"
 #include "notify.h"
 #include "sanitycheck.h"
-#include "srv_main.h"
+#include "savegame.h"
 #include "stdinhand.h"
 #include "techtools.h"
 #include "unittools.h"

Modified: trunk/server/savegame.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/savegame.c?rev=31444&r1=31443&r2=31444&view=diff
==============================================================================
--- trunk/server/savegame.c     (original)
+++ trunk/server/savegame.c     Mon Jan 11 12:43:53 2016
@@ -17,17 +17,23 @@
 
 /* utility */
 #include "log.h"
+#include "mem.h"
 #include "registry.h"
 
 /* common */
 #include "capability.h"
+#include "game.h"
 
 /* server */
+#include "console.h"
 #include "legacysave.h"
+#include "notify.h"
 #include "savegame2.h"
 #include "savegame3.h"
 
 #include "savegame.h"
+
+static fc_thread *save_thread = NULL;
 
 /****************************************************************************
   Main entry point for loading a game.
@@ -79,3 +85,203 @@
 {
   savegame3_save(sfile, save_reason, scenario);
 }
+
+struct save_thread_data
+{
+  struct section_file *sfile;
+  char filepath[600];
+  int save_compress_level;
+  enum fz_method save_compress_type;
+};
+
+/*************************************************************************
+  Run game saving thread.
+*************************************************************************/
+static void save_thread_run(void *arg)
+{
+  struct save_thread_data *stdata = (struct save_thread_data *)arg;
+  
+  if (!secfile_save(stdata->sfile, stdata->filepath, 
stdata->save_compress_level,
+                    stdata->save_compress_type)) {
+    con_write(C_FAIL, _("Failed saving game as %s"), stdata->filepath);
+    log_error("Game saving failed: %s", secfile_error());
+  } else {
+    con_write(C_OK, _("Game saved as %s"), stdata->filepath);
+  }
+
+  secfile_destroy(stdata->sfile);
+  free(arg);
+}
+
+/**************************************************************************
+  Unconditionally save the game, with specified filename.
+  Always prints a message: either save ok, or failed.
+**************************************************************************/
+void save_game(const char *orig_filename, const char *save_reason,
+               bool scenario)
+{
+  char *dot, *filename;
+  struct timer *timer_cpu, *timer_user;
+  struct save_thread_data *stdata;
+
+  stdata = fc_malloc(sizeof(*stdata));
+
+  stdata->save_compress_type = game.server.save_compress_type;
+  stdata->save_compress_level = game.server.save_compress_level;
+
+  if (!orig_filename) {
+    stdata->filepath[0] = '\0';
+    filename = stdata->filepath;
+  } else {
+    sz_strlcpy(stdata->filepath, orig_filename);
+    if ((filename = strrchr(stdata->filepath, '/'))) {
+      filename++;
+    } else {
+      filename = stdata->filepath;
+    }
+
+    /* Ignores the dot at the start of the filename. */
+    for (dot = filename; '.' == *dot; dot++) {
+      /* Nothing. */
+    }
+    if ('\0' == *dot) {
+      /* Only dots in this file name, consider it as empty. */
+      filename[0] = '\0';
+    } else {
+      char *end_dot;
+      char *strip_extensions[] = { ".sav", ".gz", ".bz2", ".xz", NULL };
+      bool stripped = TRUE;
+
+      while ((end_dot = strrchr(dot, '.')) && stripped) {
+       int i;
+
+        stripped = FALSE;
+
+       for (i = 0; strip_extensions[i] != NULL && !stripped; i++) {
+          if (!strcmp(end_dot, strip_extensions[i])) {
+            *end_dot = '\0';
+            stripped = TRUE;
+          }
+        }
+      }
+    }
+  }
+
+  /* If orig_filename is NULL or empty, use a generated default name. */
+  if (filename[0] == '\0'){
+    /* manual save */
+    generate_save_name(game.server.save_name, filename,
+                       sizeof(stdata->filepath) + stdata->filepath - filename, 
"manual");
+  }
+
+  timer_cpu = timer_new(TIMER_CPU, TIMER_ACTIVE);
+  timer_start(timer_cpu);
+  timer_user = timer_new(TIMER_USER, TIMER_ACTIVE);
+  timer_start(timer_user);
+
+  /* Allowing duplicates shouldn't be allowed. However, it takes very too
+   * long time for huge game saving... */
+  stdata->sfile = secfile_new(TRUE);
+  savegame_save(stdata->sfile, save_reason, scenario);
+
+  /* We have consistent game state in stdata->sfile now, so
+   * we could pass it to the saving thread already. We want to
+   * handle below notify_conn() and directory creation in
+   * main thread, though. */
+
+  /* Append ".sav" to filename. */
+  sz_strlcat(stdata->filepath, ".sav");
+
+  if (stdata->save_compress_level > 0) {
+    switch (stdata->save_compress_type) {
+#ifdef FREECIV_HAVE_LIBZ
+    case FZ_ZLIB:
+      /* Append ".gz" to filename. */
+      sz_strlcat(stdata->filepath, ".gz");
+      break;
+#endif
+#ifdef FREECIV_HAVE_LIBBZ2
+    case FZ_BZIP2:
+      /* Append ".bz2" to filename. */
+      sz_strlcat(stdata->filepath, ".bz2");
+      break;
+#endif
+#ifdef FREECIV_HAVE_LIBLZMA
+   case FZ_XZ:
+      /* Append ".xz" to filename. */
+      sz_strlcat(stdata->filepath, ".xz");
+      break;
+#endif
+    case FZ_PLAIN:
+      break;
+    default:
+      log_error(_("Unsupported compression type %d."),
+                stdata->save_compress_type);
+      notify_conn(NULL, NULL, E_SETTING, ftc_warning,
+                  _("Unsupported compression type %d."),
+                  stdata->save_compress_type);
+      break;
+    }
+  }
+
+  if (!path_is_absolute(stdata->filepath)) {
+    char tmpname[600];
+
+    if (!scenario) {
+      /* Ensure the saves directory exists. */
+      make_dir(srvarg.saves_pathname);
+
+      sz_strlcpy(tmpname, srvarg.saves_pathname);
+    } else {
+      /* Make sure scenario directory exist */
+      make_dir(srvarg.scenarios_pathname);
+
+      sz_strlcpy(tmpname, srvarg.scenarios_pathname);
+    }
+
+    if (tmpname[0] != '\0') {
+      sz_strlcat(tmpname, "/");
+    }
+    sz_strlcat(tmpname, stdata->filepath);
+    sz_strlcpy(stdata->filepath, tmpname);
+  }
+
+  if (save_thread != NULL) {
+    /* Previously started thread */
+    fc_thread_wait(save_thread);
+    if (!game.server.threaded_save) {
+      /* Setting has changed since the last save */
+      free(save_thread);
+      save_thread = NULL;
+    }
+  } else if (game.server.threaded_save) {
+    save_thread = fc_malloc(sizeof(save_thread));
+  }
+
+  if (save_thread != NULL) {
+    fc_thread_start(save_thread, &save_thread_run, stdata);
+  } else {
+    save_thread_run(stdata);
+  }
+
+#ifdef LOG_TIMERS
+  log_verbose("Save time: %g seconds (%g apparent)",
+              timer_read_seconds(timer_cpu), timer_read_seconds(timer_user));
+#endif
+
+  timer_destroy(timer_cpu);
+  timer_destroy(timer_user);
+}
+
+/**************************************************************************
+  Close saving system.
+**************************************************************************/
+void save_system_close(void)
+{
+  if (save_thread != NULL) {
+    fc_thread_wait(save_thread);
+    free(save_thread);
+    save_thread = NULL;
+  }
+}
+

Modified: trunk/server/savegame.h
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/savegame.h?rev=31444&r1=31443&r2=31444&view=diff
==============================================================================
--- trunk/server/savegame.h     (original)
+++ trunk/server/savegame.h     Mon Jan 11 12:43:53 2016
@@ -22,4 +22,9 @@
 void savegame_save(struct section_file *sfile, const char *save_reason,
                    bool scenario);
 
+void save_game(const char *orig_filename, const char *save_reason,
+               bool scenario);
+
+void save_system_close(void);
+
 #endif /* FC__SAVEGAME_H */

Modified: trunk/server/scripting/api_server_base.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/scripting/api_server_base.c?rev=31444&r1=31443&r2=31444&view=diff
==============================================================================
--- trunk/server/scripting/api_server_base.c    (original)
+++ trunk/server/scripting/api_server_base.c    Mon Jan 11 12:43:53 2016
@@ -19,6 +19,7 @@
 #include "luascript.h"
 
 /* server */
+#include "savegame.h"
 #include "score.h"
 #include "settings.h"
 #include "srv_main.h"
@@ -62,6 +63,7 @@
   }
 
   save_game(filename, "User request (Lua)", FALSE);
+
   return TRUE;
 }
 

Modified: trunk/server/settings.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/settings.c?rev=31444&r1=31443&r2=31444&view=diff
==============================================================================
--- trunk/server/settings.c     (original)
+++ trunk/server/settings.c     Mon Jan 11 12:43:53 2016
@@ -2646,6 +2646,17 @@
                  "quits due to interrupt.\n"
                  "- \"Timer\" (TIMER): Save every 'savefrequency' minutes."),
               autosaves_callback, NULL, autosaves_name, GAME_DEFAULT_AUTOSAVES)
+
+  GEN_BOOL("threaded_save", game.server.threaded_save,
+           SSET_META, SSET_INTERNAL, SSET_RARE, SSET_SERVER_ONLY,
+           N_("Whether to do saving in separate thread"),
+           /* TRANS: The string between single quotes is a setting name and
+            * should not be translated. */
+           N_("If this is turned in, compressing and saving the actual "
+              "file containing the game situation takes place in "
+              "the background while game otherwise continues. This way "
+              "users are not required to wait for the save to finish."),
+           NULL, NULL, GAME_DEFAULT_THREADED_SAVE)
 
   GEN_INT("compress", game.server.save_compress_level,
           SSET_META, SSET_INTERNAL, SSET_RARE, SSET_SERVER_ONLY,

Modified: trunk/server/srv_main.c
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/srv_main.c?rev=31444&r1=31443&r2=31444&view=diff
==============================================================================
--- trunk/server/srv_main.c     (original)
+++ trunk/server/srv_main.c     Mon Jan 11 12:43:53 2016
@@ -1468,148 +1468,6 @@
 }
 
 /**************************************************************************
-  Unconditionally save the game, with specified filename.
-  Always prints a message: either save ok, or failed.
-**************************************************************************/
-void save_game(const char *orig_filename, const char *save_reason,
-               bool scenario)
-{
-  char filepath[600];
-  char *dot, *filename;
-  struct section_file *file;
-  struct timer *timer_cpu, *timer_user;
-
-  if (!orig_filename) {
-    filepath[0] = '\0';
-    filename = filepath;
-  } else {
-    sz_strlcpy(filepath, orig_filename);
-    if ((filename = strrchr(filepath, '/'))) {
-      filename++;
-    } else {
-      filename = filepath;
-    }
-
-    /* Ignores the dot at the start of the filename. */
-    for (dot = filename; '.' == *dot; dot++) {
-      /* Nothing. */
-    }
-    if ('\0' == *dot) {
-      /* Only dots in this file name, consider it as empty. */
-      filename[0] = '\0';
-    } else {
-      char *end_dot;
-      char *strip_extensions[] = { ".sav", ".gz", ".bz2", ".xz", NULL };
-      bool stripped = TRUE;
-
-      while ((end_dot = strrchr(dot, '.')) && stripped) {
-       int i;
-        stripped = FALSE;
-
-       for (i = 0; strip_extensions[i] != NULL && !stripped; i++) {
-          if (!strcmp(end_dot, strip_extensions[i])) {
-            *end_dot = '\0';
-            stripped = TRUE;
-          }
-        }
-      }
-    }
-  }
-
-  /* If orig_filename is NULL or empty, use a generated default name. */
-  if (filename[0] == '\0'){
-    /* manual save */
-    generate_save_name(game.server.save_name, filename,
-                       sizeof(filepath) + filepath - filename, "manual");
-  }
-
-  timer_cpu = timer_new(TIMER_CPU, TIMER_ACTIVE);
-  timer_start(timer_cpu);
-  timer_user = timer_new(TIMER_USER, TIMER_ACTIVE);
-  timer_start(timer_user);
-
-  /* Allowing duplicates shouldn't be allowed. However, it takes very too
-   * long time for huge game saving... */
-  file = secfile_new(TRUE);
-  savegame_save(file, save_reason, scenario);
-
-  /* Append ".sav" to filename. */
-  sz_strlcat(filepath, ".sav");
-
-  if (game.server.save_compress_level > 0) {
-    switch (game.server.save_compress_type) {
-#ifdef FREECIV_HAVE_LIBZ
-    case FZ_ZLIB:
-      /* Append ".gz" to filename. */
-      sz_strlcat(filepath, ".gz");
-      break;
-#endif
-#ifdef FREECIV_HAVE_LIBBZ2
-    case FZ_BZIP2:
-      /* Append ".bz2" to filename. */
-      sz_strlcat(filepath, ".bz2");
-      break;
-#endif
-#ifdef FREECIV_HAVE_LIBLZMA
-   case FZ_XZ:
-      /* Append ".xz" to filename. */
-      sz_strlcat(filepath, ".xz");
-      break;
-#endif
-    case FZ_PLAIN:
-      break;
-    default:
-      log_error(_("Unsupported compression type %d."),
-                game.server.save_compress_type);
-      notify_conn(NULL, NULL, E_SETTING, ftc_warning,
-                  _("Unsupported compression type %d."),
-                  game.server.save_compress_type);
-      break;
-    }
-  }
-
-  if (!path_is_absolute(filepath)) {
-    char tmpname[600];
-
-    if (!scenario) {
-      /* Ensure the saves directory exists. */
-      make_dir(srvarg.saves_pathname);
-
-      sz_strlcpy(tmpname, srvarg.saves_pathname);
-    } else {
-      /* Make sure scenario directory exist */
-      make_dir(srvarg.scenarios_pathname);
-
-      sz_strlcpy(tmpname, srvarg.scenarios_pathname);
-    }
-
-    if (tmpname[0] != '\0') {
-      sz_strlcat(tmpname, "/");
-    }
-    sz_strlcat(tmpname, filepath);
-    sz_strlcpy(filepath, tmpname);
-  }
-
-  if (!secfile_save(file, filepath, game.server.save_compress_level,
-                    game.server.save_compress_type)) {
-    con_write(C_FAIL, _("Failed saving game as %s"), filepath);
-    log_error("Game saving failed: %s", secfile_error());
-  } else {
-    con_write(C_OK, _("Game saved as %s"), filepath);
-  }
-
-  secfile_destroy(file);
-
-#ifdef LOG_TIMERS
-  log_verbose("Save time: %g seconds (%g apparent)",
-              timer_read_seconds(timer_cpu), timer_read_seconds(timer_user));
-#endif
-
-  timer_destroy(timer_cpu);
-  timer_destroy(timer_user);
-}
-
-/**************************************************************************
 Save game with autosave filename
 **************************************************************************/
 void save_game_auto(const char *save_reason, enum autosave_type type)
@@ -3292,6 +3150,9 @@
       server_sniff_all_input();
     }
 
+    /* Close it even between games. */
+    save_system_close();
+
     if (game.info.timeout == -1 || srvarg.exit_on_end) {
       /* For autogames or if the -e option is specified, exit the server. */
       server_quit();

Modified: trunk/server/srv_main.h
URL: 
http://svn.gna.org/viewcvs/freeciv/trunk/server/srv_main.h?rev=31444&r1=31443&r2=31444&view=diff
==============================================================================
--- trunk/server/srv_main.h     (original)
+++ trunk/server/srv_main.h     Mon Jan 11 12:43:53 2016
@@ -99,8 +99,6 @@
 
 bool server_packet_input(struct connection *pconn, void *packet, int type);
 void start_game(void);
-void save_game(const char *orig_filename, const char *save_reason,
-               bool scenario);
 const char *pick_random_player_name(const struct nation_type *pnation);
 void player_nation_defaults(struct player *pplayer, struct nation_type 
*pnation,
                             bool set_name);


_______________________________________________
Freeciv-commits mailing list
Freeciv-commits@gna.org
https://mail.gna.org/listinfo/freeciv-commits

Reply via email to