See inline.

Cheers,

Peter.
----- Original message -----
>
>
> Further discussion below...
>
> Cheers,
>
> Greg.
>
> On Mon, 2013-05-27 at 16:08, Peter wrote:
> > Now's a great time to standardise a common subset we can all use, this
> > is a good conversation.
> >
> > We're all solving similar issues, we could have something really great
> > if we can work together.
> >
> > I created com.sun.jini.start.Starter out of necessity to fix unsafe
> > publication, however this could take another form.
> >
> Although I've never liked the "export and publish in the costructor"
> model, I really think the likelihood of having another thread hit the
> exported object before the constructor is finished is pretty slim. 

Don't let 'this' escape during construction.

It's Russian roulette, it's caused test failures for me that have taken me 
weeks to solve and only then by hand auditing code, I wouldn't want a critical 
failure to occur in production caused by this escaping during construction, 
because of the low frequency of failure it's really a very nasty bug.

So if you have code that exports during construction, fix it now, before it 
manifests in production.

For example the last test failure on arm was caused by it. I couldn't reproduce 
it on other architectures, but arm had a high frequency of failure.

Exporting during construction can break synchronization, don't ask my why, it 
just did that's all.  Besides Josh Bloch and Doug Lee tell us not to allow this 
to escape during construction. Who am I to argue with them?

Older jvm's are kinder, but now concurrency and scalability is the priority, 
these bugs are more likely to occur.

Sim put it succinctly recently, it's akin to when garbage collection became 
more agressive and objects were collected early breaking existing code.  The 
same thing is occurring now with concurrency.

Heed the warning, don't let me say "told you so" in a year or two.

There's a real urgency to get it fixed asap.  The fix is simple; export after 
construction.

> the real use case, the proxy would have to go through a number of
> network calls first before it was accessed by another thread.  Things
> might be different in the test environment, but that can be addressed in
> the test.    As I understand it, you could just synchronize on the proxy,
> and release it before you access it in a subsequent test.
>
> > I've fixed the dynamic IP adressing issue in qa-refactor, see inline
> > further below.
> >
>
> I think we might be talking about different things here.  I'm wondering
> how a running container can deal with a network interface having its IP
> address changed, as when its DHCP lease expires, or when a laptop
> attaches to a different network.

Oh ok, so the codebase issue is only part of the problem, right, detect the 
change and re-export.


>
> > Also, it might be worth investigating
> > org.apache.river.api.io.Distributed, this allows a non Serializable
> > object to be stored in MarshalledInstance and created on demand, using
> > any constructor, static factory method or builder object.  This object
> > is created in an unpriviliged context, otherwise an attacker could
> > create a Classloader etc.
> >
> > It's so simple, yet so powerful, it's scary.
> >
> I don't quite understand the use case for this.  In the context of a
> client that wants to look up a service in a registrar and then begin to
> use it, without knowing anything about the implementation class, how
> does "org.apache.river.api.io.Distributed" fit into things?

It's orthogonal to the client, to the client it's just another object, however 
it can be truely immutable with all invarients checked and all fields final so 
it can be shared without synchronization.

Another case is refactoring code, the developer decides to substitute it with a 
different class, this would cause an Exception with serialization, the 
developer can substitute it with another object if it's constructed with a 
builder.  Distributed objects in marshalled form only contain instructions and 
parameters for creating an object using reflection during unmarshalling; using 
a constructor, a static factory method or a builder object.  There is no serial 
form and the developer is free to change those instructions.

Distributed is akin to distributed injection, the client is not aware of how 
the object is constructed so it's implementation can remain invisible to the 
client.  This allows a compact public api to use many different 
implementations, while the client sees only one type.  It's free from serial 
form, unfortunately it can't be used as an Entry.

It makes sense to use it to address persistence and concurrency concerns, or as 
parameters or return values for service methods.

