Using Node.js with VoltDB

written by Andrew Wilson on May 9, 2012 with no comments

We recently released the first supported version of a VoltDB client driver for Node.js applications. It was able to execute over 695K transactions per second. Since then we have been working on building a better driver and sought out help from the Node community and made a series of improvements.

Today I’m going to write about how to access VoltDB from a Node application. A sample application is included with the driver, the latest version of which can be downloaded from http://www.voltdb.com/tao-volt/downloads-home.php.

The integration process is short and straightforward. All VoltDB applications have a set of stored procedures that are compiled into a catalog which is used to start VoltDB. Once your stored procedures are implemented, you’re ready to build your application.

You will have to implement some code to  map the VoltDB stored procedures into Node, connect to the VoltDB server, and then execute those procedures. Let’s begin by mapping our stored procedures.

var resultsProc = new VoltProcedure('Results');
var initProc = new VoltProcedure('Initialize', ['int', 'string']);
var voteProc = new VoltProcedure('Vote', ['long', 'int', 'long']);

The VoltProcedure object acts as a factory for each invocation of a stored procedure. The VoltProcedure provides access to the VoltDB stored procedure and also declares the VoltDB specific data types that will be passed into an instance of the stored procedure.

function getConfiguration(host) {
 var cfg = new VoltConfiguration();
 cfg.host = host;
 cfg.messageQueueSize = 20;
 return cfg;
}

// Connect to the server
exports.initClient = function(startLoop) {
 if(client == null) {
       var configs = [];

       configs.push(getConfiguration('localhost'));
       client = new VoltClient(configs);

       client.connect(function startup(code, event,results) {
       if(startLoop == true) {
        setInterval(logResults, statsLoggingInterval);
        voteInsertLoop();
       } else {
        voltInit();
       }

       }, function loginError(results) {
        util.log('Node did not connect to VoltDB');
       });
 }
}

Connecting to the server requires a little configuration.The VoltClient manages one or more VoltConnection objects. The VoltClient will open a connection to each host specified in the array of VoltConfiguration objects. The VoltClient will perform a round-robin load balancing between the connections so that your queries are spread across an entire cluster of VoltDB instances.

The VoltClient.connect()method takes a callback handler that is internally mapped to an event. The callback will get back an error code, an event type and the result object itself. The error code will be null if the connection was successful. Otherwise, use the event and the code in conjunction to determine the error. There is documentation on the error codes and event types in the voltconstants.js file.

 function voltInit() {
 var query = initProc.getQuery();
 query.setParameters([6, voteCandidates]);
 client.callProcedure(query, function initVoter(code, event, results) {
       var val = results.table[0][0];
       util.log('Initialized app for ' + val[''] + ' candidates.');
 });
}

We are now ready to call our first stored procedure. The initialize stored procedure sets up the sample database with a list of candidates that the application will ultimately vote on. We see the basic operations. First, we create an instance of a VoltQuery from our VoltProcedure object. VoltQuery’s purpose is to manage a specific query’s life cycle. It will keep track of how long it has been running and ensure that old or unresponsive queries do not clog up the Node server so that a user can exit gracefully without blocking other users.

The client’s callProcedure() method takes a VoltQuery instance and a callback handler. The callback handler will again be mapped to an event emission. All callback handlers will have the same three parameters, always with the error code as the first parameter and it will always be null if everything is successful. In this case, a successful execution will display the number of candidates added to the database.

Summary

The paragraphs above describe the process of defining client-side stored procedure mappings, connecting to the database and executing queries as well as describing some basic memory housekeeping, connection load balancing and the event processing used in this driver. The complete example is within the driver’s bundle under the examples/voter/voter directory. You can examine the main app.js file and go further into the ./models/volt.js to see the complete client integration. As you can see, building a Node.js app using a VoltDB database is very straight-forward.