[omniORB] Problem with deeply nested structs.

baileyk@schneider.com baileyk@schneider.com
Fri, 22 Mar 2002 16:04:35 -0600



I've written a few stream types and generally end up dissatisfied with my
ability to control the serialization process.  A simple stream abstraction
wants to see nothing more than a sequence of primitives.  I haven't spent
much time looking at cdrStream yet, but it appears to be that way at first
glance (the stream doesn't really know when it crosses boundaries from one
object to another in a graph).  When traversing an object graph during
serialization I've found it helpful to allow for flexibility in how the
process treats each non-trivial relationship in the graph.  Rather than
equip each class to handle an inflate and a deflate ( operator>>= and <<=)
I give each a single inspect() method that takes an "inspector".  The
inspect method gives each primitive member (by reference) to the inspector
much as is done with streams, but the transition from one object to another
isn't implemented as a call directly to another inspect() method.  Instead
it calls a method on the inspector and passes the other object.  This works
well for single rooted trees of inspectable types.  For other types, an
adapter template class is instantiated to wrap the non-inspectable ( like a
tie object ).

I've found references to this pattern, but I can't recall where.  It seems
to me to be the next logical layer on top of the usual stream/streambuf
pair.  A streambuf deals with bytes, a stream deals with primitives but we
lack a standardized means of dealing with objects themselves (i.e.
traversing a graph).

All off topic I know.  I'm not volunteering to replace the cdrStream and
operator>>=().  In this specific case I hope all that is needed is a
recursion count within the cdrStream itself.  I assume the stream is being
used by a single thread at a time (if I'm wrong then I would need to wrap
the thread shared stream in each thread) and could carry the recursion
count.  Then in each struct's operator>>=() method, I would use a guard
class to call methods with names like cdrStream::beginObj() and
cdrStream::endObj() on entry and exit.  The stream's beginObj()/endObj()
methods could decide whether to count or not and how to fail when the count
got too high.  My only question is, if a MARSHAL exception were thrown in
the middle of a deeply nested operator>>=(), would the client process get
it, or would they get a truncated IIOP message?  Hopefully any client ORB
would translate a trucated message into a MARSHAL excpetion (or
COMM_FAILURE?) anyway.

A lot of work to avoid stack overflow, I know.  When trying to write
systems that stay up no matter what crazy data is thrown at them it's
better to add the overhead than have a hard to diagnose failure.  It would
be much nicer if a stack overflow just threw an exception (similar to
bad_alloc on memory exhaustion).  I love recursive algorithms, but I try to
make sure in production code to check sanity limits to avoid just such
problems.

Kendall



                                                                                                                          
                    Duncan Grisby                                                                                         
                    <dgrisby@uk.research.att.com       To:     baileyk@schneider.com                                      
                    >                                  cc:     omniorb-list@uk.research.att.com                           
                    Sent by:                           Fax to:                                                            
                    owner-omniorb-list@uk.resear       Subject:     Re: [omniORB] Problem with deeply nested structs.     
                    ch.att.com                                                                                            
                                                                                                                          
                                                                                                                          
                    03/21/2002 05:14 AM                                                                                   
                                                                                                                          
                                                                                                                          




On Friday 15 March, baileyk@schneider.com wrote:

> Perhaps you can point me to where the recursion is done.  Is it in the
> omniidl generated stub code or in the orb core itself?  I might try to
add
> a configurable recusion limit and throw a MARSHAL exception so that it
> fails more gracefully.

It's done in the stubs. Each thing that can be marshalled has an
operator >>= that does the marshalling. You can see the recursion
there. The way it's structured, it won't be at all easy to add a
recursion count.

Cheers,

Duncan.

--
 -- Duncan Grisby  \  Research Engineer  --
  -- AT&T Laboratories Cambridge          --
   -- http://www.uk.research.att.com/~dpg1 --