3 new revisions:
Revision: 76e95431f113
Author: Tomaz Muraus <[email protected]>
Date: Mon Jan 9 10:35:07 2012
Log: Remove trailing whitespace.
http://code.google.com/a/apache-extras.org/p/cassandra-node/source/detail?r=76e95431f113
Revision: 6ac4262a9375
Author: Tomaz Muraus <[email protected]>
Date: Mon Jan 9 10:46:41 2012
Log: Replace uuid-js with node-uuid library and add a new UUID type.
This p...
http://code.google.com/a/apache-extras.org/p/cassandra-node/source/detail?r=6ac4262a9375
Revision: 3257cd3f977f
Author: Tomaz Muraus <[email protected]>
Date: Mon Jan 9 10:50:19 2012
Log: update CHANGES.
http://code.google.com/a/apache-extras.org/p/cassandra-node/source/detail?r=3257cd3f977f
==============================================================================
Revision: 76e95431f113
Author: Tomaz Muraus <[email protected]>
Date: Mon Jan 9 10:35:07 2012
Log: Remove trailing whitespace.
http://code.google.com/a/apache-extras.org/p/cassandra-node/source/detail?r=76e95431f113
Modified:
/lib/driver.js
=======================================
--- /lib/driver.js Mon Jan 9 10:14:12 2012
+++ /lib/driver.js Mon Jan 9 10:35:07 2012
@@ -47,7 +47,7 @@
var DEFAULT_CONNECTION_TIMEOUT = 4000;
-/** Default timeout for each of the steps (login, learn, use) which are
performed
+/** Default timeout for each of the steps (login, learn, use) which are
performed
* when the Connection to the Cassandra server has been established. */
var DEFAULT_STEP_TIMEOUTS = {
'login': 1000,
@@ -150,11 +150,11 @@
var Row = module.exports.Row = function(row, decoder) {
// decoded key.
this.key = decoder.decode(row.key, 'key');
-
+
// cols, all names and values are decoded.
this.cols = []; // list of hashes of {name, value};
this.colHash = {}; // hash of name->value
-
+
var count = 0;
for (var i = 0; i < row.columns.length; i++) {
if (row.columns[i].value) {
@@ -168,7 +168,7 @@
count += 1;
}
}
-
+
this._colCount = count;
};
@@ -179,19 +179,19 @@
/**
* Perform queries against a pool of open connections.
- *
+ *
* Accepts a single argument of an object used to configure the new
PooledConnection
* instance. The config object supports the following attributes:
- *
+ *
* hosts : List of strings in host:port format.
* keyspace : Keyspace name.
* user : User for authentication (optional).
* pass : Password for authentication (optional).
* maxSize : Maximum number of connection to pool (optional).
* idleMillis : Idle connection timeout in milliseconds (optional).
- *
+ *
* Example:
- *
+ *
* var pool = new PooledConnection({
* hosts : ['host1:9160', 'host2:9170', 'host3', 'host4'],
* keyspace : 'database',
@@ -200,7 +200,7 @@
* maxSize : 25,
* idleMillis : 30000
* });
- *
+ *
* @param config an object used to control the creation of new instances.
*/
var PooledConnection = module.exports.PooledConnection = function(config) {
@@ -223,11 +223,11 @@
log.debug("adding " + hostSpec + " to working node list");
this.nodes.push([host[0], (isNaN(host[1])) ? 9160 : host[1]]);
}
-
+
var self = this;
var maxSize = isNaN(config.maxSize) ? 25 : config.maxsize;
var idleMillis = isNaN(config.idleMillis) ? 30000 : config.idleMillis;
-
+
this.pool = genericPool.Pool({
name : 'Connection',
create : function(callback) {
@@ -237,12 +237,12 @@
} else {
self.current_node++;
}
-
+
var tries = self.nodes.length;
-
+
function retry(curNode) {
tries--;
-
+
if ((curNode + 1) >= self.nodes.length) {
curNode = 0;
} else {
@@ -254,16 +254,16 @@
if (node.holdUntil > (new Date().getTime())) {
return retry(curNode);
}
-
- var conn = new Connection({host: node[0],
- port: node[1],
- keyspace: config.keyspace,
- user: config.user,
- pass: config.pass,
+
+ var conn = new Connection({host: node[0],
+ port: node[1],
+ keyspace: config.keyspace,
+ user: config.user,
+ pass: config.pass,
use_bigints: self.use_bigints,
timeout: self.timeout,
log_time: self.log_time});
-
+
conn.connect(function(err) {
if (!err) { // Success, we're connected
callback(conn);
@@ -381,7 +381,7 @@
/**
- * makes the connection.
+ * makes the connection.
* @param callback called when connection is successful or ultimately
fails (err will be present).
*/
Connection.prototype.connect = function(callback) {
@@ -406,9 +406,9 @@
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) {
@@ -430,7 +430,7 @@
cb(null);
}
};
-
+
// 2) login.
var learn = function(cb) {
var timeoutId = setTimeout(function() {
@@ -454,7 +454,7 @@
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
+ // 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;
}
@@ -465,14 +465,14 @@
}
});
};
-
+
// 3) set the keyspace on the server.
var use = function(cb) {
var timeoutId = setTimeout(function() {
timeoutId = null;
cb(decorateErrWithErrno(new Error('use timed out'),
constants.ETIMEDOUT));
}, DEFAULT_STEP_TIMEOUTS.use);
-
+
self.client.set_keyspace(self.connectionInfo.keyspace, function(err)
{
if (timeoutId) {
timeoutId = clearTimeout(timeoutId);
@@ -575,6 +575,6 @@
callback(null);
}
}
- });
+ });
}
};
==============================================================================
Revision: 6ac4262a9375
Author: Tomaz Muraus <[email protected]>
Date: Mon Jan 9 10:46:41 2012
Log: Replace uuid-js with node-uuid library and add a new UUID type.
This patch has
been contributed by Christoph Tavan <[email protected]> is is part of #12.
http://code.google.com/a/apache-extras.org/p/cassandra-node/source/detail?r=6ac4262a9375
Added:
/lib/uuid.js
Modified:
/lib/decoder.js
/lib/driver.js
/package.json
/test/test_decoder.js
/test/test_driver.js
/test/test_uuid.js
=======================================
--- /dev/null
+++ /lib/uuid.js Mon Jan 9 10:46:41 2012
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2011 Christoph Tavan
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/**
+ * @fileoverview UUID type for cassandra
+ */
+
+var uuid = require('node-uuid');
+
+/**
+ * UUID object for use in node-cassandra-client
+ */
+function UUID(bytes) {
+ this._bytes = (Buffer.isBuffer(bytes) && bytes.length == 16) ?
+ bytes :
+ (Array.isArray(bytes) && bytes.length == 16 ?
+ new Buffer(bytes) :
+ new Buffer(16)
+ );
+ if (!bytes) {
+ uuid.v4(null, this._bytes);
+ }
+}
+module.exports = UUID;
+
+/**
+ * Converts a UUID to string hyphen-separated string-notations
+ *
+ * @return {string} UUID in hyphen-separated string-notation
+ */
+UUID.prototype.toString = function() {
+ return uuid.unparse(this._bytes);
+};
+
+/**
+ * Compare a given UUID-object with the current UUID object
+ *
+ * @param {object} other UUID object to compare with
+ * @return {bool}
+ */
+UUID.prototype.equals = function(other) {
+ return this.toString() === other.toString();
+};
+
+/**
+ * Factory method that returns a UUID object.
+ *
+ * @param {Buffer} bytes The 16 bytes of a UUID
+ * @return {object} UUID
+ */
+UUID.fromBytes = function(bytes) {
+ return new UUID(bytes);
+};
+
+/**
+ * Factory method that returns a UUID object.
+ *
+ * @param {string} string UUID in hyphen-separated string-notation
+ * @return {object} UUID
+ */
+UUID.fromString = function(string) {
+ return new UUID(uuid.parse(string));
+};
+
+/**
+ * Factory method that generates a v1 UUID for a given timestamp.
+ *
+ * Successive calls using the same timestamp will generate incrementally
+ * different UUIDs that sort appropriately.
+ *
+ * @param {int} timestamp Unix-timestamp
+ * @return {object} UUID
+ */
+UUID.fromTime = function(timestamp) {
+ var buf = new Buffer(16);
+ uuid.v1({ msecs: timestamp }, buf);
+ return new UUID(buf);
+};
+
+/**
+ * Factory method generates the minimum (first) UUID for a given
ms-timestamp
+ *
+ * @param {int} timestamp Unix-timestamp
+ * @return {object} UUID
+ */
+UUID.minUUID = function(timestamp) {
+ var buf = new Buffer(16);
+ uuid.v1({ msecs: timestamp, nsecs: 0 }, buf);
+ return new UUID(buf);
+};
+
+/**
+ * Opposite of minUUID.
+ *
+ * @param {int} timestamp Unix-timestamp
+ * @return {object} UUID
+ */
+UUID.maxUUID = function(timestamp) {
+ var buf = new Buffer(16);
+ uuid.v1({ msecs: timestamp, nsecs: 9999 }, buf);
+ return new UUID(buf);
+};
+
=======================================
--- /lib/decoder.js Mon Jan 9 10:14:12 2012
+++ /lib/decoder.js Mon Jan 9 10:46:41 2012
@@ -16,7 +16,7 @@
*/
/** [en|de]coder for cassandra types. */
var BigInteger = require('./bigint').BigInteger;
-var UUID = require('uuid-js');
+var UUID = require('./uuid');
// remember: values x such that -2^31 > x or x > 2^31-1 will make this
routine puke.
var bytesToNum = module.exports.bytesToNum = function(bytes) {
=======================================
--- /lib/driver.js Mon Jan 9 10:35:07 2012
+++ /lib/driver.js Mon Jan 9 10:46:41 2012
@@ -123,7 +123,7 @@
var CfDef = module.exports.CfDef = require('./system').CfDef;
var ColumnDef = module.exports.ColumnDef = require('./system').ColumnDef;
var BigInteger = module.exports.BigInteger =
require('./bigint').BigInteger;
-var UUID = module.exports.UUID = require('uuid-js');
+var UUID = module.exports.UUID = require('./uuid');
/**
=======================================
--- /package.json Sun Dec 25 16:24:07 2011
+++ /package.json Mon Jan 9 10:46:41 2012
@@ -30,7 +30,7 @@
"logmagic": ">= 0.1.1",
"generic-pool": ">= 1.0.7",
"whiskey": ">= 0.6.1",
- "uuid-js": ">= 0.5.2"
+ "node-uuid": ">= 1.3.3"
},
"devDependencies": {},
"licenses" : [{
=======================================
--- /test/test_decoder.js Fri Nov 11 07:49:04 2011
+++ /test/test_decoder.js Mon Jan 9 10:46:41 2012
@@ -19,7 +19,7 @@
var BigInteger = require('../lib/bigint').BigInteger;
var bytesToBigLong = require('../lib/decoder').bytesToBigLong;
var bytesToNum = require('../lib/decoder').bytesToNum;
-var UUID = require('uuid-js');
+var UUID = require('../lib/uuid');
function makeBuffer(string) {
return new Buffer(string, 'binary');
@@ -238,7 +238,7 @@
assert.strictEqual(strings.length, arrays.length);
for (var i = 0; i < strings.length; i++) {
- assert.deepEqual( UUID.fromURN(strings[i]), UUID.fromBytes(arrays[i])
);
+ assert.deepEqual( UUID.fromString(strings[i]),
UUID.fromBytes(arrays[i]) );
}
test.finish();
};
=======================================
--- /test/test_driver.js Mon Jan 9 10:29:09 2012
+++ /test/test_driver.js Mon Jan 9 10:46:41 2012
@@ -610,8 +610,8 @@
exports.testUUID = function(test, assert) {
// make sure we're not comparing the same things.
-
assert.ok(!UUID.fromURN('6f8483b0-65e0-11e0-0000-fe8ebeead9fe').equals(UUID.fromURN('6fd589e0-65e0-11e0-0000-7fd66bb03aff')));
-
assert.ok(!UUID.fromURN('6fd589e0-65e0-11e0-0000-7fd66bb03aff').equals(UUID.fromURN('fa6a8870-65fa-11e0-0000-fe8ebeead9fd')));
+
assert.ok(!UUID.fromString('6f8483b0-65e0-11e0-0000-fe8ebeead9fe').equals(UUID.fromString('6fd589e0-65e0-11e0-0000-7fd66bb03aff')));
+
assert.ok(!UUID.fromString('6fd589e0-65e0-11e0-0000-7fd66bb03aff').equals(UUID.fromString('fa6a8870-65fa-11e0-0000-fe8ebeead9fd')));
connect(function(err, con) {
if (err) {
assert.ok(false);
@@ -634,15 +634,15 @@
assert.strictEqual(rows.rowCount(), 1);
var row = rows[0];
assert.strictEqual(2, row.colCount());
-
-
assert.ok(UUID.fromURN('6f8483b0-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[0].name));
-
assert.ok(UUID.fromURN('6fd45160-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[0].value));
-
assert.ok(UUID.fromURN('6fd589e0-65e0-11e0-0000-7fd66bb03aff').equals(row.cols[1].name));
-
assert.ok(UUID.fromURN('6fd6e970-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[1].value));
-
-
assert.ok(row.colHash[(UUID.fromURN('6fd589e0-65e0-11e0-0000-7fd66bb03aff'))].equals(row.cols[1].value));
+
+
assert.ok(UUID.fromString('6f8483b0-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[0].name));
+
assert.ok(UUID.fromString('6fd45160-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[0].value));
+
assert.ok(UUID.fromString('6fd589e0-65e0-11e0-0000-7fd66bb03aff').equals(row.cols[1].name));
+
assert.ok(UUID.fromString('6fd6e970-65e0-11e0-0000-fe8ebeead9fe').equals(row.cols[1].value));
+
+
assert.ok(row.colHash[(UUID.fromString('6fd589e0-65e0-11e0-0000-7fd66bb03aff'))].equals(row.cols[1].value));
assert.ok(row.colHash[(row.cols[0].name)].equals(row.cols[0].value));
-
assert.ok(row.colHash[(UUID.fromURN('6f8483b0-65e0-11e0-0000-fe8ebeead9fe'))].equals(row.cols[0].value));
+
assert.ok(row.colHash[(UUID.fromString('6f8483b0-65e0-11e0-0000-fe8ebeead9fe'))].equals(row.cols[0].value));
assert.ok(row.colHash[(row.cols[1].name)].equals(row.cols[1].value));
}
test.finish();
=======================================
--- /test/test_uuid.js Fri Nov 11 07:51:19 2011
+++ /test/test_uuid.js Mon Jan 9 10:46:41 2012
@@ -1,6 +1,28 @@
// some tests for the uuid-js module.
-var UUID = require('uuid-js');
+var UUID = require('../lib/uuid');
+
+var UUID_FORMAT = {
+ v1:
/[0-9a-f]{8}-[0-9a-f]{4}-1[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i,
+ v4:
/[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i
+};
+
+exports['test_uuid_random_v4'] = function(test, assert) {
+ var uuid = new UUID();
+ assert.ok(uuid.toString().match(UUID_FORMAT.v4));
+ test.finish();
+};
+exports['test_uuid_from_time_v1'] = function(test, assert) {
+ var ts = 1314735336312;
+ var uuid = UUID.fromTime(ts);
+ assert.ok(uuid.toString().match(UUID_FORMAT.v1));
+ ts += 1;
+ uuid = UUID.minUUID(ts);
+ assert.ok(uuid.toString().match(UUID_FORMAT.v1));
+ uuid = UUID.maxUUID(ts);
+ assert.ok(uuid.toString().match(UUID_FORMAT.v1));
+ test.finish();
+};
exports['test_uuid_from_buffer'] = function(test, assert) {
var buf = new
Buffer('\u00ee\u00a1\u006c\u00c0\u00cf\u00bd\u0011\u00e0\u0017' +
@@ -10,22 +32,74 @@
test.finish();
};
-// this test currently doesn't work, but I'd like to see the work done in
uuid-js to make it happen. the problem is
-// that it only generates time uuids for the beginning or ending of a
specific millisecond. It should support
-// generating multiple successive UUIDs for the same millisecond for
highly concurrent applications.
+// As per RFC 4122 regressions in time should result in the clockseq being
+// incremented to ensure uniqueness of v1 UUIDs
exports['test_uuid_backwards_in_time'] = function(test, assert) {
- test.skip();
-
var ts = 1314735336316;
+ var ns = 0;
var uuidTs = UUID.fromTime(ts).toString();
- // this forces the nano tracker in uuid to get set way ahead.
+ // This is like setting the system-time to a future value:
var uuidFuture = UUID.fromTime(ts + 5000).toString();
- // we want to verify that the nanos used reflect ts and not ts+5000.
+ // Now this is like setting the system-clock back in time which must
result
+ // in the clock_seq field of the UUID being incremented to avoid
collisions.
var uuidTsSame = UUID.fromTime(ts).toString();
+
+ // UUIDs generated from same TS after going back in time must differ
+ // since clockseq must have been updated
+ assert.ok(uuidTs !== uuidTsSame);
assert.ok(uuidTs !== uuidFuture); // duh
- assert.ok(uuidTs !== uuidTsSame); // generated from same TS after going
back in time.
- // but time lo should definitely be the same.
- // this test would have failed before we started using the back-in-time
reset block in UUID.nanos().
assert.strictEqual(uuidTs.split('-')[0], uuidTsSame.split('-')[0]);
+ assert.strictEqual(uuidTs.split('-')[1], uuidTsSame.split('-')[1]);
+ assert.strictEqual(uuidTs.split('-')[2], uuidTsSame.split('-')[2]);
+ test.finish();
+};
+
+// Generating multiple successive UUIDs for the same millisecond should be
+// supported by the uuid library for highly concurrent applications. Note
that
+// v1 UUIDs are based on 100ns intervals while javascript only offers
+// millisecond resolution times, so the UUID lib should have an internal
+// "100nanosecond-counter" to allow generating 10k v1 UUIDs/millisecond.
+exports['test_uuid_same_ms'] = function(test, assert) {
+ var ts = 1314735336316;
+ var uuidTs = UUID.fromTime(ts).toString();
+ var uuidTsSame = UUID.fromTime(ts).toString();
+ // UUIDs generated for the same millisecond must differ
+ assert.ok(uuidTs !== uuidTsSame);
+ // time low should differ by a 100ns tick.
+ assert.strictEqual(parseInt(uuidTsSame.split('-')[0], 16) -
parseInt(uuidTs.split('-')[0], 16), 1);
+ // but time mid and hi should definitely be the same.
+ assert.strictEqual(uuidTs.split('-')[1], uuidTsSame.split('-')[1]);
+ assert.strictEqual(uuidTs.split('-')[2], uuidTsSame.split('-')[2]);
+ test.finish();
+};
+
+// v1 time-UUIDs are generated with 100ns resolution and cassandra
compares all
+// 60 time bits when comparing time-UUIDs. So for range-queries we always
need
+// UUIDs that have the 100ns count set to 0 for the beginning of a range
+// and set to 9999 for the end of a range to miss no values.
+exports['test_uuid_same_ms_min_max'] = function(test, assert) {
+ var ts = 1314735336320;
+ var uuidTs = UUID.minUUID(ts).toString();
+ var uuidTsSame = UUID.maxUUID(ts).toString();
+ // UUIDs generated for the same millisecond must differ
+ assert.ok(uuidTs !== uuidTsSame);
+ // time low should differ by the full range of 9999 100ns tick.
+ assert.strictEqual(parseInt(uuidTsSame.split('-')[0], 16) -
parseInt(uuidTs.split('-')[0], 16), 9999);
+ // but time mid and hi should definitely be the same.
+ assert.strictEqual(uuidTs.split('-')[1], uuidTsSame.split('-')[1]);
+ assert.strictEqual(uuidTs.split('-')[2], uuidTsSame.split('-')[2]);
+ test.finish();
+};
+exports['test_uuid_same_ms_min_nextmin'] = function(test, assert) {
+ var ts = 1314735336320;
+ var uuidTs = UUID.minUUID(ts).toString();
+ var uuidTsNext = UUID.minUUID(ts+1).toString();
+ // UUIDs generated for the same millisecond must differ
+ assert.ok(uuidTs !== uuidTsNext);
+ // time low should differ by the full range of 9999 100ns tick.
+ assert.strictEqual(parseInt(uuidTsNext.split('-')[0], 16) -
parseInt(uuidTs.split('-')[0], 16), 10000);
+ // but time mid and hi should definitely be the same.
+ assert.strictEqual(uuidTs.split('-')[1], uuidTsNext.split('-')[1]);
+ assert.strictEqual(uuidTs.split('-')[2], uuidTsNext.split('-')[2]);
test.finish();
};
==============================================================================
Revision: 3257cd3f977f
Author: Tomaz Muraus <[email protected]>
Date: Mon Jan 9 10:50:19 2012
Log: update CHANGES.
http://code.google.com/a/apache-extras.org/p/cassandra-node/source/detail?r=3257cd3f977f
Modified:
/CHANGES
=======================================
--- /CHANGES Mon Dec 19 14:58:12 2011
+++ /CHANGES Mon Jan 9 10:50:19 2012
@@ -1,3 +1,10 @@
+Changes with cassandra-client in development:
+
+- Fix scope leaks.
+
+- Replace uuid-js with node-uuid library and add a new UUID type.
+ [Christoph Tavan]
+
Changes with cassandra-client 0.6.1:
- Attach 'connectionInfo' object to the error object which is passed to the