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

Reply via email to