Merge branch 'master' of git://git.assembla.com/fpdb-eric

Conflicts:
	pyfpdb/HandHistoryConverter.py
This commit is contained in:
Worros 2009-08-12 22:53:49 +08:00
commit 116141b833
3 changed files with 3075 additions and 3075 deletions

File diff suppressed because it is too large Load Diff

View File

@ -1,271 +1,271 @@
# Code from http://ender.snowburst.org:4747/~jjohns/interlocks.py # Code from http://ender.snowburst.org:4747/~jjohns/interlocks.py
# Thanks JJ! # Thanks JJ!
import sys import sys
import os, os.path import os, os.path
import subprocess import subprocess
import time import time
import signal import signal
import base64 import base64
InterProcessLock = None InterProcessLock = None
""" """
Just use me like a thread lock. acquire() / release() / locked() Just use me like a thread lock. acquire() / release() / locked()
Differences compared to thread locks: Differences compared to thread locks:
1. By default, acquire()'s wait parameter is false. 1. By default, acquire()'s wait parameter is false.
2. When acquire fails, SingleInstanceError is thrown instead of simply returning false. 2. When acquire fails, SingleInstanceError is thrown instead of simply returning false.
3. acquire() can take a 3rd parameter retry_time, which, if wait is True, tells the locking 3. acquire() can take a 3rd parameter retry_time, which, if wait is True, tells the locking
mechanism how long to sleep between retrying the lock. Has no effect for unix/InterProcessLockFcntl. mechanism how long to sleep between retrying the lock. Has no effect for unix/InterProcessLockFcntl.
Differences in fpdb version to JJ's original: Differences in fpdb version to JJ's original:
1. Changed acquire() to return false like other locks 1. Changed acquire() to return false like other locks
2. Made acquire fail if same process already has the lock 2. Made acquire fail if same process already has the lock
""" """
class SingleInstanceError(RuntimeError): class SingleInstanceError(RuntimeError):
"Thrown when you try to acquire an InterProcessLock and another version of the process is already running." "Thrown when you try to acquire an InterProcessLock and another version of the process is already running."
class InterProcessLockBase: class InterProcessLockBase:
def __init__(self, name=None ): def __init__(self, name=None ):
self._has_lock = False self._has_lock = False
if not name: if not name:
name = sys.argv[0] name = sys.argv[0]
self.name = name self.name = name
def getHashedName(self): def getHashedName(self):
return base64.b64encode(self.name).replace('=','') return base64.b64encode(self.name).replace('=','')
def acquire_impl(self, wait): abstract def acquire_impl(self, wait): abstract
def acquire(self, wait=False, retry_time=1): def acquire(self, wait=False, retry_time=1):
if self._has_lock: # make sure 2nd acquire in same process fails if self._has_lock: # make sure 2nd acquire in same process fails
return False return False
while not self._has_lock: while not self._has_lock:
try: try:
self.acquire_impl(wait) self.acquire_impl(wait)
self._has_lock = True self._has_lock = True
#print 'i have the lock' #print 'i have the lock'
except SingleInstanceError: except SingleInstanceError:
if not wait: if not wait:
# raise # change back to normal acquire functionality, sorry JJ! # raise # change back to normal acquire functionality, sorry JJ!
return False return False
time.sleep(retry_time) time.sleep(retry_time)
return True return True
def release(self): def release(self):
self.release_impl() self.release_impl()
self._has_lock = False self._has_lock = False
def locked(self): def locked(self):
if self._has_lock: if self._has_lock:
return True return True
try: try:
self.acquire() self.acquire()
self.release() self.release()
return False return False
except SingleInstanceError: except SingleInstanceError:
return True return True
LOCK_FILE_DIRECTORY = '/tmp' LOCK_FILE_DIRECTORY = '/tmp'
class InterProcessLockFcntl(InterProcessLockBase): class InterProcessLockFcntl(InterProcessLockBase):
def __init__(self, name=None): def __init__(self, name=None):
InterProcessLockBase.__init__(self, name) InterProcessLockBase.__init__(self, name)
self.lockfd = 0 self.lockfd = 0
self.lock_file_name = os.path.join(LOCK_FILE_DIRECTORY, self.getHashedName() + '.lck') self.lock_file_name = os.path.join(LOCK_FILE_DIRECTORY, self.getHashedName() + '.lck')
assert(os.path.isdir(LOCK_FILE_DIRECTORY)) assert(os.path.isdir(LOCK_FILE_DIRECTORY))
# This is the suggested way to get a safe file name, but I like having a descriptively named lock file. # This is the suggested way to get a safe file name, but I like having a descriptively named lock file.
def getHashedName(self): def getHashedName(self):
import re import re
bad_filename_character_re = re.compile(r'/\?<>\\\:;\*\|\'\"\^=\.\[\]') bad_filename_character_re = re.compile(r'/\?<>\\\:;\*\|\'\"\^=\.\[\]')
return bad_filename_character_re.sub('_',self.name) return bad_filename_character_re.sub('_',self.name)
def acquire_impl(self, wait): def acquire_impl(self, wait):
self.lockfd = open(self.lock_file_name, 'w') self.lockfd = open(self.lock_file_name, 'w')
fcntrl_options = fcntl.LOCK_EX fcntrl_options = fcntl.LOCK_EX
if not wait: if not wait:
fcntrl_options |= fcntl.LOCK_NB fcntrl_options |= fcntl.LOCK_NB
try: try:
fcntl.flock(self.lockfd, fcntrl_options) fcntl.flock(self.lockfd, fcntrl_options)
except IOError: except IOError:
self.lockfd.close() self.lockfd.close()
self.lockfd = 0 self.lockfd = 0
raise SingleInstanceError('Could not acquire exclusive lock on '+self.lock_file_name) raise SingleInstanceError('Could not acquire exclusive lock on '+self.lock_file_name)
def release_impl(self): def release_impl(self):
fcntl.lockf(self.lockfd, fcntl.LOCK_UN) fcntl.lockf(self.lockfd, fcntl.LOCK_UN)
self.lockfd.close() self.lockfd.close()
self.lockfd = 0 self.lockfd = 0
try: try:
os.unlink(self.lock_file_name) os.unlink(self.lock_file_name)
except IOError: except IOError:
# We don't care about the existence of the file too much here. It's the flock() we care about, # We don't care about the existence of the file too much here. It's the flock() we care about,
# And that should just go away magically. # And that should just go away magically.
pass pass
class InterProcessLockWin32(InterProcessLockBase): class InterProcessLockWin32(InterProcessLockBase):
def __init__(self, name=None): def __init__(self, name=None):
InterProcessLockBase.__init__(self, name) InterProcessLockBase.__init__(self, name)
self.mutex = None self.mutex = None
def acquire_impl(self,wait): def acquire_impl(self,wait):
self.mutex = win32event.CreateMutex(None, 0, self.getHashedName()) self.mutex = win32event.CreateMutex(None, 0, self.getHashedName())
if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS: if win32api.GetLastError() == winerror.ERROR_ALREADY_EXISTS:
self.mutex.Close() self.mutex.Close()
self.mutex = None self.mutex = None
raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name) raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name)
def release_impl(self): def release_impl(self):
self.mutex.Close() self.mutex.Close()
class InterProcessLockSocket(InterProcessLockBase): class InterProcessLockSocket(InterProcessLockBase):
def __init__(self, name=None): def __init__(self, name=None):
InterProcessLockBase.__init__(self, name) InterProcessLockBase.__init__(self, name)
self.socket = None self.socket = None
self.portno = 65530 - abs(self.getHashedName().__hash__()) % 32749 self.portno = 65530 - abs(self.getHashedName().__hash__()) % 32749
def acquire_impl(self, wait): def acquire_impl(self, wait):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
try: try:
self.socket.bind(('127.0.0.1', self.portno)) self.socket.bind(('127.0.0.1', self.portno))
except socket.error: except socket.error:
self.socket.close() self.socket.close()
self.socket = None self.socket = None
raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name) raise SingleInstanceError('Could not acquire exclusive lock on ' + self.name)
def release_impl(self): def release_impl(self):
self.socket.close() self.socket.close()
self.socket = None self.socket = None
# Set InterProcessLock to the correct type given the sysem parameters available # Set InterProcessLock to the correct type given the sysem parameters available
try: try:
import fcntl import fcntl
InterProcessLock = InterProcessLockFcntl InterProcessLock = InterProcessLockFcntl
except ImportError: except ImportError:
try: try:
import win32event import win32event
import win32api import win32api
import winerror import winerror
InterProcessLock = InterProcessLockWin32 InterProcessLock = InterProcessLockWin32
except ImportError: except ImportError:
import socket import socket
InterProcessLock = InterProcessLockSocket InterProcessLock = InterProcessLockSocket
def test_construct(): def test_construct():
""" """
# Making the name of the test unique so it can be executed my multiple users on the same machine. # Making the name of the test unique so it can be executed my multiple users on the same machine.
>>> test_name = 'InterProcessLockTest' +str(os.getpid()) + str(time.time()) >>> test_name = 'InterProcessLockTest' +str(os.getpid()) + str(time.time())
>>> lock1 = InterProcessLock(name=test_name) >>> lock1 = InterProcessLock(name=test_name)
>>> lock1.acquire() >>> lock1.acquire()
>>> lock2 = InterProcessLock(name=test_name) >>> lock2 = InterProcessLock(name=test_name)
>>> lock3 = InterProcessLock(name=test_name) >>> lock3 = InterProcessLock(name=test_name)
# Since lock1 is locked, other attempts to acquire it fail. # Since lock1 is locked, other attempts to acquire it fail.
>>> lock2.acquire() >>> lock2.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> lock3.acquire() >>> lock3.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Release the lock and let lock2 have it. # Release the lock and let lock2 have it.
>>> lock1.release() >>> lock1.release()
>>> lock2.acquire() >>> lock2.acquire()
>>> lock3.acquire() >>> lock3.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Release it and give it back to lock1 # Release it and give it back to lock1
>>> lock2.release() >>> lock2.release()
>>> lock1.acquire() >>> lock1.acquire()
>>> lock2.acquire() >>> lock2.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
# Test lock status # Test lock status
>>> lock2.locked() >>> lock2.locked()
True True
>>> lock3.locked() >>> lock3.locked()
True True
>>> lock1.locked() >>> lock1.locked()
True True
>>> lock1.release() >>> lock1.release()
>>> lock2.locked() >>> lock2.locked()
False False
>>> lock3.locked() >>> lock3.locked()
False False
>>> lock1.locked() >>> lock1.locked()
False False
>>> if os.name == 'posix': >>> if os.name == 'posix':
... def os_independent_kill(pid): ... def os_independent_kill(pid):
... import signal ... import signal
... os.kill(pid, signal.SIGKILL) ... os.kill(pid, signal.SIGKILL)
... else: ... else:
... assert(os.name == 'nt') ... assert(os.name == 'nt')
... def os_independent_kill(pid): ... def os_independent_kill(pid):
... ''' http://www.python.org/doc/faq/windows/#how-do-i-emulate-os-kill-in-windows ''' ... ''' http://www.python.org/doc/faq/windows/#how-do-i-emulate-os-kill-in-windows '''
... import win32api ... import win32api
... import win32con ... import win32con
... import pywintypes ... import pywintypes
... handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE , pywintypes.FALSE, pid) ... handle = win32api.OpenProcess(win32con.PROCESS_TERMINATE , pywintypes.FALSE, pid)
... return (0 != win32api.TerminateProcess(handle, 0)) ... return (0 != win32api.TerminateProcess(handle, 0))
# Test to acquire the lock in another process. # Test to acquire the lock in another process.
>>> def execute(cmd): >>> def execute(cmd):
... cmd = 'import time;' + cmd + 'time.sleep(10);' ... cmd = 'import time;' + cmd + 'time.sleep(10);'
... process = subprocess.Popen([sys.executable, '-c', cmd]) ... process = subprocess.Popen([sys.executable, '-c', cmd])
... pid = process.pid ... pid = process.pid
... time.sleep(2) # quick hack, but we test synchronization in the end ... time.sleep(2) # quick hack, but we test synchronization in the end
... return pid ... return pid
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();') >>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
>>> lock1.acquire() >>> lock1.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> os_independent_kill(pid) >>> os_independent_kill(pid)
>>> time.sleep(1) >>> time.sleep(1)
>>> lock1.acquire() >>> lock1.acquire()
>>> lock1.release() >>> lock1.release()
# Testing wait # Testing wait
>>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();') >>> pid = execute('import interlocks;a=interlocks.InterProcessLock(name=\\''+test_name+ '\\');a.acquire();')
>>> lock1.acquire() >>> lock1.acquire()
Traceback (most recent call last): Traceback (most recent call last):
... ...
SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck SingleInstanceError: Could not acquire exclusive lock on /tmp/test.lck
>>> os_independent_kill(pid) >>> os_independent_kill(pid)
>>> lock1.acquire(True) >>> lock1.acquire(True)
>>> lock1.release() >>> lock1.release()
""" """
pass pass
if __name__=='__main__': if __name__=='__main__':
import doctest import doctest
doctest.testmod(optionflags=doctest.IGNORE_EXCEPTION_DETAIL) doctest.testmod(optionflags=doctest.IGNORE_EXCEPTION_DETAIL)

