[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