[Design of the JBoss EJB Container] - Question about Remoting, Marshalling, and EJBs
by ron.sigal@jboss.com
I'm looking at an old Remoting issue, JBREM-167 "RMI Invoker does not use true remoting marshalling/unmarshalling" and I have a question. This issue concerns the Remoting RMI transport, which, as an alternative to the more commonly used "socket" transport, makes invocations using Java RMI. If the "jboss.remoting:service=Connector,transport=socket" Connector in conf/jboss-service.xml were configured to use the RMI tranport, then EJB2 calls would be transported by Java RMI.
Currently, the RMI transport uses org.jboss.invocation.unified.marshall.InvocationMarshaller to marshal invocations on the client side and org.jboss.invocation.unified.marshall.InvocationUnMarshaller to unmarshal invocations on the server side. Their main function, other than serializing and deserializing the invocation, is to add and remove transaction context information:
| // From InvocationMarshaller:
|
| public Object addDecoration(Object dataObject) throws IOException {
| if(dataObject instanceof InvocationRequest)
| {
| InvocationRequest remoteInv = (InvocationRequest) dataObject;
|
| if(remoteInv.getParameter() instanceof Invocation)
| {
| Invocation inv = (Invocation) remoteInv.getParameter();
|
| MarshalledInvocation marshInv = new MarshalledInvocation(inv);
|
| if(inv != null)
| {
| // now that have invocation object related to ejb invocations,
| // need to get the possible known payload objects and make sure
| // they get serialized.
|
| try
| {
| marshInv.setTransactionPropagationContext(getTransactionPropagationContext());
| }
| catch(SystemException e)
| {
| log.error("Error setting transaction propagation context.", e);
| throw new IOException("Error setting transaction context. Message: " + e.getMessage());
| }
|
| // reset the invocation parameter within remote invocation
| remoteInv.setParameter(marshInv);
| }
| else
| {
| //Should never get here, but will check anyways
| log.error("Attempting to marshall Invocation but is null. Can not proceed.");
| throw new IOException("Can not process data object due to the InvocationRequest's parameter being null.");
| }
|
| }
| }
| return dataObject;
| }
|
and
| // From InvocationUnMarshaller:
|
| public Object removeDecoration(Object obj) throws IOException
| {
| if(obj instanceof InvocationRequest)
| {
| InvocationRequest remoteInv = (InvocationRequest) obj;
| Object param = remoteInv.getParameter();
|
| if(param instanceof MarshalledInvocation)
| {
| MarshalledInvocation mi = (MarshalledInvocation) param;
| Object txCxt = mi.getTransactionPropagationContext();
| if(txCxt != null)
| {
| TransactionPropagationContextImporter tpcImporter = TransactionPropagationContextUtil.getTPCImporter();
| mi.setTransaction(tpcImporter.importTransactionPropagationContext(txCxt));
| }
| }
| }
| return obj;
| }
|
On the other hand, when the server returns a response, no marshalling is performed on the server side and no unmarshalling is performed on the client side: the response is passed directly to the RMI runtime. The point of JBREM-167 is to change the RMI server invoker to use a configured marshaller and to change the RMI client invoker to use a configured unmarshaller. This way, someone could interpose, for example, encrypting or compressing marshaller/unmarshallers, which is not currently possible.
My questions:
1. Does anyone care about having this feature?
2. This change would mean that the InvocationMarshaller would be used on the server side when returning a response and InvocationUnMarshaller would be used on the client side to unmarshal the response. Would adding and removing transaction context in the server-to-client direction have any implications?
3. Since EJB3 handles transaction information in an interceptor and doesn't, by default, configure any marshaller or unmarshaller, am I right that this issue is irrelevant to EJB3?
Thanks,
Ron
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4135118#4135118
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4135118
18 years, 1 month
[Design of JBossCache] - Re: Fqns containing just Strings
by bstansberry@jboss.com
Please note that changing from Fqn to Fqn is going to 100% break the Hibernate 2nd Level Cache use case, requiring a major rewrite. I'm not at all certain the proper semantics can be maintained. We talked about this at JBW and I thought there might be a workable solution, but as I think about it more, I'm not seeing one yet.
The workaround we've discussed involves hashing the entity PK and treating a cache node as a hash bucket, with the PK as a key in the node's attribute map. This leads to the potential to have lock conflicts between transactions that by chance use entities whose PKs resolve to the same hash bucket. It also breaks the current putForExternalRead implementation, which fails fast if the node exists. It also makes invalidation more coarse grained, since a write to one key in a bucket invalidates the entire bucket on all remote peers.
We've bounced around the idea of not storing the entity as a value in the hash bucket node's attribute map, but rather a GUID string. Hibernate/JBC integration would first find the GUID, and then use that to construct a String-only Fqn where it would store the real entity. This would deal with the putForExternalRead problem. With a lot of jujitsu in the Hibernate/JBC integration it *perhaps* could get around most of the potential for lock conflicts. It would certainly be complicated and prone to race conditions as multiple peers attempt to cache entities.
But, as I think about it, the GUID approach absolutely won't work with invalidation, as the PK/GUID key/value pair will never be available on any remote peer. Each node will therefore cache a given entity under a different Fqn, and an update of the entity on one node will fail to invalidate the other caches.
Other thing we've discussed is asking the Hibernate guys to come up with some infrastructure to deterministically convert an entity PK into a unique string. But,
1) I don't think such magic exists, at least not for all types. For entities, we could add a requirement that all fields in the PK be primitive, which is not a major restriction, but is an obscure pain point.
2) For query caching, the equivalent to the entity PK is an object that encapsulates the query string and all parameters. Deterministically converting that object into a unique string is another more complex variant on the entity PK task. Lots of fun escaping stuff to distinguish our representation of things from random query content. Further, any entity field type used as a parameter than goes into the query needs to be "stringable", not just those the go into PKs. In practice, again not a major restriction, but an obscure pain point.
3) Perhaps most significantly, I don't see providing such an API as being a high priority for the Hibernate team.
Bottom line, please recognize that making whatever JBC release incorporates this switch usable for Hibernate will be a pain. At minimum it will take time and resources, and the effort will compete for resources with whatever other things are going on. And thus may take longer. At worst, it will introduce a problem that can't be solved effectively. Either way, until the new integration is done, that JBC release will not be usable by EJB3 or JBoss AS.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4135113#4135113
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4135113
18 years, 1 month
[Design of JBossCache] - Re: Eager state push on failure with Buddy Replication
by bstansberry@jboss.com
The presence of a region can act as a "hint" about related data. Meaning a region root node represents the lowest level of unrelated data. For example, we have a region
/JSESSION/localhost/webapp1
In buddy backup we have:
/_BUDDY_BACKUP/CacheA:dead_0//JSESSION/localhost/webapp1/session1/attrA
/_BUDDY_BACKUP/CacheA:dead_0//JSESSION/localhost/webapp1/session1/attrB
/_BUDDY_BACKUP/CacheA:dead_0//JSESSION/localhost/webapp1/session2/attrA
/_BUDDY_BACKUP/CacheA:dead_0//JSESSION/localhost/webapp1/session2/attrB
/_BUDDY_BACKUP/CacheA:dead_0//JSESSION/localhost/webapp1/session3/attrA
/_BUDDY_BACKUP/CacheA:dead_0//JSESSION/localhost/webapp1/session3/attrB
The background thread recognizes the existence of the
/JSESSION/localhost/webapp1 region and therefore starts iterating over the children of
/_BUDDY_BACKUP/CacheA:dead_0//JSESSION/localhost/webapp1/ migrating one child at a time.
I recognize this example is very much tailored to my particular use case, but actually in every JBC app I've written a region has that kind of meaning.
A "structural" node marker can be used instead of a region, and more cleanly indicates the meaning, since the region concept is so overloaded.
Re: usefulness, I think it's pretty necessary. With buddy groups / data partitions by default having 2 members, one member leaving means only 1 copy of data. Admins have to be very careful 1) to know what node has that backup data and 2) not to remove that node fom service until they are sure that data isn't needed any longer -- which typically means waiting a 1/2 hour or more. That means a simple rolling upgrade of a 4 node cluster takes over 2 hours, which is probably longer than a lot of service windows. Larger cluster takes longer.
View the original post : http://www.jboss.com/index.html?module=bb&op=viewtopic&p=4135102#4135102
Reply to the post : http://www.jboss.com/index.html?module=bb&op=posting&mode=reply&p=4135102
18 years, 1 month