View File

@ -1,27 +1,27 @@
# script to update indexes on mysql (+other?) database # script to update indexes on mysql (+other?) database
select '1. Dropping indexes' as ' '; select '1. Dropping indexes' as ' ';
select 'Can''t drop messages indicate index already gone' as ' '; select 'Can''t drop messages indicate index already gone' as ' ';
ALTER TABLE `fpdb`.`Settings` DROP INDEX `id`; ALTER TABLE `fpdb`.`Settings` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Sites` DROP INDEX `id`; ALTER TABLE `fpdb`.`Sites` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Gametypes` DROP INDEX `id`; ALTER TABLE `fpdb`.`Gametypes` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Players` DROP INDEX `id`; ALTER TABLE `fpdb`.`Players` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Autorates` DROP INDEX `id`; ALTER TABLE `fpdb`.`Autorates` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Hands` DROP INDEX `id`; ALTER TABLE `fpdb`.`Hands` DROP INDEX `id`;
ALTER TABLE `fpdb`.`BoardCards` DROP INDEX `id`; ALTER TABLE `fpdb`.`BoardCards` DROP INDEX `id`;
ALTER TABLE `fpdb`.`TourneyTypes` DROP INDEX `id`; ALTER TABLE `fpdb`.`TourneyTypes` DROP INDEX `id`;
ALTER TABLE `fpdb`.`Tourneys` DROP INDEX `id`; ALTER TABLE `fpdb`.`Tourneys` DROP INDEX `id`;
ALTER TABLE `fpdb`.`TourneysPlayers` DROP INDEX `id`; ALTER TABLE `fpdb`.`TourneysPlayers` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HandsPlayers` DROP INDEX `id`; ALTER TABLE `fpdb`.`HandsPlayers` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HandsActions` DROP INDEX `id`; ALTER TABLE `fpdb`.`HandsActions` DROP INDEX `id`;
ALTER TABLE `fpdb`.`HudCache` DROP INDEX `id`; ALTER TABLE `fpdb`.`HudCache` DROP INDEX `id`;
select '2. Adding extra indexes on useful fields' as ' '; select '2. Adding extra indexes on useful fields' as ' ';
select 'Duplicate key name messages indicate new indexes already there' as ' '; select 'Duplicate key name messages indicate new indexes already there' as ' ';
ALTER TABLE `fpdb`.`tourneys` ADD INDEX `siteTourneyNo`(`siteTourneyNo`); ALTER TABLE `fpdb`.`tourneys` ADD INDEX `siteTourneyNo`(`siteTourneyNo`);
ALTER TABLE `fpdb`.`hands` ADD INDEX `siteHandNo`(`siteHandNo`); ALTER TABLE `fpdb`.`hands` ADD INDEX `siteHandNo`(`siteHandNo`);
ALTER TABLE `fpdb`.`players` ADD INDEX `name`(`name`); ALTER TABLE `fpdb`.`players` ADD INDEX `name`(`name`);