tomcat-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Raiden <rai...@wonko.inow.com>
Subject RE: How to synchronize based on session? (Prevent multiple submissions of forms)
Date Tue, 01 Jul 2003 22:35:03 GMT
Hello Justin,

Thanks for your response.  My understanding is that there will be
multiple instances of a servlet depending on what the container thinks
is necessary.  This will most likely happen, because this is a high-volume
site.  If that's the case, won't there be multiple instances of the
servlet, each with its own member variable?  I believe this would lead
for varying results as a particular session could access any of these
instances on a given request.

Now granted, what you've mentioned below will make the race condition even
harder to meet, since we've now introduced a level of synchronization
based on the servlets themselves, but I believe it still has the potential
to be a problem... since two different instances of the servlet could both
attempt to add the session attribute at exactly the same time... even
though each has its own respective lock.

As you've probably guessed, we've been avoiding the single-threaded
servlet model, because we do have such a large volume of
simultaneous accesses on these pages.

Thanks again,
-Raiden


On Tue, 1 Jul 2003, Justin Ruthenbeck wrote:

>
> If your code worked like this:
>
> 1:   if (session.getAttribute(LOCKED_ATTR) == LOCKED)
> 2:      return user a waiting page
> 3:   else
> 4:   {
> 5:      session.setAttribute(LOCKED_ATTR, LOCKED)
> 6:      work with submitted data
> 7:   }
>
> then you're right -- it's possible for one thread to get interrupted after
> evaluating line 1 to "false".  Another thread could come in, evaluate line
> 1 to "false" again and you'd end up with two threads doing the "work with
> submitted data" code (a double submission).
>
> I don't see any way around this save for synchronizing on a lock in your
> servlet.  Don't worry about setting anything at Session creation time ...
> make your logic do something like the following:
>
> // Member variable
> protected Object m_synchObj = new Object();
>
> // In your service() method
> boolean processData = false;
> synchronized (m_synchObj)
> {
>     if (session.getAttribute(LOCKED_ATTR) != LOCKED)
>     {
>        session.setAttribute(LOCKED_ATTR, LOCKED);
>        processData = true;
>     }
> }
> if (processData)
> {
>     [Process the Data]
> }
> else
> {
>     [Send user to a "waiting" page]
> }
>
> True, you've now got a potential bottleneck in your servlet since every
> thread for that servlet waits (a small amount of time) on a single
> object.  Unless you've got *LOTS* of concurrent servlet threads, I don't
> think this would affect you.  I haven't given due diligence to the thought
> of synching on an Object in the session, but perhaps that's a better idea
> -- seems like you could still have a race condition if two thread both
> tried to create a session at the same time (perhaps Tomcat guarantees this
> won't happen by synching in it's session creation code?).  You could
> probably work something out with an HttpSessionListener.  Me?  I'd synch on
> the servlet in favor of simplifying my code.
>
> justin
>
>
> At 02:56 PM 7/1/2003, you wrote:
> >Hi Stefan,
> >
> >Thanks for the explanation.  That makes sense, except how can you make
> >sure that the object is added to the session only once, when the session
> >is created?
> >
> >It would seem like you would need to synchronize on something else for
> >adding the object to the session, because there might be a race
> >condition (unless there is a special bit of code that is only ever called
> >once, when the session is created).  Otherwise, two different threads
> >might each have their own instance of the lock object.
> >
> >How do I guarantee that the lock object is only created once, at the time
> >the session is created?
> >
> >Thanks,
> >Raiden
> >
> >
> >On Tue, 1 Jul 2003, Stefan Radzom wrote:
> >
> > > For security reasons your are not handed the internal
> > > org.apache.catalina.session.StandardSession . Instead, the implicit session
> > > you are trying to synchronize holds a reference to
> > > org.apache.catalina.session.StandardSessionFacade which is backed by the
> > > actual StandardSession to which all method calls are delegated. The facade
> > > object can therefore change between different requests, thus making it not
> > > appropriate for synchronisation.
> > >
> > > Try putting a dummy object into the session when creating a new session:
> > > session.setAttribute("lock", new Object()) . On subsequent requests you can
> > > get the attribute and obtain a lock on this object.
> > >
> > > Object lock = session.getAttribute("lock");
> > > synchronized (lock) { ; }
> > >
> > > -Stefan
> > >
> > >
> > > > -----Original Message-----
> > > > From: Raiden [mailto:raiden@wonko.inow.com]
> > > > Sent: Tuesday, July 01, 2003 8:19 PM
> > > > To: tomcat-user@jakarta.apache.org
> > > > Subject: How to synchronize based on session? (Prevent
> > > > multiple submissions of forms)
> > > >
> > > >
> > > > Hello,
> > > >
> > > > We are trying to prevent the "multiple submission of a form problem",
> > > > that can result when a user double-clicks the submit button.
> > > > We have a
> > > > process in place, but we have been unable to get the session based
> > > > synchronization to work correctly.
> > > >
> > > > Our order page submits to a "meta-refresh" page that checks to see the
> > > > current status of the order processing each time it loads.
> > > > If there is
> > > > an error, it sends the user back to the order page.  If the order was
> > > > successful, the user is sent to the success page.  If the
> > > > order is still
> > > > processing, it refreshes in 5 seconds (and meanwhile, the user has a
> > > > pretty 5 second progress bar to watch).  However, The
> > > > relevant snippet of
> > > > code is below:
> > > >
> > > > String nextUrl = null;
> > > > synchronized (session) {
> > > >   BigDecimal status =
> > > >     (BigDecimal)session.getAttribute(SiteProps.PROCESS_STATUS);
> > > >
> > > >   if (status != null) {
> > > >     System.out.println("  Processing has already begun.  Checking
> > > > status.");
> > > >
> > > >     if (status.equals(SiteProps.PROCESS_SUCCESS)) {
> > > >       System.out.println("  We already know it was approved.
> > > > Just showing
> > > > them the success page.");
> > > >       nextUrl = "/success.jsp";
> > > >       response.sendRedirect(response.encodeRedirectUrl(nextUrl));
> > > >       return;  // will remove status object on next page
> > > >     } else if (status.equals(SiteProps.PROCESS_ERROR)) {
> > > >       System.out.println("  We know the credit card charge
> > > > failed.  Send
> > > > them back to the order form.");
> > > >       nextUrl = "/order.jsp";
> > > >       response.sendRedirect(response.encodeRedirectUrl(nextUrl));
> > > >       return;  // will remove status object on next page
> > > >     } else if (status.equals(SiteProps.PROCESS_UNKNOWN)) {
> > > >       System.out.println("  Still processing.  Not sure what
> > > > the result
> > > > will be.  This page will refresh in 5 seconds.");
> > > >       nextUrl = "/order_check.jsp"; // refresh back to this same page
> > > >     }
> > > >   } else {
> > > >     // we don't have any record of a previous attempt to process
> > > >     System.out.println("  First time trying to process order page.
> > > > Starting processing, scheduling a refresh.");
> > > >     session.setAttribute(SiteProps.PROCESS_STATUS,
> > > >       SiteProps.PROCESS_UNKNOWN);
> > > >   }
> > > >   %>
> > > >   <html>
> > > >     <!-- progress bar animated gif html code here -->
> > > >   </html>
> > > >   <%
> > > >   if (nextUrl == null) {
> > > >     // first time to page
> > > >
> > > >     // order processing code here
> > > >   }
> > > > }
> > > >
> > > > The problem is, that there isn't any real synchronization
> > > > here.  This is
> > > > because the "session" object is a different object each time this page
> > > > loads.  In fact, printing out the "session" object each time the page
> > > > loads results in:
> > > >
> > > > org.apache.catalina.session.StandardSessionFacade@24ea85
> > > > org.apache.catalina.session.StandardSessionFacade@10275fa
> > > > org.apache.catalina.session.StandardSessionFacade@18706f6
> > > > org.apache.catalina.session.StandardSessionFacade@f1f34a
> > > > org.apache.catalina.session.StandardSessionFacade@fb6763
> > > >
> > > > Since the session object keeps changing, what is the proper way to
> > > > synchronize based on the user's session, to make this
> > > > anti-double-process
> > > > code work properly?
> > > >
> > > > This middle page with the progress bar helps to remove most of our
> > > > double-click problems, but occassionally a user is able to
> > > > get multiple
> > > > copies of this "progress page" opened, and then if the timing
> > > > is right,
> > > > they both enter that snippet of code above at the same time,
> > > > both think
> > > > it's the first time this page is being processed, and both
> > > > run the order
> > > > processing code.
> > > >
> > > > Thank you,
> > > > Raiden
> > > >
> > > >
> > > > ---------------------------------------------------------------------
> > > > To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> > > > For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
> > > >
> > > >
> > >
> > >
> > >
> > > ---------------------------------------------------------------------
> > > To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> > > For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
> > >
> >
> >---------------------------------------------------------------------
> >To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> >For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
>
>
> ____________________________________
> Justin Ruthenbeck
> Software Engineer, NextEngine Inc.
> justinr - AT - nextengine DOT com
> Confidential
>     See http://www.nextengine.com/confidentiality.php
> ____________________________________
>
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: tomcat-user-help@jakarta.apache.org
>

---------------------------------------------------------------------
To unsubscribe, e-mail: tomcat-user-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tomcat-user-help@jakarta.apache.org


Mime
View raw message