[Mulgara-general] Mulgara API's

Paul Gearon gearon at ieee.org
Fri Feb 22 00:52:49 UTC 2008


On Feb 21, 2008, at 5:54 PM, Alex Hall wrote:

>> If it's in the same JVM, then you can continue to use a session.
>> Otherwise, I recommend moving to using Connections (these wrap
>> sessions).  Unfortunately I haven't had time to document them yet.
>> :-(
>>
>
> What benefits does using a Connection have as opposed to using a
> SessionFactory to get a remote session to the server?

Sessions are a lower level, and you have to do more work with them.   
Connections handle some of the boilerplate, and try to present  
everything consistently regardless of back end.

The idea was to have something that looked more like using MySQL.  You  
know... create a connection to a server and issue commands on it.

>> The basic idea of the interface is to create a connection to a  
>> running
>> database.  You can then execute commands on this connection.  A  
>> simple
>> example (without exception handling) is:
>>
>> Connection conn = new SessionConnection(URI.create("rmi://hostname/ 
>> server1"));
>>
>> Interpreter interpreter = new TqlInterpreter();
>> Command cmd = interpreter.parse("insert ......... into
>> <rmi://hostname/server1#data>;");
>> cmd.execute(conn);
>>
>
> What happens in this case if you try and execute a command to insert
> into a server other than the one you opened a connection to?

You're talking about inserting into a graph whose URL specifies  
another server, right?

Your command goes to the server you connected to.  That server will  
have to work out what to do with it.  In the scenario you describe,  
that server will know it can't deal with it, and the distributed- 
resolver will send it on.  (This is a new resolver).

Importantly, the server you send the command to is checking to see if  
it knows the graph before handing it on to this resolver.  This means  
a few things.  Most important is the fact that URIs for a graph need  
not specify protocol, location, or service.  This is all done when you  
establish a connection.  The URI becomes just a label for a graph.   
(However, it is still possible to use a graph URL to find the server,  
but this is for backward compatibility).

Another important thing is that you can force a particular server to  
take your command, even if it is going to be passed on.  This can be  
useful for all sorts of reasons (server visibility, efficiency in  
distributed queries, etc).

> If memory
> serves, the ItqlInterpreterBean was smart enough to determine the
> correct server and open a session with it.

The ItqlInterpreterBean sucked.

The code in that class parsed its queries, and if it happened to  
notice a graph URL while parsing it would automatically change  
sessions, even though it was still in the middle of the parsing  
operation.  Even if you provided your own session, it could still  
arbitrarily change the session on you.  And all this was buried deep  
in the parsing process.  I can't begin to tell you how unmanageable  
this was.

For backward compatibility, the ItqlInterpreterBean is still there,  
but now it works differently.  Now it parses a query into a command.   
If the command is something that is to operate on a remote server,  
then it interrogates the command for the URLs of the graphs it refers  
to.  It then establishes new connections (caching old ones for the  
current ItqlInterpreterBean) as needed, and issues commands on these.   
If it is in a transaction, then any new connections are put into that  
transaction as well.  When a transaction completes, then all servers  
that have been spoken to during that transaction are informed that the  
transaction is complete.  The whole thing performs faster, more  
efficiently, and has greater functionality than the previous  
ItqlInterpreterBean.

Most of the heavy lifting for this emulated functionality is done in  
TqlAutoInterpreter.  I recommend looking at this to understand what I  
was thinking when I did it.  :-)

(caveat: Ronald pointed out that I fiddled trivially with the  
ItqlInterpreterBean interface, breaking backward compatibility.  If he  
hasn't fixed this already then I will.  It was a mistake)

>> cmd = interpreter.parse("select $x from <rmi://hostname/server1#data>
>> where $x $y $z;");
>> Answer answer = (Answer)cmd.execute(conn);
>>
>>
>> You can also manually create Commands if you want to do that instead
>> of using iTQL:
>>
>> new SetAutoCommit(false).execute(conn);
>> new Load(fileUri, modelUri, false).execute(conn);
>> Command c = new Commit();
>> c.execute(conn);
>> new Load(fileUri2, modelUri, false).execute(conn);
>> c.execute(conn);
>>
>>
>> Yes, this looks a little backwards (Ronald pointed out that it should
>> look like connection.execute(command)).  I'll have to look at this,
>> but for the moment it works.
>>
>
> Creating commands manually is probably the method I would prefer, if  
> the
> alternative is building up an ITQL string and then sending it back
> through the parser.  You're right, this calling convention feels  
> pretty
> awkward.  If I decide to go down this route, I would certainly be
> willing to take a look at refactoring that code.

Actually, it's just a matter of changing it to a visitor pattern.   
Connections just need to implement an execute method for every Command  
type, with the form:

Object execute(CommandImplementation cmd) { return cmd.execute(this); }

This is standard boilerplate visitor pattern stuff, and one of the  
reasons I hate Java.  :-)

It would only take 10 minutes to do.  Maybe I'll do it in the morning.

(yes, these methods can be avoided by putting all the functionality in  
a Connection class, avoiding the callback, but this does not use  
encapsulation or information hiding, and makes for a monolithic class,  
which is always a bad idea.)


Paul



More information about the Mulgara-general mailing list