Mercurial > bitten > bitten-test
changeset 281:33625fa61d6c
* If a slave disconnects after the master has started to create a snapshot archive for it, just remain calm and keep the archive in place.
* Fix a potential race condition where two slaves could trigger the same snapshot archive to be created.
author | cmlenz |
---|---|
date | Fri, 14 Oct 2005 19:50:08 +0000 |
parents | 24ba49dee33c |
children | 3950b8141e85 |
files | bitten/master.py bitten/snapshot.py |
diffstat | 2 files changed, 30 insertions(+), 14 deletions(-) [+] |
line wrap: on
line diff
--- a/bitten/master.py +++ b/bitten/master.py @@ -177,6 +177,10 @@ if worker.isAlive(): self.master.schedule(2, _check_snapshot) else: + if self.name not in self.master.handlers: + # The slave disconnected while we were building + # the archive + return snapshot = snapshots.get(build.rev) if snapshot is None: log.error('Failed to create snapshot archive for '
--- a/bitten/snapshot.py +++ b/bitten/snapshot.py @@ -99,6 +99,8 @@ self._lock = threading.RLock() self._cleanup() + self._workers = {} + def _scan(self): """Find all existing snapshots in the directory.""" for filename in [f for f in os.listdir(self.directory) @@ -150,23 +152,31 @@ function is the thread object. The caller may use this object to check for completion of the operation. """ - prefix = self.prefix + '_r' + str(rev) - filename = prefix + '.zip' - filepath = os.path.join(self.directory, filename) - if os.path.exists(filepath): - raise IOError, 'Snapshot file already exists at %s' % filepath + self._lock.acquire() + try: + repos = self.env.get_repository() + root = repos.get_node(self.config.path or '/', rev) + assert root.isdir, '"%s" is not a directory' % self.config.path - repos = self.env.get_repository() - root = repos.get_node(self.config.path or '/', rev) - assert root.isdir, '"%s" is not a directory' % self.config.path + if root.rev in self._workers: + return self._workers[root.rev] - self._cleanup(self.limit - 1) + prefix = self.prefix + '_r' + str(rev) + filename = prefix + '.zip' + filepath = os.path.join(self.directory, filename) + if os.path.exists(filepath): + raise IOError, 'Snapshot file already exists at %s' % filepath - worker = threading.Thread(target=self._create, - args=(prefix, root, filepath), - name='Create snapshot %s' % filename) - worker.start() - return worker + self._cleanup(self.limit - 1) + + worker = threading.Thread(target=self._create, + args=(prefix, root, filepath), + name='Create snapshot %s' % filename) + worker.start() + self._workers[root.rev] = worker + return worker + finally: + self._lock.release() def _create(self, prefix, root, filepath): """Actually create a snapshot archive. @@ -185,6 +195,7 @@ path = os.path.join(prefix, name).rstrip('/\\') + '/' info = zipfile.ZipInfo(path) zip.writestr(info, '') + log.debug('Adding directory %s to archive' % name) for entry in node.get_entries(): _add_entry(entry) time.sleep(.5) # be nice @@ -211,6 +222,7 @@ self._lock.acquire() try: self._index.append((os.path.getmtime(filepath), root.rev, filepath)) + del self._workers[root.rev] finally: self._lock.release() log.info('Prepared snapshot archive at %s', filepath)