Sunday, December 20, 2009

Network client server SimpleDBM

I am happy to report that an initial implementation of network client server has been checked in. This will allow the SimpleDBM clients to use a thin client which will connect to a remote SimpleDBM server.

The client interface is a simplified version of the Database API.

The network protocol is based on a simple request/reply model. The messages are passed in the SimpleDBM serialization format.

I looked at the possibility of using a third-party NIO framework for SimpleDBM. However, all existing frameworks seemed to be unnecessarily complicated, due to a desire to make them generic. In the end, I ended up writing my own NIO server. It was easier than I thought it might be; though it is early days  and I have not tested all the failure scenarios yet.

There is no attempt to optimise the network traffic in the current implementation. The main goal right now is to prototype the client interface and get it to a satisfactory level. Optimisation can happen once the interface is stable.

The current implementation does not have any security constraints; security must be handled by the client application.

An example of how the client interacts with the server is shown in the snippet below:


Properties properties = parseProperties("test.properties");
// start a session
SessionManager sessionManager = new SessionManager(properties,
"localhost", 8000);
TypeFactory ff = sessionManager.getTypeFactory();
Session session = sessionManager.openSession();
try {
// create a table definition
TypeDescriptor employee_rowtype[] = { ff.getIntegerType(), /* pk */
ff.getVarcharType(20), /* name */
ff.getVarcharType(20), /* surname */
ff.getVarcharType(20), /* city */
ff.getVarcharType(45), /* email address */
ff.getDateTimeType(), /* date of birth */
ff.getNumberType(2) /* salary */
};
TableDefinition tableDefinition = sessionManager
.newTableDefinition("employee", 1, employee_rowtype);
tableDefinition.addIndex(2, "employee1.idx", new int[] { 0 }, true,
true);
tableDefinition.addIndex(3, "employee2.idx", new int[] { 2, 1 },
false, false);
tableDefinition.addIndex(4, "employee3.idx", new int[] { 5 },
false, false);
tableDefinition.addIndex(5, "employee4.idx", new int[] { 6 },
false, false);
// create table
session.createTable(tableDefinition);
// now lets insert/update a row
session.startTransaction(IsolationMode.READ_COMMITTED);
boolean success = false;
try {
Table table = session.getTable(1);
Row tableRow = table.getRow();
tableRow.setInt(0, 1);
tableRow.setString(1, "Joe");
tableRow.setString(2, "Blogg");
tableRow.setDate(5, getDOB(1930, 12, 31));
tableRow.setString(6, "500.00");
table.addRow(tableRow);
TableScan scan = table.openScan(0, null, false);
try {
Row row = scan.fetchNext();
while (row != null) {
System.out.println("Fetched row " + row);
row.setString(6, "501.00");
scan.updateCurrentRow(row);
row = scan.fetchNext();
}
} finally {
scan.close();
}
success = true;
} finally {
if (success) {
session.commit();
} else {
session.rollback();
}
}

// now delete all the rows
session.startTransaction(IsolationMode.READ_COMMITTED);
success = false;
try {
Table table = session.getTable(1);
TableScan scan = table.openScan(0, null, false);
try {
Row row = scan.fetchNext();
while (row != null) {
System.out.println("Deleting row " + row);
scan.deleteRow();
row = scan.fetchNext();
}
} finally {
scan.close();
}
success = true;
} finally {
if (success) {
session.commit();
} else {
session.rollback();
}
}
} catch (Exception e) {
e.printStackTrace();
} finally {
session.close();
}