aprsd/aprsd/utils/objectstore.py

113 lines
3.1 KiB
Python

import logging
import os
import pathlib
import pickle
from oslo_config import cfg
CONF = cfg.CONF
LOG = logging.getLogger("APRSD")
class ObjectStoreMixin:
"""Class 'MIXIN' intended to save/load object data.
The asumption of how this mixin is used:
The using class has to have a:
* data in self.data as a dictionary
* a self.lock thread lock
* Class must specify self.save_file as the location.
When APRSD quits, it calls save()
When APRSD Starts, it calls load()
aprsd server -f (flush) will wipe all saved objects.
"""
def __len__(self):
return len(self.data)
def get_all(self):
with self.lock:
return self.data
def get(self, id):
with self.lock:
return self.data[id]
def _init_store(self):
if not CONF.enable_save:
return
sl = CONF.save_location
if not os.path.exists(sl):
LOG.warning(f"Save location {sl} doesn't exist")
try:
os.makedirs(sl)
except Exception as ex:
LOG.exception(ex)
def _save_filename(self):
save_location = CONF.save_location
return "{}/{}.p".format(
save_location,
self.__class__.__name__.lower(),
)
def _dump(self):
dump = {}
with self.lock:
for key in self.data.keys():
dump[key] = self.data[key]
return dump
def save(self):
"""Save any queued to disk?"""
if not CONF.enable_save:
return
if len(self) > 0:
LOG.info(
f"{self.__class__.__name__}::Saving"
f" {len(self)} entries to disk at"
f"{CONF.save_location}",
)
with open(self._save_filename(), "wb+") as fp:
pickle.dump(self._dump(), fp)
else:
LOG.debug(
"{} Nothing to save, flushing old save file '{}'".format(
self.__class__.__name__,
self._save_filename(),
),
)
self.flush()
def load(self):
if not CONF.enable_save:
return
if os.path.exists(self._save_filename()):
try:
with open(self._save_filename(), "rb") as fp:
raw = pickle.load(fp)
if raw:
self.data = raw
LOG.debug(
f"{self.__class__.__name__}::Loaded {len(self)} entries from disk.",
)
LOG.debug(f"{self.data}")
except (pickle.UnpicklingError, Exception) as ex:
LOG.error(f"Failed to UnPickle {self._save_filename()}")
LOG.error(ex)
self.data = {}
def flush(self):
"""Nuke the old pickle file that stored the old results from last aprsd run."""
if not CONF.enable_save:
return
if os.path.exists(self._save_filename()):
pathlib.Path(self._save_filename()).unlink()
with self.lock:
self.data = {}