avoiding file corruption

Tim Scheidemantle tim at zoominternet.net
Sun Aug 27 10:51:23 EDT 2006


Amir Michail wrote:
> Hi,
>
> Trying to open a file for writing that is already open for writing
> should result in an exception.
Look at fcntl module, I use it in a class to control access from within my processes.
I don't think this functionality should be inherent to python though.
Keep in mind only my processes open the shelve db so your mileage may vary.
get and set methods are just for convenience 
This works under linux, don't know about windows.

#!/usr/bin/env python

import fcntl, shelve, time, bsddb
from os.path import exists

class fLocked:

    def __init__(self, fname):
        if exists(fname):
            #verify it is not corrupt
            bsddb.db.DB().verify(fname)
        self.fname = fname
        self.have_lock = False
        self.db = shelve.open(self.fname)
        self.fileno = self.db.dict.db.fd()

    def __del__(self):
        try: self.db.close()
        except: pass

    def aquire_lock(self, timeout = 5):
        if self.have_lock: return True
        started = time.time()
        while not self.have_lock and (time.time() - started < timeout):
            try:
                fcntl.flock(self.fileno, fcntl.LOCK_EX + fcntl.LOCK_NB)
                self.have_lock = True
            except IOError:
                # wait for it to become available
                time.sleep(.5)
        return self.have_lock

    def release_lock(self):
        if self.have_lock:
            fcntl.flock(self.fileno, fcntl.LOCK_UN)
            self.have_lock = False
        return not self.have_lock

    def get(self, key, default = {}):
        if self.aquire_lock():
            record = self.db.get(key, default)
            self.release_lock()
        else:
            raise IOError, "Unable to lock %s" % self.fname
        return record

    def set(self, key, value):
        if self.aquire_lock():
            self.db[key] = value
            self.release_lock()
        else:
            raise IOError, "Unable to lock %s" % self.fname

if __name__ == '__main__':
    fname = 'test.db'
    dbs = []
    for i in range(2): dbs.append(fLocked(fname))
    print dbs[0].aquire_lock()
    print dbs[1].aquire_lock(1)     #should fail getting flock
    dbs[0].release_lock()
    print dbs[1].aquire_lock()      #should be able to get lock


--Tim




More information about the Python-list mailing list