Guarantees around Servlet Filter initialization that sets an instance variable?

classic Classic list List threaded Threaded
8 messages Options
Reply | Threaded
Open this post in threaded view
|

Guarantees around Servlet Filter initialization that sets an instance variable?

JSR166 Concurrency mailing list

Greetings,

 

I hope this is a suitable topic for this list.

 

We are wondering if we need to arrange for some explicit synchronization in a Servlet Filter’s doFilter() method to safely refer to an instance variable that was set in the init() method.

 

We can’t find any mention of this, and without forcing memory fences, are concerned that we’re asking for trouble downstream somewhere.

 

(I think this works, consistently, in practice, “by accident,” because there is enough synchronization required between when the container instantiates the filter and calls init() in one thread and when the first doFilter() call comes along in a worker thread.  It seems to me that just having a worker thread pick up a request from a shared queue involves synchronization that “covers” this need in that thread.)

 

Thanks,

 

Mark Ludwig

 

Siemens Digital Industries Software

Lifecycle Collaboration

5939 Rice Creek Parkway

Shoreview, MN  55126 United States

Tel.      :+1 (651) 855-6140

Fax      :+1 (651) 855-6280

[hidden email]

 


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Guarantees around Servlet Filter initialization that sets an instance variable?

JSR166 Concurrency mailing list

I’d be inclined to trust this line in the Javadoc:

The init method must complete successfully before the filter is asked to do any filtering work.

"Complete successfully before" falls short of specifying that there is a happens-before edge between the actions in init() and those in doFilter(), but it’s hard to imagine an implementation for which that wouldn't be the case.

—tim



On Wed, Apr 15, 2020 at 4:46 PM Ludwig, Mark via Concurrency-interest <[hidden email]> wrote:

Greetings,

 

I hope this is a suitable topic for this list.

 

We are wondering if we need to arrange for some explicit synchronization in a Servlet Filter’s doFilter() method to safely refer to an instance variable that was set in the init() method.

 

We can’t find any mention of this, and without forcing memory fences, are concerned that we’re asking for trouble downstream somewhere.

 

(I think this works, consistently, in practice, “by accident,” because there is enough synchronization required between when the container instantiates the filter and calls init() in one thread and when the first doFilter() call comes along in a worker thread.  It seems to me that just having a worker thread pick up a request from a shared queue involves synchronization that “covers” this need in that thread.)

 

Thanks,

 

Mark Ludwig

 

Siemens Digital Industries Software

Lifecycle Collaboration

5939 Rice Creek Parkway

Shoreview, MN  55126 United States

Tel.      :+1 (651) 855-6140

Fax      :+1 (651) 855-6280

[hidden email]

 

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Guarantees around Servlet Filter initialization that sets an instance variable?

JSR166 Concurrency mailing list

Thank you.  My most-paranoid architect doesn't consider that language a

sufficient guarantee, so we’re going with another pattern I started using about

15 years ago, after I got my head around the final field semantics in Java

[1.]5, for lock-free "steady state" access elsewhere in our product.

 

I am interested in a little review of this pattern by JLS & JMM experts here.

 

Below is an example showing the design, in the context of the Filter interface.

Is there a name for this sort of design that uses a race that leads to the

exact, same data through different classes' methods – one synchronized and the

other unsynchronized?  The code below compiles.

 

import java.io.IOException;

import javax.servlet.Filter;

import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;

import javax.servlet.ServletException;

import javax.servlet.ServletRequest;

import javax.servlet.ServletResponse;

 

/**

* Show steady-state lock-free access to data in doFilter

*/

 

class ShowDataAccess implements Filter

{

   private DataAccessor data = new SynchronizedDataAccessor();

 

   public void init(final FilterConfig config) throws ServletException

   {

      data.setAll(config);

   }

 

