faster server autosaves patch

Forum for technical discussions regarding development. If you have a general suggestion, problem or comment, please use one of the other forums.

Moderator: OpenTTD Developers

Post Reply
xarick
Transport Coordinator
Transport Coordinator
Posts: 341
Joined: 26 Feb 2015 00:52

faster server autosaves patch

Post by xarick »

Download last version there (v6) -> viewtopic.php?p=1184282#p1184282

Current version features (v6):

a) The encoding part of a server savegame is now started on a different thread to minimize the impact of the stall that occurs after writting all the game state into memory, but there are some limitations:
a.1) When a client joins and the server is performing a savegame, the server stalls for the remaining duration that is still needed to finish encoding the savegame.
a.2) When a client joins and is receiving the map, and the server is not set to pause on join, no autosave (or any save) will be performed should a client still be receiving the map and the encoding part is not yet finished.

b) When a client joins, AIs and GS scripts are no longer requested to save their data. This removes yet another stall during game state copying, while reducing the size of the map that is to be compressed and then sent to the client. The client also starts downloading the map a bit earlier. As an extra benefit, this permits AIs and GS scripts that usually take too long to save to be useable while running a server, but there's a small note regarding this:
b.1) Should the server manually save the game or perform autosaves, AIs and GS scripts are still going to be requested to save their data.

c) Added 2 more configurable parameters in openttd.cfg, "sendmap_format" and "autosave_format" on top of "savegame_format". Search for these 3 lines inside openttd.cfg file, under [misc] section:

Code: Select all

[misc]
savegame_format = 
sendmap_format = 
autosave_format = 
c.1) These 2 new parameters accept the same valid values as the existant one: https://wiki.openttd.org/Savegame_format
- savegame_format sets the format of manual save games.
- autosave_format sets the format of autosave save games.
- sendmap_format sets the format that is used by a server when sending a map to a client joining.

c.2) Each of these 3 formats also include 2 additional compression level defaults to complement the already existant default:
- fast
- default
- slow

As it currently stands, only lzma and zlib benefit from these added defaults.
- lzma:0 .. lzma:9 (fast: 0, default: 2, slow: 2)
- zlib:0 .. zlib:9 (fast: 1, default: 6, slow: 6)

c.3) OpenTTD resorts to these default compression levels if they're not set in the configuration parameters, and only when certain game conditions match:
- fast when the current running game is the host of a network game or if an autosave occurs when the current running game is in fast forward mode.
- slow when the current running game is the host of a network game and a client is joining in.
- default whenever the criterias above don't occur.


The video example that I used for v1, could be set with the following parameters:

Code: Select all

[misc]
savegame_format = 
sendmap_format = 
autosave_format = zlib:2
In that example, savegames and sendmap formats and compression levels would resort to using openttd defaults, which is lzma for the format. The compression level would depend on those certain game conditions refered in c.3). Autosaves would use zlib format, and compression level would be 2, regardless of current game conditions.

Previous version (v1):
Video: https://onedrive.live.com/redir?resid=2 ... file%2cmp4
[+] Spoiler
faster server autosaves v1 r27539.patch
(2.99 KiB) Downloaded 134 times
v1 r27539

a) Server autosaves are now compressed using ZLIB format with level 2 compression, which should be much faster than what it was.

b) On top of that, the encoding part of a server autosave is now started on a different thread to minimize the impact of the stall that occurs after writting all the game state into memory, but there is some limitations:
b.1) When a client joins and the server is still performing the autosave (or any save), the server stalls for the remaining duration that is still needed to finish encoding the autosave, but since it is now using a much faster compression format, the stall is expected to be much shorter.
b.2) When a client joins and is receiving the map, and the server is not set to pause on join, no autosave will be performed should a client still be receiving the map.
Last edited by xarick on 23 Mar 2017 08:17, edited 29 times in total.
Formerly known as Samu
xarick
Transport Coordinator
Transport Coordinator
Posts: 341
Joined: 26 Feb 2015 00:52

Re: faster server autosaves

Post by xarick »

