dev@grizzly.java.net

Re: [Fwd: [Issue 53] AttributeHolder needs maps with parameterized types <T>]

From: Ken Cavanaugh <Ken.Cavanaugh_at_Sun.COM>
Date: Tue, 19 Feb 2008 12:04:52 -0800
Oleksiy Stashok wrote:
Hello Ken,


 Context...   What would be the
BEST to describe an attribute in a collection, in the context of grizzly's Context, SelectorHandler, Controller?  does it really a String type?  Actually, the way Grizzly using the *term* attribute is not even appropriate. Why?   attribute is something that describes a specific distinguishable feature of the particular object (or instance).  The way grizzly uses here is, to store SOME objects and their references, in case it needs at various scopes.  This forces users to "create" their own strings?keys  (to accommodate in) to retrieve the  references.

Right. Might not be perfect, but a lot of API use that approach:

http://java.sun.com/j2se/1.4.2/docs/api/javax/net/ssl/SSLSession.html
http://java.sun.com/javaee/5/docs/api/javax/servlet/ServletContext.html
And all of them suffer a string hash lookup on every attribute access.  That is a String hash computation
and comparison, and these are expensive operations to perform (possibly multiple times) every time we
read bytes from a channel.
Hashcode computation happens just once for String, though comparison could be expensive.

The design tradeoff here is that there should only be a small number of unique attributes in the system, so that the
AttributedObject arraylists are not too large (say 10-30 attributes, not hundreds).  Many other designs are possible,
depending on exactly how a Map<Integer,Object> is implemented, with the assumption that the keys are small contiguously
allocated non-negative integers.  For example, segmented maps could be used, but then the lookup cost is higher.
Saving space costs time in this case.
I like your implementation! Agree, we can have several "AttributeObjectBase"-like implementation, one you have in Corba with ArrayLists, another with Maps for situation, where we can have more attributes.
I currently use around 20 Attributes in codegen, which is probably more than a Grizzly client
would typically need.  For me, the ArrayList approach works fine.  But codegen has an additional
complication: any Node may be copied, and the copy and the source must share the current
values, but any new Attribute set calls must result in independent values for the source and
the copy.  This results in a fairly complex implementation of AttributedNodeBase, which is probably
not what you want for Grizzly.  Grizzly's implementation of AttributedObject can be very simple:
just delegate everything to the appropriate implementation of a Map<Integer,Object>.

A more complex situation could occur, where a module uses several different contiguously created
attributes.  So one module might use attrs 0-4, another 5-7, another 8-12, etc. This would point to a
Map<Integer,Object> implementation that uses an ArrayList plus an offset.  Chains of such things
could also be used, but that would only make sense if the dynamic attribute implementation was
widely used with many attributes.

There is another consideration: we want to keep the range of Attribute indices as small as possible, so
Grizzly attributes on the SelectionKey attachment should have nothing to do with other sorts of
Attributes used elsewhere in the system (or in other parts of Grizzly for that matter).  To do that,
we need something like AttibuteBuilder which creates an AttributeFactory which creates Attributes
instead of using the constructor of Attribute.  I would not expose AttributeBuilder to the Grizzly client.
The Grizzly client would just do something like

SomeGrizzlyClass.makeAttribute( ... )

with makeAttribute taking the same arguments as the current constructors.
Of course, we could also simply copy the code and rename the packages rather
than sharing the implementation.  In fact, the exposed interface should be like this,
so that we are free to use any implementation at all behind the scenes.
Not sure we need to store type in Attribute? Which role does it play?
The original intent was to use cls to cast the object stored in the AttributedObject to the
correct type.  This of course does not work for things like Attribute<List<String>>,
but then I ended up always using a "typedef" for things like that, e.g.

public interface Foo extends List<String> {}

so that Foo.class is really a Class<Foo> which is as good as (though not at all equivalent to!)
Class<List<String>> for most purposes.

There is currently a confusion here that can be resolved in one of two ways:
  1. Remove cls from the Attribute constructor
  2. Change Attribute.get to use cls.cast instead of (T)
While I don't see a strong need for approach 2, I do use the classname in the
toString method.  Consequently I am changing the implementation to use approach 2.
Grizzly could of course choose a slightly different approach, such as only using the attribute
name in the toString method.

Ken.