implement lazy multisave saving using a daemon thread
This commit is contained in:
parent
01d793bc00
commit
7e3ee8101f
|
@ -25,3 +25,4 @@ weights/
|
|||
/logs/
|
||||
_persistent_storage.yaml
|
||||
mystery_result_*.yaml
|
||||
/db.db3
|
||||
|
|
|
@ -11,6 +11,7 @@ import typing
|
|||
import inspect
|
||||
import weakref
|
||||
import datetime
|
||||
import threading
|
||||
|
||||
import ModuleUpdate
|
||||
|
||||
|
@ -94,14 +95,17 @@ class Context(Node):
|
|||
self.commandprocessor = ServerCommandProcessor(self)
|
||||
self.embedded_blacklist = {"host", "port"}
|
||||
self.client_ids: typing.Dict[typing.Tuple[int, int], datetime.datetime] = {}
|
||||
self.auto_save_interval = 60 # in seconds
|
||||
self.auto_saver_thread = None
|
||||
self.save_dirty = False
|
||||
|
||||
def load(self, multidatapath: str, use_embedded_server_options: bool = False):
|
||||
with open(multidatapath, 'rb') as f:
|
||||
self._load(f, use_embedded_server_options)
|
||||
self._load(json.loads(zlib.decompress(f.read()).decode("utf-8-sig")),
|
||||
use_embedded_server_options)
|
||||
self.data_filename = multidatapath
|
||||
|
||||
def _load(self, fileobj, use_embedded_server_options: bool):
|
||||
jsonobj = json.loads(zlib.decompress(fileobj.read()).decode("utf-8-sig"))
|
||||
def _load(self, jsonobj: dict, use_embedded_server_options: bool):
|
||||
for team, names in enumerate(jsonobj['names']):
|
||||
for player, name in enumerate(names, 1):
|
||||
self.player_names[(team, player)] = name
|
||||
|
@ -126,6 +130,28 @@ class Context(Node):
|
|||
setattr(self, key, value)
|
||||
self.item_cheat = not server_options.get("disable_item_cheat", True)
|
||||
|
||||
def save(self, now=False) -> bool:
|
||||
if self.saving:
|
||||
if now:
|
||||
self.save_dirty = False
|
||||
return self._save()
|
||||
|
||||
self.save_dirty = True
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def _save(self) -> bool:
|
||||
try:
|
||||
jsonstr = json.dumps(self.get_save())
|
||||
with open(self.save_filename, "wb") as f:
|
||||
f.write(zlib.compress(jsonstr.encode("utf-8")))
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def init_save(self, enabled: bool = True):
|
||||
self.saving = enabled
|
||||
if self.saving:
|
||||
|
@ -141,6 +167,22 @@ class Context(Node):
|
|||
except Exception as e:
|
||||
logging.exception(e)
|
||||
|
||||
if not self.auto_saver_thread:
|
||||
def save_regularly():
|
||||
import time
|
||||
while self.running:
|
||||
time.sleep(self.auto_save_interval)
|
||||
if self.save_dirty:
|
||||
logging.debug("Saving multisave via thread.")
|
||||
self.save_dirty = False
|
||||
self._save()
|
||||
|
||||
self.auto_saver_thread = threading.Thread(target=save_regularly, daemon=True)
|
||||
self.auto_saver_thread.start()
|
||||
|
||||
import atexit
|
||||
atexit.register(self._save) # make sure we save on exit too
|
||||
|
||||
def get_save(self) -> dict:
|
||||
d = {
|
||||
"rom_names": list(self.rom_names.items()),
|
||||
|
@ -407,7 +449,7 @@ def register_location_checks(ctx: Context, team: int, slot: int, locations):
|
|||
for client in ctx.endpoints:
|
||||
if client.team == team and client.slot == slot:
|
||||
asyncio.create_task(ctx.send_msgs(client, [["HintPointUpdate", (get_client_points(ctx, client),)]]))
|
||||
save(ctx)
|
||||
ctx.save()
|
||||
|
||||
|
||||
def notify_team(ctx: Context, team: int, text: str):
|
||||
|
@ -415,15 +457,6 @@ def notify_team(ctx: Context, team: int, text: str):
|
|||
ctx.broadcast_team(team, [['Print', text]])
|
||||
|
||||
|
||||
def save(ctx: Context):
|
||||
if ctx.saving:
|
||||
try:
|
||||
jsonstr = json.dumps(ctx.get_save())
|
||||
with open(ctx.save_filename, "wb") as f:
|
||||
f.write(zlib.compress(jsonstr.encode("utf-8")))
|
||||
except Exception as e:
|
||||
logging.exception(e)
|
||||
|
||||
|
||||
def collect_hints(ctx: Context, team: int, slot: int, item: str) -> typing.List[Utils.Hint]:
|
||||
hints = []
|
||||
|
@ -683,13 +716,13 @@ class ClientMessageProcessor(CommandProcessor):
|
|||
self.ctx.name_aliases[self.client.team, self.client.slot] = alias_name
|
||||
self.output(f"Hello, {alias_name}")
|
||||
update_aliases(self.ctx, self.client.team)
|
||||
save(self.ctx)
|
||||
self.ctx.save()
|
||||
return True
|
||||
elif (self.client.team, self.client.slot) in self.ctx.name_aliases:
|
||||
del (self.ctx.name_aliases[self.client.team, self.client.slot])
|
||||
self.output("Removed Alias")
|
||||
update_aliases(self.ctx, self.client.team)
|
||||
save(self.ctx)
|
||||
self.ctx.save()
|
||||
return True
|
||||
return False
|
||||
|
||||
|
@ -776,7 +809,7 @@ class ClientMessageProcessor(CommandProcessor):
|
|||
self.output(
|
||||
"Could not pay for everything. Rerun the hint later with more points to get the remaining hints.")
|
||||
notify_hints(self.ctx, self.client.team, found_hints + hints)
|
||||
save(self.ctx)
|
||||
self.ctx.save()
|
||||
return True
|
||||
|
||||
else:
|
||||
|
@ -938,9 +971,13 @@ class ServerCommandProcessor(CommandProcessor):
|
|||
|
||||
def _cmd_save(self) -> bool:
|
||||
"""Save current state to multidata"""
|
||||
save(self.ctx)
|
||||
self.output("Game saved")
|
||||
return True
|
||||
if self.ctx.saving:
|
||||
self.ctx.save(True)
|
||||
self.output("Game saved")
|
||||
return True
|
||||
else:
|
||||
self.output("Saving is disabled.")
|
||||
return False
|
||||
|
||||
def _cmd_players(self) -> bool:
|
||||
"""Get information about connected players"""
|
||||
|
@ -968,13 +1005,13 @@ class ServerCommandProcessor(CommandProcessor):
|
|||
self.ctx.name_aliases[team, slot] = alias_name
|
||||
self.output(f"Named {player_name} as {alias_name}")
|
||||
update_aliases(self.ctx, team)
|
||||
save(self.ctx)
|
||||
self.ctx.save()
|
||||
return True
|
||||
else:
|
||||
del (self.ctx.name_aliases[team, slot])
|
||||
self.output(f"Removed Alias for {player_name}")
|
||||
update_aliases(self.ctx, team)
|
||||
save(self.ctx)
|
||||
self.ctx.save()
|
||||
return True
|
||||
else:
|
||||
self.output(response)
|
||||
|
|
Loading…
Reference in New Issue