Mercurial > moin > 1.9
changeset 1314:62b8e7e8d5a5
Merge with main.
author | Alexander Schremmer <alex AT alexanderweb DOT de> |
---|---|
date | Thu, 17 Aug 2006 19:11:38 +0200 |
parents | 73ea47cbfc79 (current diff) fca5b70800b2 (diff) |
children | ed3baf538cd5 |
files | |
diffstat | 4 files changed, 141 insertions(+), 23 deletions(-) [+] |
line wrap: on
line diff
--- a/MoinMoin/caching.py Thu Aug 17 19:11:00 2006 +0200 +++ b/MoinMoin/caching.py Thu Aug 17 19:11:38 2006 +0200 @@ -8,11 +8,7 @@ import os from MoinMoin import config -from MoinMoin.util import filesys - -locking = 1 -if locking: - from MoinMoin.util import lock +from MoinMoin.util import filesys, lock class CacheEntry: def __init__(self, request, arena, key, scope='page_or_wiki', do_locking=True): @@ -28,6 +24,8 @@ 'farm' - a cache for the whole farm """ self.request = request + self.key = key + self.locking = do_locking if scope == 'page_or_wiki': # XXX DEPRECATED, remove later if isinstance(arena, str): self.arena_dir = os.path.join(request.cfg.cache_dir, request.cfg.siteid, arena) @@ -43,16 +41,17 @@ elif scope == 'farm': self.arena_dir = os.path.join(request.cfg.cache_dir, '__common__', arena) filesys.makeDirs(self.arena_dir) - self.key = key - self.locking = do_locking and locking if self.locking: self.lock_dir = os.path.join(self.arena_dir, '__lock__') - self.rlock = lock.ReadLock(self.lock_dir, 60.0) - self.wlock = lock.WriteLock(self.lock_dir, 60.0) + self.rlock = lock.LazyReadLock(self.lock_dir, 60.0) + self.wlock = lock.LazyWriteLock(self.lock_dir, 60.0) def _filename(self): return os.path.join(self.arena_dir, self.key) + def _tmpfilename(self): + return os.tempnam(self.arena_dir, self.key) + def exists(self): return os.path.exists(self._filename()) @@ -85,10 +84,15 @@ return needsupdate def copyto(self, filename): + # currently unused function import shutil + tmpfname = self._tmpfilename() + fname = self._filename() if not self.locking or self.locking and self.wlock.acquire(1.0): try: - shutil.copyfile(filename, self._filename()) + shutil.copyfile(filename, tmpfname) + # this is either atomic or happening with real locks set: + filesys.rename(tmpfname, fname) try: os.chmod(self._filename(), 0666 & config.umask) except OSError: @@ -100,15 +104,22 @@ self.request.log("Can't acquire write lock in %s" % self.lock_dir) def update(self, content, encode=False): + tmpfname = self._tmpfilename() + fname = self._filename() if encode: content = content.encode(config.charset) if not self.locking or self.locking and self.wlock.acquire(1.0): try: - f = open(self._filename(), 'wb') + # we do not write content to old inode, but to a new file + # se we don't need to lock when we just want to read the file + # (at least on POSIX, this works) + f = open(tmpfname, 'wb') f.write(content) f.close() + # this is either atomic or happening with real locks set: + filesys.rename(tmpfname, fname) try: - os.chmod(self._filename(), 0666 & config.umask) + os.chmod(fname, 0666 & config.umask) except OSError: pass finally: @@ -118,10 +129,17 @@ self.request.log("Can't acquire write lock in %s" % self.lock_dir) def remove(self): - try: - os.remove(self._filename()) - except OSError: - pass + if not self.locking or self.locking and self.wlock.acquire(1.0): + try: + try: + os.remove(self._filename()) + except OSError: + pass + finally: + if self.locking: + self.wlock.release() + else: + self.request.log("Can't acquire write lock in %s" % self.lock_dir) def content(self, decode=False): if not self.locking or self.locking and self.rlock.acquire(1.0):
--- a/MoinMoin/parser/text_moin_wiki.py Thu Aug 17 19:11:00 2006 +0200 +++ b/MoinMoin/parser/text_moin_wiki.py Thu Aug 17 19:11:38 2006 +0200 @@ -30,8 +30,11 @@ # some common strings PARENT_PREFIX = wikiutil.PARENT_PREFIX - sq_string = ur"('.*?')" # single quoted string - dq_string = ur"(\".*?\")" # double quoted string + # quoted strings (we require that there is at least one char (that is not the quoting char) + # inside to not confuse stuff like '''Contact:''' (just a bold Contact:) with interwiki markup + # OtherWiki:'Page with blanks' + sq_string = ur"('[^']+?')" # single quoted string + dq_string = ur"(\"[^\"]+?\")" # double quoted string q_string = ur"(%s|%s)" % (sq_string, dq_string) # quoted string attachment_schemas = ["attachment", "inline", "drawing"] punct_pattern = re.escape(u'''"\'}]|:,.)?!''')
--- a/MoinMoin/util/filesys.py Thu Aug 17 19:11:00 2006 +0200 +++ b/MoinMoin/util/filesys.py Thu Aug 17 19:11:38 2006 +0200 @@ -52,7 +52,7 @@ def rename(oldname, newname): - ''' Multiplatform rename + """ Multiplatform rename Needed because win32 rename is not POSIX compliant, and does not remove target file if it exists. @@ -62,14 +62,14 @@ FIXME: What about rename locking? we can have a lock file in the page directory, named: PageName.lock, and lock this file before we rename, then unlock when finished. - ''' + """ if os.name == 'nt': if os.path.isfile(newname): try: os.remove(newname) except OSError, er: pass # let os.rename give us the error (if any) - return os.rename(oldname, newname) + os.rename(oldname, newname) def copystat(src, dst):
--- a/MoinMoin/util/lock.py Thu Aug 17 19:11:00 2006 +0200 +++ b/MoinMoin/util/lock.py Thu Aug 17 19:11:38 2006 +0200 @@ -6,7 +6,7 @@ @license: GNU GPL, see COPYING for details. """ -import os, tempfile, time, errno +import os, sys, tempfile, time, errno # Temporary debugging aid, to be replaced with system wide debuging @@ -262,7 +262,6 @@ return True return False - class ReadLock(ExclusiveLock): """ Read lock @@ -305,3 +304,101 @@ self.writeLock.release() return False + +class LazyReadLock(ReadLock): + """ Lazy Read lock + + See ReadLock, but we do an optimization here: + If (and ONLY if) the resource protected by this lock is updated in a POSIX + style "write new content to tmpfile, rename tmpfile -> origfile", then reading + from an open origfile handle will give either the old content (when opened + before the rename happens) or the new content (when opened after the rename + happened), but never cause any trouble. This means that we don't have to lock + at all in that case. + + Of course this doesn't work for us on the win32 platform: + * using MoveFileEx requires opening the file with some FILE_SHARE_DELETE + mode - we currently don't do that + * Win 95/98/ME do not have MoveFileEx + We currently solve by using the non-lazy locking code in ReadLock class. + """ + def __init__(self, dir, timeout=None): + if sys.platform == 'win32': + ReadLock.__init__(self, dir, timeout) + else: # POSIX + self._locked = False + + def acquire(self, timeout=None): + if sys.platform == 'win32': + return ReadLock.acquire(self, timeout) + else: # POSIX + self._locked = True + return True + + def release(self): + if sys.platform == 'win32': + return ReadLock.release(self) + else: # POSIX + self._locked = False + + def exists(self): + if sys.platform == 'win32': + return ReadLock.exists(self) + else: # POSIX + return True + + def isExpired(self): + if sys.platform == 'win32': + return ReadLock.isExpired(self) + else: # POSIX + return True + + def expire(self): + if sys.platform == 'win32': + return ReadLock.expire(self) + else: # POSIX + return True + +class LazyWriteLock(WriteLock): + """ Lazy Write lock + + See WriteLock and LazyReadLock docs. + """ + def __init__(self, dir, timeout=None): + if sys.platform == 'win32': + WriteLock.__init__(self, dir, timeout) + else: # POSIX + self._locked = False + + def acquire(self, timeout=None): + if sys.platform == 'win32': + return WriteLock.acquire(self, timeout) + else: # POSIX + self._locked = True + return True + + def release(self): + if sys.platform == 'win32': + return WriteLock.release(self) + else: # POSIX + self._locked = False + + def exists(self): + if sys.platform == 'win32': + return WriteLock.exists(self) + else: # POSIX + return True + + def isExpired(self): + if sys.platform == 'win32': + return WriteLock.isExpired(self) + else: # POSIX + return True + + def expire(self): + if sys.platform == 'win32': + return WriteLock.expire(self) + else: # POSIX + return True + +