Previous version (v2):
[+] Spoiler
It came to my attention there is already a similar feature implemented in OpenTTD:
https://wiki.openttd.org/Savegame_format

This means most part of v1 code is useless. I was totally not aware of this parameter being available in openttd configuration file (usually openttd.cfg). You could already set ZLIB with compression level 2 by finding this line inside openttd configuration file...

Code: Select all

savegame_format = 
... and type zlib:2 at the end of it, and it will look like this:

Code: Select all

savegame_format = zlib:2
This will, however, always use zlib with compression level 2 for every savegame that openttd does, and that also includes the savefile of the map that is sent to a client joining the server.
faster server autosaves v2 r27546.patch
(1.06 KiB) Downloaded 129 times
v2 r27546

v2 reverts most of the code related to using the zlib with level 2. It was being forcidly set in code to be used regardless of the value in the configuration file. This version only keeps the part of the code that allows compression to start on a different thread.

There is a bug I found regarding 64-bit version of OpenTTD loading savefiles compressed with lzo. It simply fails to load the savegame. I've arranged a simple workaround which is using a different lzo decompressor.
Last edited by xarick on 20 Apr 2016 14:19, edited 1 time in total.
Formerly known as Samu
xarick
Transport Coordinator
Transport Coordinator
Posts: 341
Joined: 26 Feb 2015 00:52

Re: faster server autosaves

Post by xarick »

faster server autosaves v4 r27547.patch
(8.97 KiB) Downloaded 135 times
[+] Spoiler

Code: Select all

Index: src/saveload/saveload.cpp
===================================================================
--- src/saveload/saveload.cpp	(revision 27547)
+++ src/saveload/saveload.cpp	(working copy)
@@ -271,6 +271,8 @@
 uint16 _sl_version;       ///< the major savegame version identifier
 byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 char _savegame_format[8]; ///< how to compress savegames
+char _sendmap_format[8];  ///< how to compress the map to send to a client joining servers
+char _autosave_format[8]; ///< how to compress autosaves
 bool _do_autosave;        ///< are we doing an autosave at the moment?
 
 /** What are we currently doing? */
@@ -409,6 +411,8 @@
 
 	byte ff_state;                       ///< The state of fast-forward when saving started.
 	bool saveinprogress;                 ///< Whether there is currently a save in progress.
+	bool sendmapinprogress;              ///< Whether there is currently an encoding of a map in progress while being sent to a client joining the server.
+	bool autosaveinprogress;             ///< Whether there is currently an autosave in progress.
 };
 
 static SaveLoadParams _sl; ///< Parameters used for/at saveload.
@@ -2007,7 +2011,7 @@
 		if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
 
 		/* Decompress */
-		lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL);
+		lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
 		return len;
 	}
 };
@@ -2338,9 +2342,11 @@
 	LoadFilter *(*init_load)(LoadFilter *chain);                    ///< Constructor for the load filter.
 	SaveFilter *(*init_write)(SaveFilter *chain, byte compression); ///< Constructor for the save filter.
 
-	byte min_compression;                 ///< the minimum compression level of this format
-	byte default_compression;             ///< the default compression level of this format
-	byte max_compression;                 ///< the maximum compression level of this format
+	byte min_compression;                 ///< the minimum compression level accepted by this format
+	byte fast_compression;                ///< the default fast compression level of this format to be used by openttd
+	byte default_compression;             ///< the default compression level of this format to be used by openttd
+	byte slow_compression;                ///< the default slow compression level of this format to be used by openttd
+	byte max_compression;                 ///< the maximum compression level accepted by this format
 };
 
 /** The different saveload formats known/understood by OpenTTD. */
