mirror of
https://github.com/pgadmin-org/pgadmin4.git
synced 2025-02-25 18:55:31 -06:00
Make the session thread safe.
As sessions in pgAdmin4 are filesystem based session, they need locking for avoiding the access from multiple threads, specially running as an WSGI application. Fixes #3547
This commit is contained in:
parent
70c95fcdd5
commit
013ad7446f
@ -20,5 +20,6 @@ Bug fixes
|
||||
| `Bug #3407 <https://redmine.postgresql.org/issues/3407>`_ - Fix keyboard shortcuts layout in the preferences panel.
|
||||
| `Bug #3461 <https://redmine.postgresql.org/issues/3461>`_ - Ensure that refreshing a node also updates the Property list.
|
||||
| `Bug #3528 <https://redmine.postgresql.org/issues/3528>`_ - Handle connection errors properly in the query tool.
|
||||
| `Bug #3547 <https://redmine.postgresql.org/issues/3578>`_ - Make session implementation thread safe
|
||||
| `Bug #3558 <https://redmine.postgresql.org/issues/3558>`_ - Fix sort/filter dialog editing issue.
|
||||
| `Bug #3578 <https://redmine.postgresql.org/issues/3578>`_ - Ensure sql for Role should be visible in SQL panel for GPDB.
|
||||
|
@ -24,6 +24,7 @@ import random
|
||||
import string
|
||||
import time
|
||||
from uuid import uuid4
|
||||
from threading import Lock
|
||||
from flask import current_app, request, flash, redirect
|
||||
from flask_login import login_url
|
||||
from pgadmin.utils.ajax import make_json_response
|
||||
@ -50,6 +51,9 @@ def _calc_hmac(body, secret):
|
||||
).decode()
|
||||
|
||||
|
||||
sess_lock = Lock()
|
||||
|
||||
|
||||
class ManagedSession(CallbackDict, SessionMixin):
|
||||
def __init__(self, initial=None, sid=None, new=False, randval=None,
|
||||
hmac_digest=None):
|
||||
@ -111,8 +115,9 @@ class CachingSessionManager(SessionManager):
|
||||
def _normalize(self):
|
||||
if len(self._cache) > self.num_to_store:
|
||||
# Flush 20% of the cache
|
||||
while len(self._cache) > (self.num_to_store * 0.8):
|
||||
self._cache.popitem(False)
|
||||
with sess_lock:
|
||||
while len(self._cache) > (self.num_to_store * 0.8):
|
||||
self._cache.popitem(False)
|
||||
|
||||
def new_session(self):
|
||||
session = self.parent.new_session()
|
||||
@ -122,59 +127,64 @@ class CachingSessionManager(SessionManager):
|
||||
if request.path.startswith(sp):
|
||||
return session
|
||||
|
||||
self._cache[session.sid] = session
|
||||
with sess_lock:
|
||||
self._cache[session.sid] = session
|
||||
self._normalize()
|
||||
|
||||
return session
|
||||
|
||||
def remove(self, sid):
|
||||
self.parent.remove(sid)
|
||||
if sid in self._cache:
|
||||
del self._cache[sid]
|
||||
with sess_lock:
|
||||
self.parent.remove(sid)
|
||||
if sid in self._cache:
|
||||
del self._cache[sid]
|
||||
|
||||
def exists(self, sid):
|
||||
if sid in self._cache:
|
||||
return True
|
||||
return self.parent.exists(sid)
|
||||
with sess_lock:
|
||||
if sid in self._cache:
|
||||
return True
|
||||
return self.parent.exists(sid)
|
||||
|
||||
def get(self, sid, digest):
|
||||
session = None
|
||||
if sid in self._cache:
|
||||
session = self._cache[sid]
|
||||
if session.hmac_digest != digest:
|
||||
session = None
|
||||
with sess_lock:
|
||||
if sid in self._cache:
|
||||
session = self._cache[sid]
|
||||
if session.hmac_digest != digest:
|
||||
session = None
|
||||
|
||||
# reset order in Dict
|
||||
del self._cache[sid]
|
||||
# reset order in Dict
|
||||
del self._cache[sid]
|
||||
|
||||
if not session:
|
||||
session = self.parent.get(sid, digest)
|
||||
if not session:
|
||||
session = self.parent.get(sid, digest)
|
||||
|
||||
# Do not store the session if skip paths
|
||||
for sp in self.skip_paths:
|
||||
if request.path.startswith(sp):
|
||||
return session
|
||||
# Do not store the session if skip paths
|
||||
for sp in self.skip_paths:
|
||||
if request.path.startswith(sp):
|
||||
return session
|
||||
|
||||
self._cache[sid] = session
|
||||
self._cache[sid] = session
|
||||
self._normalize()
|
||||
|
||||
return session
|
||||
|
||||
def put(self, session):
|
||||
self.parent.put(session)
|
||||
with sess_lock:
|
||||
self.parent.put(session)
|
||||
|
||||
# Do not store the session if skip paths
|
||||
for sp in self.skip_paths:
|
||||
if request.path.startswith(sp):
|
||||
return
|
||||
# Do not store the session if skip paths
|
||||
for sp in self.skip_paths:
|
||||
if request.path.startswith(sp):
|
||||
return
|
||||
|
||||
if session.sid in self._cache:
|
||||
try:
|
||||
del self._cache[session.sid]
|
||||
except Exception:
|
||||
pass
|
||||
if session.sid in self._cache:
|
||||
try:
|
||||
del self._cache[session.sid]
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
self._cache[session.sid] = session
|
||||
self._cache[session.sid] = session
|
||||
self._normalize()
|
||||
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user