# $SnapHashLicense:
#
# SnapLogic - Open source data services
#
# Copyright (C) 2008, SnapLogic, Inc. All rights reserved.
#
# See http://www.snaplogic.org for more information about
# the SnapLogic project.
#
# This program is free software, distributed under the terms of
# the GNU General Public License Version 2. See the LEGAL file
# at the top of the source tree.
#
# "SnapLogic" is a trademark of SnapLogic, Inc.
#
#
# $
# $Id: file_lock.py 1967 2008-03-26 23:23:36Z jbrendel $
"""
This module provides methods for locking and unlocking files
For OS platforms that support POSIX standard, the locking mechanism uses fcntl.
For Windows, there are two mechanisms availbable. One uses the msvcrt module which
comes with python on Windows. This mechanim does not have a blocking lock, so it
forces us to implement a sleep-and-poll approach to check for availability of lock.
The other approach uses pywin32 module. This module needs to be downloaded (around 4 MB)
and is available only for 32 bit Windows. It does support blocking locks and is thus a much
more efficient lock for our needs. The code in this module checks if pywin32 is installed,
if it is, then that module is used. Otherwise, the code falls back on msvcrt module.
Some of the code is based on the code snippet provided in the O'Rielly book
Python Cookbook http://safari.oreilly.com/0596007973/pythoncook2-CHP-2-SECT-28#snippet
"""
import os
import sys
import time
from snaplogic.common.snap_exceptions import *
if os.name in ('nt','dos','ce') or sys.platform == 'cygwin':
# Windows lock implementation.
try:
# Requires pywin32 (http://sourceforge.net/project/showfiles.php?group_id=78018)
# to work on Windows (NT, 2K, XP, _not_ /95 or /98)
# Attempt to load pywin32 modules.
import win32con, win32file, pywintypes
except:
win32con = None
win32file = None
pywintypes = None
# snap_use_msvcrt is an environment variable, which can for the use
# of msvcrt module, even if pywin32 modules are available. It is mainly
# used in test environment.
if (win32file is not None) and ("snap_use_msvcrt" not in os.environ):
LOCK_EX = win32con.LOCKFILE_EXCLUSIVE_LOCK
LOCK_SH = 0 # the default
LOCK_NB = win32con.LOCKFILE_FAIL_IMMEDIATELY
__overlapped = pywintypes.OVERLAPPED()
def lock(file, flags):
"""Lock using pywin32 interfaces."""
hfile = win32file._get_osfhandle(file.fileno())
win32file.LockFileEx(hfile, flags, 0, -0x10000 , __overlapped)
def unlock(file):
"""Unlock using pywin32 interfaces."""
hfile = win32file._get_osfhandle(file.fileno())
win32file.UnlockFileEx(hfile, 0, -0x10000 , __overlapped)
else:
import msvcrt
import errno
# We don't have pywin32 installed. Use the poor man's file lock.
# This locking mechanism does not have blocking locks. So, a
# polling approach has been implemented.
LOCK_SH = 0
LOCK_EX = 1
LOCK_NB = 2
def lock(file, flags):
"""Lock using msvcrt interfaces."""
file.seek(0)
# msvcrt's locking() method does not have a blocking lock.
# (It just retries once per second for ten seconds).
if flags & LOCK_NB:
blocking = False
else:
blocking = True
if flags & LOCK_EX:
f = msvcrt.LK_NBLCK
else:
f = msvcrt.LK_NBRLCK
while 1:
try:
msvcrt.locking(file.fileno(), f, 1)
return
except IOError, e:
if e.errno not in (errno.EAGAIN, errno.EACCES) or not blocking:
raise
elif flags & LOCK_NB:
time.sleep(0.3)
def unlock(file):
"""Unlock using msvcrt interfaces."""
file.seek(0)
msvcrt.locking(file.fileno(), msvcrt.LK_UNLCK, 1)
elif os.name == 'posix':
# POSIX lock implementation.
import fcntl
from fcntl import LOCK_EX,LOCK_SH,LOCK_NB
def lock(file, flags):
fcntl.flock(file.fileno(), flags)
def unlock(file):
fcntl.flock(file.fileno(), fcntl.LOCK_UN)
else:
raise SnapObjNotFoundError("file_lock only defined for nt and posix platforms")
|