   public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain)

         throws IOException, ServletException

   {

      System.out.println("doFilter config: " + data.getConfig());

   }

 

   public void destroy()

   {

      data = new SynchronizedDataAccessor();

   }

 

   private interface DataAccessor

   {

      public void setAll (FilterConfig config);

      public FilterConfig getConfig();

   }

  

   private class UnsynchronizedDataAccessor implements DataAccessor

   {

      private final FilterConfig config;

      public UnsynchronizedDataAccessor(FilterConfig config)

      {

         this.config = config;

      }

      public void setAll(FilterConfig config)

      {

         throw new UnsupportedOperationException("Logic error");

      }

      public FilterConfig getConfig()

      {

         return config;

      }

   }

  

   private class SynchronizedDataAccessor implements DataAccessor

   {

      public synchronized void setAll(FilterConfig config)

      {

         data = new UnsynchronizedDataAccessor(config); // Replace reference in parent that led here

      }

      public synchronized FilterConfig getConfig()

      {

         return data.getConfig();

      }

   }

}

 

Thanks,

Mark

 

From: Tim Peierls <[hidden email]>
Sent: Wednesday, April 15, 2020 4:13 PM
To: Ludwig, Mark (DI SW LCS APPS CG&C) <[hidden email]>
Cc: [hidden email]
Subject: Re: [concurrency-interest] Guarantees around Servlet Filter initialization that sets an instance variable?

 

I’d be inclined to trust this line in the Javadoc:

The init method must complete successfully before the filter is asked to do any filtering work.

"Complete successfully before" falls short of specifying that there is a happens-before edge between the actions in init() and those in doFilter(), but it’s hard to imagine an implementation for which that wouldn't be the case.

—tim

 

 

On Wed, Apr 15, 2020 at 4:46 PM Ludwig, Mark via Concurrency-interest <[hidden email]> wrote:

Greetings,

 

I hope this is a suitable topic for this list.

 

We are wondering if we need to arrange for some explicit synchronization in a Servlet Filter’s doFilter() method to safely refer to an instance variable that was set in the init() method.

 

We can’t find any mention of this, and without forcing memory fences, are concerned that we’re asking for trouble downstream somewhere.

 

(I think this works, consistently, in practice, “by accident,” because there is enough synchronization required between when the container instantiates the filter and calls init() in one thread and when the first doFilter() call comes along in a worker thread.  It seems to me that just having a worker thread pick up a request from a shared queue involves synchronization that “covers” this need in that thread.)

 

Thanks,

 

Mark Ludwig

 

Siemens Digital Industries Software

Lifecycle Collaboration

5939 Rice Creek Parkway

Shoreview, MN  55126 United States

Tel.      :+1 (651) 855-6140

Fax      :+1 (651) 855-6280

[hidden email]

 

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest


_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Guarantees around Servlet Filter initialization that sets an instance variable?

JSR166 Concurrency mailing list
On Tue, 28 Apr 2020 at 13:00, Ludwig, Mark via Concurrency-interest
<[hidden email]> wrote:

>
> Thank you.  My most-paranoid architect doesn't consider that language a
>
> sufficient guarantee, so we’re going with another pattern I started using about
>
> 15 years ago, after I got my head around the final field semantics in Java
>
> [1.]5, for lock-free "steady state" access elsewhere in our product.
>
>
>
> I am interested in a little review of this pattern by JLS & JMM experts here.

Hi Mark

I agree with Tim you are wasting your time with this. I can't think of any sane
implementation where you would run into any issue.
The chance of you introducing a bug with a homegrown solution is a lot bigger
than this ever being a problem.

But if you really believe that there might be an issue with memory effects just
declare:

class ShowDataAccess
  volatile field FilterConfig;

and you should be safe.

The code you posted it basically good old double-checked-locking [1] in
disguise. There is no happens-before relationship between
SynchronizedDataAccessor.setAll and subsequent calls to
UnsynchronizedDataAccessor.getConfig. So you have accomplished nothing. Other
than confusing your co-workers.

/Kasper