>
> > It's up to the implementor to do something in a privileged context,
> > including getting a login context.
> >
> > Because a Distributed object doesn't need to implement Serializable
> > and because it can be recreated on demand just by calling
> > MarshalledInstance.get(), it allows an implementation to avoid having
> > a serial form, the implementation is then free to change, even to a
> > completely different class.  At present it's intended to be immutable,
> > but that could be relaxed to include a thread safe service.
> >
> > This would allow any service to have it and it's current persisted
> > state stored in a MarshalledInstance for fail over replication to
> > other nodes, to be restored simply by calling get().    Upgrades could
> > be performed simply by persisting and restarting.
> >
> > More inline below.
> > ----- Original message -----
> > > (New subject for an interesting point)
> > >
> > > Good point, Dennis...
> > >
> > > On Mon, 2013-05-27 at 13:30, Dennis Reedy wrote:
> > > > On May 27, 2013, at 103PM, Greg Trasuk wrote:
> > > >
> > >
> > > > Sure, no problem. One big thing to consider wrt container IoC, is
> > that
> > > > the lifecycle of a River service is different then an EJB. With
> > River,
> > > > a service can join and leave the network (advertised and
> > > > unadvertised). Making sure that you consider that has been
> > important
> > > > in my experience. This when tied with how a service deals with
> > other
> > > > services (what I call associations
> > > > http://www.rio-project.org/associations.html), can change the
> > > > lifecycle of a service. So food for thought
> > > >
> > >
> > > I think you're on the right track in Rio, with injecting a dynamic
> > proxy
> > > for associations.  Curiously, this approach is similar to the
> > dynamic
> > > proxies injected under JEE6 CDI for contextual objects.
> > >
> > > Truth is, I've always been hesitant about injecting service
> > > dependencies, because it seems to me that resolving the services
> > needs
> > > to be a part of the logic of the service invocation, so that various
> > > failures can be handled appropriately.
> > >
> > > Couple of scenarios:
> > >
> > > Context - We're talking about a service that depends on one or more
> > > other services.  When you call service A's 'doSomething()' method,
> > it
> > > needs to call methods on services B, C, etc.
> > >
> > > Scenario 1- You have a (not very efficient!) policy of looking up
> > every
> > > service dependency every time A.doSomething() is called.  In this
> > case
> > > it might just be reasonable to throw an exception
> > (ServiceNotAvailable
> > > or something similar) and let the client deal with it.  Straight
> > > injection works in that case.  Or you might want to save the data
> > > locally and do some alternate handling.  In that case, perhaps it
> > might
> > > be best to leave the unresolved service references null, so the
> > > A.doSomething() code can handle it.
> > >
> > > Scenario 2- You have some service references cached.  When you go to
> > do
> > > A.doSomething(), you find that service B has failed (of course, you
> > find
> > > this out by means of an IOException when calling service B).  What
> > to
> > > do?  In the past, I've handled this by dumping all the caches and
> > > rediscovering the services.  Which means that A.doSomething() has to
> > > take some control of the dependency resolution, which doesn't fit
> > with
> > > dependency injection very well.  In Harvester, I had a resolver
> > object
> > > (I could be wrong, but I think I saw something similar in Rio), so
> > > A.doSomething() would execute the resolution before attempting to
> > use
> > > service dependencies.  Then in case of failure, it could call fail()
> > on
> > > the resolver, which would dump the caches, and attempt resolution
> > again,
> > > then complete the calls.
> > >
> > > Another issue I've been pondering is how Jini interacts with dynamic
> > IP
> > > address assignments (i.e. network cards on DHCP).  If the IP address
> > of
> > > a node changes, it's kind of catastrophic, since the IP addresses of
> > any
> > > services it exports are probably baked in to both the serialized
> > > endpoints, and the codebase urls (assuming that we pessimistically
> > > assumed that name-based resolution won't work - arguably the truth
> > in
> > > most networks).
> >
> > I've gone to great lengths to fix this in qa-refactor, however I've
> > also provided a system property that reverts to the present behaviour:
> >
> > -Dnet.jini.loader.codebaseAnnotation=URL
> >
> >
> >    It seems like in that case, the services' states need
> > > to roll back to before the endpoints were exported, then re-export
> > and
> > > re-publish to the registrar.
> > >
> >
> > > > From a client point of view, a client would simply see that as a
> > set of
> > > services failing, and then go and rediscover the services.  That's
> > no
> > > problem.  But I wonder how to handle that on the service side.  It's
> > > almost easiest to just shutdown the services and restart.
> > >
> > > And what happens if a host has more than one IP address
> > (multi-homed)?
> > > Again, the services codebases will likely have the IP address
> > baked-in.
> > > So a client on one interface needs to use the serialized proxy that
> > > corresponds to the correct interface.  Here's a case where using
> > Maven
> > > artifact ids could help handle the codebase issue.  I suspect the
> > > multiple IP addresses could be handled at the JERI level.
> > >
> > > Anyway, lots of things to think about.
> > >
> > > Greg.
> > >
> > > > Regards
> > > >
> > > > Dennis
> > > >
> > > >
> > >
> >
>

Reply via email to