Commits

Anonymous committed 7b355d0

* Added an optimization to the FileNamespaceContainer when used with
Session, such that the pickled contents of the file are not
read a second time when session.save() is called. (#64)

Comments (0)

Files changed (7)

   direct specification of the name of which memcache backend to use.
 * Basic container/file-based Session support working in Py3K. (#72)
 * Further Python 3 fixes
+* Added an optimization to the FileNamespaceContainer when used with 
+  Session, such that the pickled contents of the file are not 
+  read a second time when session.save() is called.  (#64)
 
 Release 1.5.4 (6/16/2010)
 =========================

beaker/container.py

 
         """
 
-    def acquire_write_lock(self, wait=True):
+    def acquire_write_lock(self, wait=True, replace=False):
         """Establish a write lock.
         
         This operation is called before a key is written.   
         
         By default the function returns ``True`` unconditionally.
         
+        'replace' is a hint indicating the full contents
+        of the namespace may be safely discarded. Some backends
+        may implement this (i.e. file backend won't unpickle the 
+        current contents).
+        
         """
         return True
 
     def get_access_lock(self):
         raise NotImplementedError()
 
-    def do_open(self, flags): 
+    def do_open(self, flags, replace): 
         raise NotImplementedError()
 
     def do_close(self): 
         finally:
             self.access_lock.release_read_lock()
 
-    def acquire_write_lock(self, wait=True): 
+    def acquire_write_lock(self, wait=True, replace=False): 
         r = self.access_lock.acquire_write_lock(wait)
         try:
             if (wait or r): 
-                self.open('c', checkcount = True)
+                self.open('c', checkcount = True, replace=replace)
             return r
         except:
             self.access_lock.release_write_lock()
         finally:
             self.access_lock.release_write_lock()
 
-    def open(self, flags, checkcount=False):
+    def open(self, flags, checkcount=False, replace=False):
         self.mutex.acquire()
         try:
             if checkcount:
                 if self.openers == 0: 
-                    self.do_open(flags)
+                    self.do_open(flags, replace)
                 self.openers += 1
             else:
-                self.do_open(flags)
+                self.do_open(flags, replace)
                 self.openers = 1
         finally:
             self.mutex.release()
                 list.append(self.file + os.extsep + ext)
         return list
 
-    def do_open(self, flags):
+    def do_open(self, flags, replace):
         debug("opening dbm file %s", self.file)
         try:
             self.dbm = self.dbmmodule.open(self.file, flags)
     def file_exists(self, file):
         return os.access(file, os.F_OK)
 
-    def do_open(self, flags):
-        if self.file_exists(self.file):
+    def do_open(self, flags, replace):
+        if not replace and self.file_exists(self.file):
             fh = open(self.file, 'rb')
             try:
                 self.hash = cPickle.load(fh)
-            except (IOError, OSError, EOFError, cPickle.PickleError, ValueError):
+            except (IOError, OSError, EOFError, 
+                    cPickle.PickleError, ValueError):
                 pass
             fh.close()
 

beaker/ext/database.py

             identifier ="databasecontainer/funclock/%s" % self.namespace,
             lock_dir = self.lock_dir)
 
-    def do_open(self, flags):
+    def do_open(self, flags, replace):
         # If we already loaded the data, don't bother loading it again
         if self.loaded:
             self.flags = flags

beaker/ext/google.py

         # this is weird, should probably be present
         return null_synchronizer()
 
-    def do_open(self, flags):
+    def do_open(self, flags, replace):
         # If we already loaded the data, don't bother loading it again
         if self.loaded:
             self.flags = flags

beaker/ext/sqla.py

             identifier ="databasecontainer/funclock/%s" % self.namespace,
             lock_dir=self.lock_dir)
 
-    def do_open(self, flags):
+    def do_open(self, flags, replace):
         if self.loaded:
             self.flags = flags
             return

beaker/session.py

                                     digest_filenames=False, 
                                     **self.namespace_args)
 
-        self.namespace.acquire_write_lock()
+        self.namespace.acquire_write_lock(replace=True)
         try:
             if accessed_only:
                 data = dict(self.accessed_dict.items())

tests/test_session.py

     session.delete()
     assert 'set_cookie' not in session.request
     assert 'cookie_out' not in session.request
+
+
+def test_file_based_replace_optimization():
+    """Test the file-based backend with session, 
+    which includes the 'replace' optimization.
+    
+    """
+
+    session = get_session(use_cookies=False, type='file', 
+                            data_dir='./cache')
+
+    session['foo'] = 'foo'
+    session['bar'] = 'bar'
+    session.save()
+
+    session = get_session(use_cookies=False, type='file', 
+                            data_dir='./cache', id=session.id)
+    assert session['foo'] == 'foo'
+    assert session['bar'] == 'bar'
+
+    session['bar'] = 'bat'
+    session['bat'] = 'hoho'
+    session.save()
+
+    session.namespace.do_open('c', False)
+    session.namespace['test'] = 'some test'
+    session.namespace.do_close()
+
+    session = get_session(use_cookies=False, type='file', 
+                            data_dir='./cache', id=session.id)
+
+    session.namespace.do_open('r', False)
+    assert session.namespace['test'] == 'some test'
+    session.namespace.do_close()
+
+    assert session['foo'] == 'foo'
+    assert session['bar'] == 'bat'
+    assert session['bat'] == 'hoho'
+    session.save()
+
+    # the file has been replaced, so our out-of-session
+    # key is gone
+    session.namespace.do_open('r', False)
+    assert 'test' not in session.namespace
+    session.namespace.do_close()