From c722716736c94261de77b337f1bffe924b8724e3 Mon Sep 17 00:00:00 2001 From: Tim Laszlo Date: Fri, 26 Oct 2012 15:23:48 -0500 Subject: Probes/DatabaseBackend: add a thread lock for databases that cannot handle multiple writes --- src/lib/Bcfg2/Server/Core.py | 3 +++ src/lib/Bcfg2/Server/Plugin/helpers.py | 29 +++++++++++++++++++++++++++++ src/lib/Bcfg2/Server/Plugins/Probes.py | 1 + 3 files changed, 33 insertions(+) (limited to 'src/lib') diff --git a/src/lib/Bcfg2/Server/Core.py b/src/lib/Bcfg2/Server/Core.py index 66a1a23a7..dca169b54 100644 --- a/src/lib/Bcfg2/Server/Core.py +++ b/src/lib/Bcfg2/Server/Core.py @@ -170,6 +170,9 @@ class BaseCore(object): #: :attr:`fam_thread`) to shutdown self.terminate = threading.Event() + #: RLock to be held on writes to the backend db + self.db_write_lock = threading.RLock() + # generate Django ORM settings. this must be done _before_ we # load plugins Bcfg2.settings.read_config(repo=self.datastore) diff --git a/src/lib/Bcfg2/Server/Plugin/helpers.py b/src/lib/Bcfg2/Server/Plugin/helpers.py index bbceb1989..c7798b705 100644 --- a/src/lib/Bcfg2/Server/Plugin/helpers.py +++ b/src/lib/Bcfg2/Server/Plugin/helpers.py @@ -118,6 +118,7 @@ class DatabaseBacked(Plugin): database. .. private-include: _use_db + .. private-include: _must_lock """ #: The option to look up in :attr:`section` to determine whether or @@ -148,6 +149,34 @@ class DatabaseBacked(Plugin): self.logger.error("%s is true but django not found" % self.option) return False + @property + def _must_lock(self): + """ Whether or not the backend database allows multiple + threads to write. """ + engine = self.core.setup.cfp.get(Bcfg2.Options.DB_ENGINE.cf[0], + Bcfg2.Options.DB_ENGINE.cf[1], + default=Bcfg2.Options.DB_ENGINE.default) + if engine == 'sqlite3': + return True + else: + return False + + @staticmethod + def _db_writer(fn): + """ Decorator to be used when a call will update the data + threads to write. """ + def _acquire_and_run(self, *args, **kwargs): + if self._must_lock: + try: + self.core.db_write_lock.acquire() + rv = fn(self, *args, **kwargs) + finally: + self.core.db_write_lock.release() + else: + rv = fn(self, *args, **kwargs) + return rv + return _acquire_and_run + class PluginDatabaseModel(object): """ A database model mixin that all database models used by diff --git a/src/lib/Bcfg2/Server/Plugins/Probes.py b/src/lib/Bcfg2/Server/Plugins/Probes.py index bb1cbf81c..78dd2af85 100644 --- a/src/lib/Bcfg2/Server/Plugins/Probes.py +++ b/src/lib/Bcfg2/Server/Plugins/Probes.py @@ -218,6 +218,7 @@ class Probes(Bcfg2.Server.Plugin.Probing, err = sys.exc_info()[1] self.logger.error("Failed to write probed.xml: %s" % err) + @Bcfg2.Server.Plugin.DatabaseBacked._db_writer def _write_data_db(self, client): """ Write received probe data to the database """ for probe, data in self.probedata[client.hostname].items(): -- cgit v1.2.3-1-g7c22