@@ -2347,19 +2353,19 @@
 static const SaveLoadFormat _saveload_formats[] = {
 #if defined(WITH_LZO)
 	/* Roughly 75% larger than zlib level 6 at only ~7% of the CPU usage. */
-	{"lzo",    TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>,    CreateSaveFilter<LZOSaveFilter>,    0, 0, 0},
+	{"lzo",    TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>,    CreateSaveFilter<LZOSaveFilter>,    0, 0, 0, 0, 0},
 #else
-	{"lzo",    TO_BE32X('OTTD'), NULL,                               NULL,                               0, 0, 0},
+	{"lzo",    TO_BE32X('OTTD'), NULL,                               NULL,                               0, 0, 0, 0, 0},
 #endif
 	/* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */
-	{"none",   TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
+	{"none",   TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0, 0, 0},
 #if defined(WITH_ZLIB)
 	/* After level 6 the speed reduction is significant (1.5x to 2.5x slower per level), but the reduction in filesize is
 	 * fairly insignificant (~1% for each step). Lower levels become ~5-10% bigger by each level than level 6 while level
 	 * 1 is "only" 3 times as fast. Level 0 results in uncompressed savegames at about 8 times the cost of "none". */
-	{"zlib",   TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>,   CreateSaveFilter<ZlibSaveFilter>,   0, 6, 9},
+	{"zlib",   TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>,   CreateSaveFilter<ZlibSaveFilter>,   0, 1, 6, 6, 9},
 #else
-	{"zlib",   TO_BE32X('OTTZ'), NULL,                               NULL,                               0, 0, 0},
+	{"zlib",   TO_BE32X('OTTZ'), NULL,                               NULL,                               0, 0, 0, 0, 0},
 #endif
 #if defined(WITH_LZMA)
 	/* Level 2 compression is speed wise as fast as zlib level 6 compression (old default), but results in ~10% smaller saves.
@@ -2367,9 +2373,9 @@
 	 * The next significant reduction in file size is at level 4, but that is already 4 times slower. Level 3 is primarily 50%
 	 * slower while not improving the filesize, while level 0 and 1 are faster, but don't reduce savegame size much.
 	 * It's OTTX and not e.g. OTTL because liblzma is part of xz-utils and .tar.xz is preferred over .tar.lzma. */
-	{"lzma",   TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>,   CreateSaveFilter<LZMASaveFilter>,   0, 2, 9},
+	{"lzma",   TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>,   CreateSaveFilter<LZMASaveFilter>,   0, 0, 2, 2, 9},
 #else
-	{"lzma",   TO_BE32X('OTTX'), NULL,                               NULL,                               0, 0, 0},
+	{"lzma",   TO_BE32X('OTTX'), NULL,                               NULL,                               0, 0, 0, 0, 0},
 #endif
 };
 
@@ -2395,6 +2401,8 @@
 		for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
 			if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
 				*compression_level = slf->default_compression;
+				if ((_network_server && !_sl.sendmapinprogress) || (_pause_mode == PM_UNPAUSED && _sl.autosaveinprogress && _sl.ff_state != _fast_forward)) *compression_level = slf->fast_compression;
+				if (_sl.sendmapinprogress) *compression_level = slf->slow_compression;
 				if (complevel != NULL) {
 					/* There is a compression level in the string.
 					 * First restore the : we removed to do proper name matching,
@@ -2424,6 +2432,8 @@
 		if (complevel != NULL) *complevel = ':';
 	}
 	*compression_level = def->default_compression;
+	if ((_network_server && !_sl.sendmapinprogress) || (_pause_mode == PM_UNPAUSED && _sl.autosaveinprogress && _sl.ff_state != _fast_forward)) *compression_level = def->fast_compression;
+	if (_sl.sendmapinprogress) *compression_level = def->slow_compression;
 	return def;
 }
 
@@ -2463,6 +2473,7 @@
 
 	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
 	_sl.saveinprogress = true;
+	if (_do_autosave) _sl.autosaveinprogress = true;
 }
 
 /** Update the gui accordingly when saving is done and release locks on saveload. */
@@ -2473,6 +2484,8 @@
 
 	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
 	_sl.saveinprogress = false;
+	_sl.sendmapinprogress = false;
+	_sl.autosaveinprogress = false;
 }
 
 /** Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friends) */
@@ -2508,7 +2521,7 @@
 {
 	try {
 		byte compression;
-		const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
+		const SaveLoadFormat *fmt = GetSavegameFormat(_sl.sendmapinprogress ? _sendmap_format : _sl.autosaveinprogress ? _autosave_format : _savegame_format, &compression);
 
 		/* We have written our stuff to memory, now write it to file! */
 		uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
@@ -2603,7 +2616,9 @@
  */
 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
 {
+	if (_network_server && _sl.saveinprogress && threaded) WaitTillSaved();
 	try {
+		_sl.sendmapinprogress = true;
 		_sl.action = SLA_SAVE;
 		return DoSave(writer, threaded);
 	} catch (...) {
@@ -2829,7 +2844,7 @@
 
 		if (mode == SL_SAVE) { // SAVE game
 			DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
-			if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
+			if (!_settings_client.gui.threaded_saves) threaded = false;
 
 			return DoSave(new FileWriter(fh), threaded);
 		}
Index: src/saveload/saveload.h
===================================================================
--- src/saveload/saveload.h	(revision 27547)
+++ src/saveload/saveload.h	(working copy)
@@ -547,6 +547,8 @@
 bool SaveloadCrashWithMissingNewGRFs();
 
 extern char _savegame_format[8];
+extern char _sendmap_format[8];
+extern char _autosave_format[8];
 extern bool _do_autosave;
 
 #endif /* SAVELOAD_H */
Index: src/table/misc_settings.ini
===================================================================
--- src/table/misc_settings.ini	(revision 27547)
+++ src/table/misc_settings.ini	(working copy)
@@ -138,6 +138,20 @@
 def      = NULL
 cat      = SC_EXPERT
 
+[SDTG_STR]
+name     = ""sendmap_format""
+type     = SLE_STRB
+var      = _sendmap_format
+def      = NULL
+cat      = SC_EXPERT
+
+[SDTG_STR]
+name     = ""autosave_format""
+type     = SLE_STRB
+var      = _autosave_format
+def      = NULL
+cat      = SC_EXPERT
+
 [SDTG_BOOL]
 name     = ""rightclick_emulate""
 var      = _rightclick_emulate
v4 r27547

Fixed the bug preventing fast forwarding autosaves to be saved with fast compression level default.


Previous version (v3):
[+] Spoiler
faster server autosaves v3 r27547.patch
(8.97 KiB) Downloaded 123 times
Added 2 more configurable parameters in openttd.cfg, "sendmap_format" and "autosave_format" on top of "savegame_format". Search for these 3 lines inside your openttd.cfg file, under [misc] section:

Code: Select all

[misc]
savegame_format = 
sendmap_format = 
autosave_format = 
These 2 new parameters accept the same valid values as the existant one: https://wiki.openttd.org/Savegame_format
- savegame_format sets the format of manual save games.
- autosave_format sets the format of autosave save games.
- sendmap_format sets the format that is used by a server when sending a map to a client joining.

Each of these 3 formats also include 2 additional compression level defaults:
- fast
- default
- slow

As it currently stands, only lzma and zlib benefit from these added defaults.
- lzma:0 .. lzma:9 (fast: 0, default: 2, slow: 2)
- zlib:0 .. zlib:9 (fast: 1, default: 6, slow: 6)

OpenTTD resorts to these default compression levels if they're not set in the configuration parameters, and only when certain game conditions match:
- fast when the current running game is the host of a network game or if an autosave occurs when the current running game is in fast forward mode.
- slow when the current running game is the host of a network game and a client is joining in.
- default whenever the criterias above don't occur.

Bug detected: fast forward autosaves aren't using the fast compression level.
Formerly known as Samu
xarick
Transport Coordinator
Transport Coordinator
Posts: 341
Joined: 26 Feb 2015 00:52

Re: faster server autosaves

Post by xarick »

faster server autosaves v5 r27601.patch
(10.57 KiB) Downloaded 117 times
[+] Spoiler

Code: Select all

Index: src/ai/ai_core.cpp
===================================================================
--- src/ai/ai_core.cpp	(revision 27601)
+++ src/ai/ai_core.cpp	(working copy)
@@ -15,6 +15,7 @@
 #include "../company_base.h"
 #include "../company_func.h"
 #include "../network/network.h"
+#include "../saveload/saveload.h"
 #include "../window_func.h"
 #include "ai_scanner.hpp"
 #include "ai_instance.hpp"
@@ -276,7 +277,7 @@
 
 /* static */ void AI::Save(CompanyID company)
 {
-	if (!_networking || _network_server) {
+	if (!_networking || _network_server && !_save_empty_script) {
 		Company *c = Company::GetIfValid(company);
 		assert(c != NULL && c->ai_instance != NULL);
 
Index: src/game/game_core.cpp
===================================================================
--- src/game/game_core.cpp	(revision 27601)
+++ src/game/game_core.cpp	(working copy)
@@ -14,6 +14,7 @@
 #include "../company_base.h"
 #include "../company_func.h"
 #include "../network/network.h"
+#include "../saveload/saveload.h"
 #include "../window_func.h"
 #include "game.hpp"
 #include "game_scanner.hpp"
@@ -197,7 +198,7 @@
 
 /* static */ void Game::Save()
 {
-	if (Game::instance != NULL && (!_networking || _network_server)) {
+	if (Game::instance != NULL && (!_networking || _network_server && !_save_empty_script)) {
 		Backup<CompanyByte> cur_company(_current_company, OWNER_DEITY, FILE_LINE);
 		Game::instance->Save();
 		cur_company.Restore();
Index: src/saveload/saveload.cpp
===================================================================
--- src/saveload/saveload.cpp	(revision 27601)
+++ src/saveload/saveload.cpp	(working copy)
@@ -272,7 +272,10 @@
 uint16 _sl_version;       ///< the major savegame version identifier
 byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
 char _savegame_format[8]; ///< how to compress savegames
+char _sendmap_format[8];  ///< how to compress the map to send to a client joining servers
+char _autosave_format[8]; ///< how to compress autosaves
 bool _do_autosave;        ///< are we doing an autosave at the moment?
+bool _save_empty_script;  ///< are we sending a map to a client over the nework?
 
 /** What are we currently doing? */
 enum SaveLoadAction {
@@ -410,6 +413,8 @@
 
 	byte ff_state;                       ///< The state of fast-forward when saving started.
 	bool saveinprogress;                 ///< Whether there is currently a save in progress.
+	bool sendmapinprogress;              ///< Whether there is currently an encoding of a map in progress while being sent to a client joining the server.
+	bool autosaveinprogress;             ///< Whether there is currently an autosave in progress.
 };
 
 static SaveLoadParams _sl; ///< Parameters used for/at saveload.
@@ -2008,7 +2013,7 @@
 		if (tmp[0] != lzo_adler32(0, out, size + sizeof(uint32))) SlErrorCorrupt("Bad checksum");
 
 		/* Decompress */
-		lzo1x_decompress_safe(out + sizeof(uint32) * 1, size, buf, &len, NULL);
+		lzo1x_decompress(out + sizeof(uint32) * 1, size, buf, &len, NULL);
 		return len;
 	}
 };
@@ -2339,9 +2344,11 @@
 	LoadFilter *(*init_load)(LoadFilter *chain);                    ///< Constructor for the load filter.
 	SaveFilter *(*init_write)(SaveFilter *chain, byte compression); ///< Constructor for the save filter.
 
-	byte min_compression;                 ///< the minimum compression level of this format
-	byte default_compression;             ///< the default compression level of this format
-	byte max_compression;                 ///< the maximum compression level of this format
+	byte min_compression;                 ///< the minimum compression level accepted by this format
+	byte fast_compression;                ///< the default fast compression level of this format to be used by openttd
+	byte default_compression;             ///< the default compression level of this format to be used by openttd
+	byte slow_compression;                ///< the default slow compression level of this format to be used by openttd
+	byte max_compression;                 ///< the maximum compression level accepted by this format
 };
 
 /** The different saveload formats known/understood by OpenTTD. */
@@ -2348,19 +2355,19 @@
 static const SaveLoadFormat _saveload_formats[] = {
 #if defined(WITH_LZO)
 	/* Roughly 75% larger than zlib level 6 at only ~7% of the CPU usage. */
-	{"lzo",    TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>,    CreateSaveFilter<LZOSaveFilter>,    0, 0, 0},
+	{"lzo",    TO_BE32X('OTTD'), CreateLoadFilter<LZOLoadFilter>,    CreateSaveFilter<LZOSaveFilter>,    0, 0, 0, 0, 0},
 #else
-	{"lzo",    TO_BE32X('OTTD'), NULL,                               NULL,                               0, 0, 0},
+	{"lzo",    TO_BE32X('OTTD'), NULL,                               NULL,                               0, 0, 0, 0, 0},
 #endif
 	/* Roughly 5 times larger at only 1% of the CPU usage over zlib level 6. */
-	{"none",   TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0},
+	{"none",   TO_BE32X('OTTN'), CreateLoadFilter<NoCompLoadFilter>, CreateSaveFilter<NoCompSaveFilter>, 0, 0, 0, 0, 0},
 #if defined(WITH_ZLIB)
 	/* After level 6 the speed reduction is significant (1.5x to 2.5x slower per level), but the reduction in filesize is
 	 * fairly insignificant (~1% for each step). Lower levels become ~5-10% bigger by each level than level 6 while level
 	 * 1 is "only" 3 times as fast. Level 0 results in uncompressed savegames at about 8 times the cost of "none". */
-	{"zlib",   TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>,   CreateSaveFilter<ZlibSaveFilter>,   0, 6, 9},
+	{"zlib",   TO_BE32X('OTTZ'), CreateLoadFilter<ZlibLoadFilter>,   CreateSaveFilter<ZlibSaveFilter>,   0, 1, 6, 6, 9},
 #else
-	{"zlib",   TO_BE32X('OTTZ'), NULL,                               NULL,                               0, 0, 0},
+	{"zlib",   TO_BE32X('OTTZ'), NULL,                               NULL,                               0, 0, 0, 0, 0},
 #endif
 #if defined(WITH_LZMA)
 	/* Level 2 compression is speed wise as fast as zlib level 6 compression (old default), but results in ~10% smaller saves.
@@ -2368,9 +2375,9 @@
 	 * The next significant reduction in file size is at level 4, but that is already 4 times slower. Level 3 is primarily 50%
 	 * slower while not improving the filesize, while level 0 and 1 are faster, but don't reduce savegame size much.
 	 * It's OTTX and not e.g. OTTL because liblzma is part of xz-utils and .tar.xz is preferred over .tar.lzma. */
-	{"lzma",   TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>,   CreateSaveFilter<LZMASaveFilter>,   0, 2, 9},
+	{"lzma",   TO_BE32X('OTTX'), CreateLoadFilter<LZMALoadFilter>,   CreateSaveFilter<LZMASaveFilter>,   0, 0, 2, 2, 9},
 #else
-	{"lzma",   TO_BE32X('OTTX'), NULL,                               NULL,                               0, 0, 0},
+	{"lzma",   TO_BE32X('OTTX'), NULL,                               NULL,                               0, 0, 0, 0, 0},
 #endif
 };
 
@@ -2396,6 +2403,8 @@
 		for (const SaveLoadFormat *slf = &_saveload_formats[0]; slf != endof(_saveload_formats); slf++) {
 			if (slf->init_write != NULL && strcmp(s, slf->name) == 0) {
 				*compression_level = slf->default_compression;
+				if ((_network_server && !_sl.sendmapinprogress) || (_pause_mode == PM_UNPAUSED && _sl.autosaveinprogress && _sl.ff_state != _fast_forward)) *compression_level = slf->fast_compression;
+				if (_sl.sendmapinprogress) *compression_level = slf->slow_compression;
 				if (complevel != NULL) {
 					/* There is a compression level in the string.
 					 * First restore the : we removed to do proper name matching,
@@ -2425,6 +2434,8 @@
 		if (complevel != NULL) *complevel = ':';
 	}
 	*compression_level = def->default_compression;
+	if ((_network_server && !_sl.sendmapinprogress) || (_pause_mode == PM_UNPAUSED && _sl.autosaveinprogress && _sl.ff_state != _fast_forward)) *compression_level = def->fast_compression;
+	if (_sl.sendmapinprogress) *compression_level = def->slow_compression;
 	return def;
 }
 
@@ -2464,6 +2475,7 @@
 
 	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
 	_sl.saveinprogress = true;
+	if (_do_autosave) _sl.autosaveinprogress = true;
 }
 
 /** Update the gui accordingly when saving is done and release locks on saveload. */
@@ -2474,6 +2486,9 @@
 
 	InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
 	_sl.saveinprogress = false;
+	_sl.sendmapinprogress = false;
+	_sl.autosaveinprogress = false;
+	_save_empty_script = false;
 }
 
 /** Set the error message from outside of the actual loading/saving of the game (AfterLoadGame and friends) */
@@ -2509,7 +2524,7 @@
 {
 	try {
 		byte compression;
-		const SaveLoadFormat *fmt = GetSavegameFormat(_savegame_format, &compression);
+		const SaveLoadFormat *fmt = GetSavegameFormat(_sl.sendmapinprogress ? _sendmap_format : _sl.autosaveinprogress ? _autosave_format : _savegame_format, &compression);
 
 		/* We have written our stuff to memory, now write it to file! */
 		uint32 hdr[2] = { fmt->tag, TO_BE32(SAVEGAME_VERSION << 16) };
@@ -2604,7 +2619,10 @@
  */
 SaveOrLoadResult SaveWithFilter(SaveFilter *writer, bool threaded)
 {
+	if (_network_server && _sl.saveinprogress && threaded) WaitTillSaved();
 	try {
+		_save_empty_script = true;
+		_sl.sendmapinprogress = true;
 		_sl.action = SLA_SAVE;
 		return DoSave(writer, threaded);
 	} catch (...) {
@@ -2830,7 +2848,7 @@
 
 		if (mode == SL_SAVE) { // SAVE game
 			DEBUG(desync, 1, "save: %08x; %02x; %s", _date, _date_fract, filename);
-			if (_network_server || !_settings_client.gui.threaded_saves) threaded = false;
+			if (!_settings_client.gui.threaded_saves) threaded = false;
 
 			return DoSave(new FileWriter(fh), threaded);
 		}
Index: src/saveload/saveload.h
===================================================================
--- src/saveload/saveload.h	(revision 27601)
+++ src/saveload/saveload.h	(working copy)
@@ -547,6 +547,9 @@
 bool SaveloadCrashWithMissingNewGRFs();
 
 extern char _savegame_format[8];
+extern char _sendmap_format[8];
+extern char _autosave_format[8];
 extern bool _do_autosave;
+extern bool _save_empty_script;
 
 #endif /* SAVELOAD_H */
Index: src/table/misc_settings.ini
===================================================================
--- src/table/misc_settings.ini	(revision 27601)
+++ src/table/misc_settings.ini	(working copy)
@@ -138,6 +138,20 @@
 def      = NULL
 cat      = SC_EXPERT
 
+[SDTG_STR]
+name     = ""sendmap_format""
+type     = SLE_STRB
+var      = _sendmap_format
+def      = NULL
+cat      = SC_EXPERT
+
+[SDTG_STR]
+name     = ""autosave_format""
+type     = SLE_STRB
+var      = _autosave_format
+def      = NULL
+cat      = SC_EXPERT
+
 [SDTG_BOOL]
 name     = ""rightclick_emulate""
 var      = _rightclick_emulate
v5 r27601

While hosting a server, AIs or GS are not going to be requested to save their data when a client attempts to join. But should you manually save the game or perform autosaves, AIs or GS are still going to be requested to save their data. This permits scripts that usually take too long to save to be useable while running a server for as long as no autosaves or manual saves are done during the session.
Formerly known as Samu
xarick
Transport Coordinator
Transport Coordinator
Posts: 341
Joined: 26 Feb 2015 00:52

Re: faster server autosaves patch

Post by xarick »

faster server autosaves v6 r27816.patch
(10.28 KiB) Downloaded 126 times
v6
-Removed the workaround for loading savegames created with lzo format, as it has been fixed in trunk r27793
Formerly known as Samu
Post Reply

Return to “OpenTTD Development”

Who is online

Users browsing this forum: No registered users and 40 guests