changeset 3859:8cb2f4ebd45f

caching: implemented file-like api (thanks to Thomas Pfaff for the patch)
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Wed, 16 Jul 2008 17:20:45 +0200
parents 5079d2246367
children c18d557b5aec
files MoinMoin/_tests/test_caching.py MoinMoin/caching.py
diffstat 2 files changed, 73 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/MoinMoin/_tests/test_caching.py	Mon Jul 14 23:28:38 2008 +0200
+++ b/MoinMoin/_tests/test_caching.py	Wed Jul 16 17:20:45 2008 +0200
@@ -76,6 +76,24 @@
         page._write_file(test_data2)
         assert cache.needsUpdate(page._text_filename())
 
+    def test_filelike_readwrite(self):
+        request = self.request
+        key = 'nooneknowsit'
+        arena = 'somethingfunny'
+        data = "dontcare"
+        cacheentry = caching.CacheEntry(request, arena, key, scope='wiki', do_locking=True,
+                 use_pickle=False, use_encode=True)
+        cacheentry.open(mode='w')
+        cacheentry.write(data)
+        cacheentry.close()
+
+        assert cacheentry.exists()
+
+        cacheentry.open(mode='r')
+        rdata = cacheentry.read()
+        cacheentry.close()
+
+        assert data == rdata
 
 coverage_modules = ['MoinMoin.caching']
 
--- a/MoinMoin/caching.py	Mon Jul 14 23:28:38 2008 +0200
+++ b/MoinMoin/caching.py	Wed Jul 16 17:20:45 2008 +0200
@@ -73,6 +73,7 @@
             self.lock_dir = os.path.join(self.arena_dir, '__lock__')
             self.rlock = lock.LazyReadLock(self.lock_dir, 60.0)
             self.wlock = lock.LazyWriteLock(self.lock_dir, 60.0)
+        self._fileobj = None
 
     def _filename(self):
         return os.path.join(self.arena_dir, self.key)
@@ -134,6 +135,60 @@
 #        else:
 #            logging.error("Can't acquire write lock in %s" % self.lock_dir)
 
+    def _determine_locktype(self, mode):
+        #returns the correct locker object for a specific file access mode
+        if 'r' in mode:
+            lock = self.rlock
+        if 'w' in mode or 'a' in mode:
+            lock = self.wlock
+        return lock
+
+    # file-like interface ----------------------------------------------------
+
+    def open(self, filename=None, mode='r', bufsize=-1):
+        if self._fileobj:
+            # bug-possibility: this doesn't check, if there is any lock on the file
+            # we assume this, as the first call to open should
+            # acquire the lock.
+            return
+        if filename is None:
+            filename = self._filename()
+        else:
+            raise Exception('caching: giving a filename is not supported (yet?)')
+
+        #acquire the correct lock for the desired mode
+        lock = self._determine_locktype(mode)
+
+        if not self.locking or self.locking and lock.acquire(1.0):
+            try:
+                self._fileobj = open(filename, mode, bufsize)
+            except IOError:
+                if self.locking:
+                    lock.release()
+                logging.error("Can't open cache file %s" % filename)
+                raise
+        else:
+            logging.error("Can't acquire read/write lock in %s" % self.lock_dir)
+
+
+    def read(self, size=-1):
+        return self._fileobj.read(size)
+
+    def write(self, data):
+        self._fileobj.write(data)
+
+    def close(self):
+        if self._fileobj:
+            lock = self._determine_locktype(self._fileobj.mode)
+            self._fileobj.close()
+
+        if self.locking:
+            lock.release()
+
+        self._fileobj = None
+
+    # ------------------------------------------------------------------------
+
     def update(self, content):
         try:
             fname = self._filename()