[1] https://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Guarantees around Servlet Filter initialization that sets an instance variable?

JSR166 Concurrency mailing list
Thank you.  I have a follow-up question....

> From: Kasper Nielsen <[hidden email]>, Tuesday, April 28, 2020 9:21 AM
>
> The code you posted it basically good old double-checked-locking [1] in
> disguise. There is no happens-before relationship between
> SynchronizedDataAccessor.setAll and subsequent calls to
> UnsynchronizedDataAccessor.getConfig. So you have accomplished nothing.
> Other
> than confusing your co-workers.

I think you're saying I misunderstand this language (from
https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5):

------------------------------------------------------------
final fields also allow programmers to implement thread-safe
immutable objects without synchronization. A thread-safe
immutable object is seen as immutable by all threads, even
if a data race is used to pass references to the immutable
object between threads. This can provide safety guarantees
against misuse of an immutable class by incorrect or
malicious code. final fields must be used correctly to
provide a guarantee of immutability.

An object is considered to be completely initialized when
its constructor finishes. A thread that can only see a
reference to an object after that object has been completely
initialized is guaranteed to see the correctly initialized
values for that object's final fields.

The usage model for final fields is a simple one: Set the
final fields for an object in that object's constructor; and
do not write a reference to the object being constructed in
a place where another thread can see it before the object's
constructor is finished. If this is followed, then when the
object is seen by another thread, that thread will always
see the correctly constructed version of that object's final
fields. It will also see versions of any object or array
referenced by those final fields that are at least as
up-to-date as the final fields are.
------------------------------------------------------------

At the end of the reference you sent, the following
seems to support what I'm trying to do:
------------------------------------------------------------
Double-Checked Locking Immutable Objects

If Helper is an immutable object, such that all of the
fields of Helper are final, then double-checked locking will
work without having to use volatile fields. The idea is that
a reference to an immutable object (such as a String or an
Integer) should behave in much the same way as an int or
float; reading and writing references to immutable objects
are atomic.
------------------------------------------------------------

Is the following statement not effectively atomic -- can the
'data' reference point to the not-completely-initialized
UnsynchronizedDataAccessor object?

         data = new UnsynchronizedDataAccessor(config);

I thought the effectively-atomic behavior derives from an
update of a reference always being atomic; the rest from
construction of an object with only final fields being
effectively atomic, which I thought was guaranteed by the
statements in the JLS I referenced above, because the
constructed UnsynchronizedDataAccessor object only has final
fields.

I appreciate being educated/disabused....

Thanks!
Mark
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Guarantees around Servlet Filter initialization that sets an instance variable?

JSR166 Concurrency mailing list
Hi Mark,

This is all getting theoretical, as you are unlikely to experience
this in practice.
But you don't know how FilterConfig is implemented. Your logic relies on the
fact the FilterConfig itself can be used racely. Maybe it has non-final fields.
You just don't know.

/Kasper

On Tue, 28 Apr 2020 at 16:33, Ludwig, Mark <[hidden email]> wrote:

>
> Thank you.  I have a follow-up question....
>
> > From: Kasper Nielsen <[hidden email]>, Tuesday, April 28, 2020 9:21 AM
> >
> > The code you posted it basically good old double-checked-locking [1] in
> > disguise. There is no happens-before relationship between
> > SynchronizedDataAccessor.setAll and subsequent calls to
> > UnsynchronizedDataAccessor.getConfig. So you have accomplished nothing.
> > Other
> > than confusing your co-workers.
>
> I think you're saying I misunderstand this language (from
> https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html#jls-17.5):
>
> ------------------------------------------------------------
> final fields also allow programmers to implement thread-safe
> immutable objects without synchronization. A thread-safe
> immutable object is seen as immutable by all threads, even
> if a data race is used to pass references to the immutable
> object between threads. This can provide safety guarantees
> against misuse of an immutable class by incorrect or
> malicious code. final fields must be used correctly to
> provide a guarantee of immutability.
>
> An object is considered to be completely initialized when
> its constructor finishes. A thread that can only see a
> reference to an object after that object has been completely
> initialized is guaranteed to see the correctly initialized
> values for that object's final fields.
>
> The usage model for final fields is a simple one: Set the
> final fields for an object in that object's constructor; and
> do not write a reference to the object being constructed in
> a place where another thread can see it before the object's
> constructor is finished. If this is followed, then when the
> object is seen by another thread, that thread will always
> see the correctly constructed version of that object's final
> fields. It will also see versions of any object or array
> referenced by those final fields that are at least as
> up-to-date as the final fields are.
> ------------------------------------------------------------
>
> At the end of the reference you sent, the following
> seems to support what I'm trying to do:
> ------------------------------------------------------------
> Double-Checked Locking Immutable Objects
>
> If Helper is an immutable object, such that all of the
> fields of Helper are final, then double-checked locking will
> work without having to use volatile fields. The idea is that
> a reference to an immutable object (such as a String or an
> Integer) should behave in much the same way as an int or
> float; reading and writing references to immutable objects
> are atomic.
> ------------------------------------------------------------
>
> Is the following statement not effectively atomic -- can the
> 'data' reference point to the not-completely-initialized
> UnsynchronizedDataAccessor object?
>
>          data = new UnsynchronizedDataAccessor(config);
>
> I thought the effectively-atomic behavior derives from an
> update of a reference always being atomic; the rest from
> construction of an object with only final fields being
> effectively atomic, which I thought was guaranteed by the
> statements in the JLS I referenced above, because the
> constructed UnsynchronizedDataAccessor object only has final
> fields.
>
> I appreciate being educated/disabused....
>
> Thanks!
> Mark
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Guarantees around Servlet Filter initialization that sets an instance variable?

JSR166 Concurrency mailing list
> From: Kasper Nielsen <[hidden email]>, Tuesday, April 28, 2020 11:03 AM
>
> Hi Mark,
>
> This is all getting theoretical, as you are unlikely to experience
> this in practice.
> But you don't know how FilterConfig is implemented. Your logic relies on the
> fact the FilterConfig itself can be used racely. Maybe it has non-final fields.
> You just don't know.
>
> /Kasper

Hi Kasper,

Thank you.  Sorry, but in my attempt to present a simple
example, I unintentionally misled by using FilterConfig as
the thing that's being stored and retrieved.  In fact, some
int and boolean values are calculated from the contents of
the FilterConfig, and they are stored and retrieved.  I
didn't want to add yet another object into the example, but
I should have....

I know this is theoretical.  This is a very simple example,
compared to the data actually involved in this pattern.  I
agree that it's overkill, that none of this is necessary,
but faced with an insistent architect, I have a very real
risk with scalability on my customers' big, non-Intel
machines (Solaris on SPARC, AIX on POWER, and HP-UX on
Itanium, to be precise).  Maybe using volatile is okay, but
can anyone tell me how the barrier it imposes will scale on
all these different architectures?

I am only trying to get a "read" on this approach, somewhat
generally -- really, whether there are restrictions on
reordering to prevent the traditional problem with
double-checked locking.

Since you only expressed concerned about something that's
(unfortunately) irrelevant (sorry, again), I believe I have
my answer.  Anyway, I realized there is the statement that
init() completes before any doFilter() calls, so /that/
ensures that the constructor has completed and the object is
fully initialized, before it's possible for doFilter() to
pick up the reference.  It might not be the precise
definition of happens-before that you'd like to see, but
it's good enough for me.

Thanks again,
Mark

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Guarantees around Servlet Filter initialization that sets an instance variable?

JSR166 Concurrency mailing list
Epilog: found sanity, so we have no barriers (synchronized or volatile).  Thanks again.

(Seeing the source for javax.servlet.GenericFilter class helped.)

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://cs.oswego.edu/mailman/listinfo/concurrency-interest