Back to index

obnam  1.1
lockmgr.py
Go to the documentation of this file.
00001 # Copyright 2012  Lars Wirzenius
00002 # 
00003 # This program is free software: you can redistribute it and/or modify
00004 # it under the terms of the GNU General Public License as published by
00005 # the Free Software Foundation, either version 3 of the License, or
00006 # (at your option) any later version.
00007 # 
00008 # This program is distributed in the hope that it will be useful,
00009 # but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00011 # GNU General Public License for more details.
00012 # 
00013 # You should have received a copy of the GNU General Public License
00014 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
00015 
00016 
00017 import os
00018 import time
00019 
00020 import obnamlib
00021 
00022 
00023 class LockManager(object):
00024 
00025     '''Lock and unlock sets of directories at once.'''
00026     
00027     def __init__(self, fs, timeout, client):
00028         self._fs = fs
00029         self.timeout = timeout
00030         data = ["[lockfile]"]
00031         data = data + ["client=" + client]
00032         data = data + ["pid=%d" % os.getpid()]
00033         data = data + self._read_boot_id()
00034         self.data = '\r\n'.join(data)
00035 
00036     def _read_boot_id(self):
00037         try:
00038             with open("/proc/sys/kernel/random/boot_id", "r") as f:
00039                 boot_id = f.read().strip()
00040         except: # pragma: no cover
00041             return []
00042         else:
00043             return ["boot_id=%s" % boot_id]
00044 
00045     def _time(self): # pragma: no cover
00046         return time.time()
00047         
00048     def _sleep(self): # pragma: no cover
00049         time.sleep(1)
00050         
00051     def sort(self, dirnames):
00052         def bytelist(s):
00053             return [ord(s) for s in str(s)]
00054         return sorted(dirnames, key=bytelist)
00055 
00056     def _lockname(self, dirname):
00057         return os.path.join(dirname, 'lock')
00058 
00059         
00060     def _lock_one(self, dirname):
00061         started = self._time()
00062         while True:
00063             lock_name = self._lockname(dirname)
00064             try:
00065                 self._fs.lock(lock_name, self.data)
00066             except obnamlib.LockFail:
00067                 if self._time() - started >= self.timeout:
00068                     raise obnamlib.LockFail('Lock timeout: %s' % lock_name)
00069             else:
00070                 return
00071             self._sleep()
00072         
00073     def _unlock_one(self, dirname):
00074         self._fs.unlock(self._lockname(dirname))
00075         
00076     def lock(self, dirnames):
00077         '''Lock ALL the directories.'''
00078         we_locked = []
00079         for dirname in self.sort(dirnames):
00080             try:
00081                 self._lock_one(dirname)
00082             except obnamlib.LockFail:
00083                 self.unlock(we_locked)
00084                 raise
00085             else:
00086                 we_locked.append(dirname)
00087 
00088     def unlock(self, dirnames):
00089         '''Unlock ALL the directories.'''
00090         for dirname in self.sort(dirnames):
00091             self._unlock_one(dirname)
00092