> On Mar 8, 2023, at 07:29, Christopher Schultz <ch...@christopherschultz.net> 
> wrote:
> 
> All,
> 
> Please see https://bz.apache.org/bugzilla/show_bug.cgi?id=66513 for reference.
> 
> It appears that the synchronization used by the PersistentManager can cause 
> problems when used with the PersistentValve and DataSource/JDBCStore.
> 
> The problem is that PersistentManager assumes that the Session object can be 
> used as a synchronization monitor to load/update the session in the Store. 
> The DataSource/JDBCStore implementation uses an INSERT to create a new 
> session, and a DELETE-then-INSERT to re-write the session data in the db.
> 
> When two requests arrive simultaneously, thread scheduling can cause 
> DELETE-then-DELETE-then-INSERT-then-INSERT which causes a duplicate PK 
> violation.
> 
> If the PersistentValve were not in use, the in-memory Session would be 
> stable. PersistentValve re-loads the Session from the Store on ever request, 
> rendering the PersistentManager's synchronized(session) attempt to protect 
> things useless.
> 
> I think a simple way to fix this might be to change:
> 
> // PersistentManager.java:478~
>        if(session != null) {
>            synchronized(session){
>                session = super.findSession(session.getIdInternal());
>                if(session != null){
>                   // To keep any external calling code from messing up the
>                   // concurrency.
>                   session.access();
>                   session.endAccess();
>                }
>            }
>        }
> 
> to this:
> 
>        if(session != null) {
>            sessionId = String.intern(sessionId);
>            synchronized(sessionId){
>                session = super.findSession(session.getIdInternal());
>                if(session != null){
>                   // To keep any external calling code from messing up the
>                   // concurrency.
>                   session.access();
>                   session.endAccess();
>                }
>            }
>        }
> 
> This swaps the Session object for the sessionId as the synchronization 
> monitor. We use String.intern to ensure that we always have the same exact 
> object, even across sessions, request, etc.
-1

This method does seem very simple and solves this problem, but it’s not as good 
as you might think, see below:
https://shipilev.net/jvm/anatomy-quarks/10-string-intern/ 
<https://shipilev.net/jvm/anatomy-quarks/10-string-intern/>

So I don’t think it should be the preferred option.

Han

> 
> This is *a* way to solve this problem. There are other ways.
> 
> Another way is also a TODO in the DataSourceRealm code which suggests using 
> UPDATE for sessions that already exist. That is probably worth implementing, 
> and it would fix this particular issue.
> 
> Note that it is essentially impossible to prevent thread scheduling, requests 
> to other members of the cluster, etc. to prevent data-loss from the session 
> and this BZ isn't asking us to fix that. It's only asking that a single 
> Tomcat node with PersistentValve enabled doesn't cause thee duplicate PK 
> violations for some pretty basic usages.
> 
> -chris
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: dev-unsubscr...@tomcat.apache.org
> For additional commands, e-mail: dev-h...@tomcat.apache.org
> 

Reply via email to