Revision: e33b86b78b05
Author: gdusbabek <gdusba...@gmail.com>
Date: Fri Dec 16 06:12:33 2011
Log: Move the timeout logic into the calls themselves. I think this
simplifies the logic by avoiding the layering and indirection introduced by
the wrapping approach.
http://code.google.com/a/apache-extras.org/p/cassandra-node/source/detail?r=e33b86b78b05
Deleted:
/lib/util.js
Modified:
/lib/driver.js
=======================================
--- /lib/util.js Tue Nov 29 04:11:51 2011
+++ /dev/null
@@ -1,15 +0,0 @@
-/**
- * Wrap a function so that the original function will only be called once,
- * regardless of how many times the wrapper is called.
- * @param {Function} fn The to wrap.
- * @return {Function} A function which will call fn the first time it is
called.
- */
-exports.fireOnce = function fireOnce(fn) {
- var fired = false;
- return function wrapped() {
- if (!fired) {
- fired = true;
- fn.apply(null, arguments);
- }
- };
-};
=======================================
--- /lib/driver.js Tue Nov 29 04:11:51 2011
+++ /lib/driver.js Fri Dec 16 06:12:33 2011
@@ -30,7 +30,6 @@
var async = require('async');
var Cassandra = require('./gen-nodejs/Cassandra');
var ttypes = require('./gen-nodejs/cassandra_types');
-var util = require('./util');
var genericPool = require('generic-pool');
@@ -53,7 +52,7 @@
var DEFAULT_STEP_TIMEOUTS = {
'login': 1000,
'learn': 2000,
- 'use': 1000,
+ 'use': 1000
};
/** converts object to a string using toString() method if it exists. */
@@ -392,15 +391,29 @@
this.con.on('connect', function() {
clearTimeout(timeoutId);
+ function decorateErrWithErrno(err, errno) {
+ err.errno = errno;
+ return err;
+ }
+
// preparing the conneciton is a 3-step process.
// 1) login
var login = function(cb) {
if (self.connectionInfo.user || self.connectionInfo.pass) {
var creds = new ttypes.AuthenticationRequest({user:
self.connectionInfo.user, password: self.connectionInfo.pass});
+ var sentinel = setTimeout(function() {
+ if (sentinel) {
+ sentinel = null;
+ cb(decorateErrWithErrno(new Error('login timed out'),
constants.ETIMEDOUT));
+ }
+ }, DEFAULT_STEP_TIMEOUTS.login);
self.client.login(creds, function(err) {
- if (err) { amendError(err); }
- cb(err);
+ if (sentinel) {
+ sentinel = clearTimeout(sentinel);
+ if (err) { amendError(err); }
+ cb(err);
+ }
});
} else {
cb(null);
@@ -409,85 +422,66 @@
// 2) login.
var learn = function(cb) {
+ var sentinel = setTimeout(function() {
+ if (sentinel) {
+ sentinel = null;
+ cb(decorateErrWithErrno(new Error('learn timed out'),
constants.ETIMEDOUT));
+ }
+ }, DEFAULT_STEP_TIMEOUTS.learn);
self.client.describe_keyspace(self.connectionInfo.keyspace,
function(err, def) {
- if (err) {
- amendError(err);
- cb(err);
- } else {
- for (var i = 0; i < def.cf_defs.length; i++) {
- var validators = {
- key: def.cf_defs[i].key_validation_class,
- comparator: def.cf_defs[i].comparator_type,
- defaultValidator: def.cf_defs[i].default_validation_class,
- specificValidators: {}
- };
- for (var j = 0; j < def.cf_defs[i].column_metadata.length;
j++) {
- // todo: verify that the name we use as the key represents
the raw-bytes version of the column name, not
- // the stringified version.
-
validators.specificValidators[def.cf_defs[i].column_metadata[j].name] =
def.cf_defs[i].column_metadata[j].validation_class;
- }
- self.validators[def.cf_defs[i].name] = validators;
- }
- cb(null); // no errors.
+ if (sentinel) {
+ sentinel = clearTimeout(sentinel);
+ if (err) {
+ amendError(err);
+ cb(err);
+ } else {
+ for (var i = 0; i < def.cf_defs.length; i++) {
+ var validators = {
+ key: def.cf_defs[i].key_validation_class,
+ comparator: def.cf_defs[i].comparator_type,
+ defaultValidator: def.cf_defs[i].default_validation_class,
+ specificValidators: {}
+ };
+ for (var j = 0; j < def.cf_defs[i].column_metadata.length;
j++) {
+ // todo: verify that the name we use as the key represents
the raw-bytes version of the column name, not
+ // the stringified version.
+
validators.specificValidators[def.cf_defs[i].column_metadata[j].name] =
def.cf_defs[i].column_metadata[j].validation_class;
+ }
+ self.validators[def.cf_defs[i].name] = validators;
+ }
+ cb(null); // no errors.
+ }
}
});
};
// 3) set the keyspace on the server.
var use = function(cb) {
+ var sentinel = setTimeout(function() {
+ sentinel = null;
+ cb(decorateErrWithErrno(new Error('use timed out'),
constants.ETIMEDOUT));
+ }, DEFAULT_STEP_TIMEOUTS.use);
+
self.client.set_keyspace(self.connectionInfo.keyspace, function(err)
{
- if (err) { amendError(err); }
- cb(err);
+ if (sentinel) {
+ sentinel = clearTimeout(sentinel);
+ if (err) { amendError(err); }
+ cb(err);
+ }
});
};
- async.series([
- function loginStep(callback) {
- var wrappedCallback = wrapStepCallback('login',
DEFAULT_STEP_TIMEOUTS.login, callback);
- login(wrappedCallback);
- },
-
- function learnStep(callback) {
- var wrappedCallback = wrapStepCallback('learn',
DEFAULT_STEP_TIMEOUTS.learn, callback);
- learn(wrappedCallback);
- },
-
- function useStep(callback) {
- var wrappedCallback = wrapStepCallback('use',
DEFAULT_STEP_TIMEOUTS.use, callback);
- use(wrappedCallback);
- },
- ],
-
- function(err) {
- if (err) {
- self.close();
- }
-
- callback(err);
- });
+ async.series(
+ [login, learn, use],
+ function(err) {
+ if (err) {
+ self.close();
+ }
+ callback(err);
+ }
+ );
});
- function timeoutStep(name, timeout, callback) {
- var timeoutId = setTimeout(function stepTimeoutHandler() {
- var err = new Error('Step "' + name + '" timed out.');
- err.errno = constants.ETIMEDOUT;
-
- callback(err);
- }, timeout);
-
- return timeoutId;
- }
-
- function wrapStepCallback(name, timeout, callback) {
- callback = util.fireOnce(callback);
- var timeoutId = timeoutStep(name, timeout, callback);
-
- return function wrappedCallback(err) {
- clearTimeout(timeoutId);
- callback(err);
- };
- }
-
function connectTimeout() {
var err = new Error('ETIMEDOUT, Operation timed out');
err.errno = constants.ETIMEDOUT;