wot/dbchunkpool.py
Joscha 9e5b5f874a Start work on server-side saving worlds
This commit includes a a few more changes because I'm too lazy to
clean them up:
 - fix chunk modification times
 - improve command line arguments
 - load multiple chunks at once
2017-04-16 13:52:39 +00:00

127 lines
2.9 KiB
Python

import sqlite3
import time
import threading
from chunks import ChunkPool
from utils import Position
class ChunkDB():
"""
Load and save chunks to a SQLite db.
"""
def __init__(self, filename):
self.dbfilename = filename
def transaction(func):
def wrapper(self, *args, **kwargs):
con = sqlite3.connect(self.dbfilename)
try:
with con:
return func(self, con, *args, **kwargs)
finally:
con.close()
return wrapper
@transaction
def save_many(self, con, chunks):
print("save_many")
@transaction
def load_many(self, con, coords):
print("load_many")
return [(coor, None) for coor in coords]
class DBChunkPool(ChunkPool):
"""
A ChunkPool that can load/save chunks from/to a database.
"""
def __init__(self, filename):
super().__init__()
self._chunkdb = ChunkDB(filename)
self.save_period = 10 # save and clean up every minute
self.max_age = 20 # ca. one minute until a chunk is unloaded again
self.save_thread = threading.Thread(
target=self.perodic_save,
name="save_thread",
daemon=True
)
self.save_thread.start()
def save_changes(self):
diffs = self.commit_changes()
changed_chunks = []
for dchunk in diffs:
pos = dchunk[0]
chunk = self.get(pos)
changed_chunks.append((pos, chunk))
self._chunkdb.save_many(changed_chunks)
def load(self, pos):
print("Loading individual chunk...")
raise Exception
def load_list(self, coords):
print("Loading chunk list...")
to_load = [pos for pos in coords if pos not in self._chunks]
chunks = self._chunkdb.load_many(to_load)
for dchunk in chunks:
pos = dchunk[0]
chunk = dchunk[1]
if chunk:
self.set(pos, chunk)
else:
self.create(pos)
def perodic_save(self):
while True:
time.sleep(self.save_period)
with self:
print("BEFORE:::")
self.print_chunks()
self.save_changes()
# unload old chunks
now = time.time()
for pos, chunk in self._chunks.items():
print(f"p{pos} :: t{now} :: m{chunk.last_modified} :: a{chunk.age(now)}")
self.clean_up(condition=lambda pos, chunk: chunk.age(now) > self.max_age)
print("AFTER:::")
self.print_chunks()
def get_min_max(self):
minx = min(pos.x for pos in self._chunks)
maxx = max(pos.x for pos in self._chunks)
miny = min(pos.y for pos in self._chunks)
maxy = max(pos.y for pos in self._chunks)
return minx, maxx, miny, maxy
def print_chunks(self):
if self._chunks:
minx, maxx, miny, maxy = self.get_min_max()
sizex, sizey = maxx - minx + 1, maxy - miny + 1
print("" + ""*sizex*2 + "")
for y in range(miny, maxy + 1):
line = []
for x in range(minx, maxx + 1):
chunk = self._chunks.get(Position(x, y))
if chunk:
if chunk.empty():
line.append("()")
else:
line.append("[]")
else:
line.append(" ")
line = "".join(line)
print("" + line + "")
print("" + ""*sizex*2 + "")