[FIX] concurrent requests overwriting each other's literal contexts and domains dicts...
authorXavier Morel <xmo@openerp.com>
Mon, 17 Oct 2011 11:07:56 +0000 (13:07 +0200)
committerXavier Morel <xmo@openerp.com>
Mon, 17 Oct 2011 11:07:56 +0000 (13:07 +0200)
also prune empty/useless openerp sessions from the http sessions
before saving the http session, in order not to have *kilobytes* of
crud lying around the magnetic tape

bzr revid: xmo@openerp.com-20111017110756-sqociibor79i6svz

addons/web/common/http.py

index 314ac8c..f496c15 100644 (file)
@@ -296,6 +296,35 @@ def session_context(request, storage_path, session_cookie='sessionid'):
     try:
         yield request.session
     finally:
+        # Remove all OpenERPSession instances with no uid, they're generated
+        # either by login process or by HTTP requests without an OpenERP
+        # session id, and are generally noise
+        for key, value in request.session.items():
+            if isinstance(value, session.OpenERPSession) and not value._uid:
+                del request.session[key]
+
+        # FIXME: remove this when non-literals disappear
+        if sid:
+            # Re-load sessions from storage and merge non-literal
+            # contexts and domains (they're indexed by hash of the
+            # content so conflicts should auto-resolve), otherwise if
+            # two requests alter those concurrently the last to finish
+            # will overwrite the previous one, leading to loss of data
+            # (a non-literal is lost even though it was sent to the
+            # client and client errors)
+            #
+            # note that domains_store and contexts_store are append-only (we
+            # only ever add items to them), so we can just update one with the
+            # other to get the right result, if we want to merge the
+            # ``context`` dict we'll need something smarter
+            in_store = session_store.get(sid)
+            for k, v in request.session.iteritems():
+                stored = in_store.get(k)
+                if stored and isinstance(v, session.OpenERPSession)\
+                        and v != stored:
+                    v.contexts_store.update(stored.contexts_store)
+                    v.domains_store.update(stored.domains_store)
+
         session_store.save(request.session)
 
 #----------------------------------------------------------