diff --git a/lib/memjs/memjs.js b/lib/memjs/memjs.js index 688456b..1145756 100644 --- a/lib/memjs/memjs.js +++ b/lib/memjs/memjs.js @@ -99,7 +99,7 @@ Client.prototype.server = function(key) { // // Fetches the value at the given key with callback signature: // -// callback(err, value, flags) +// callback(err, value, flags, cas) // // _value_ and _flags_ are both `Buffer`s. // If the key is not found, the callback is invoked @@ -110,20 +110,20 @@ Client.prototype.get = function(key, callback) { var logger = this.options.logger; this.perform(key, request, function(err, response) { if (err) { - callback && callback(err, null, null); + callback && callback(err, null, null, null); return; } switch (response.header.status) { case 0: - callback && callback(null, response.val, response.extras) + callback && callback(null, response.val, response.extras, response.header.cas) break; case 1: - callback && callback(null, null, null); + callback && callback(null, null, null, null); break; default: var errorMessage = 'MemJS GET: ' + errors[response.header.status]; logger.log(errorMessage); - callback && callback(new Error(errorMessage), null, null); + callback && callback(new Error(errorMessage), null, null, null); } }); } @@ -134,12 +134,12 @@ Client.prototype.get = function(key, callback) { // in last, after the callback) overrides the default expiration (see // `Client.create`). The callback signature is: // -// callback(err, success) -Client.prototype.set = function(key, value, callback, expires) { +// callback(err, success, cas) +Client.prototype.set = function(key, value, callback, expires, cas) { var extras = Buffer.concat([new Buffer('00000000', 'hex'), makeExpiration(expires || this.options.expires)]); this.seq++; - var request = makeRequestBuffer(1, key, extras, value, this.seq); + var request = makeRequestBuffer(1, key, extras, value, this.seq, cas); var logger = this.options.logger; this.perform(key, request, function(err, response) { if (err) { @@ -148,7 +148,10 @@ Client.prototype.set = function(key, value, callback, expires) { } switch (response.header.status) { case 0: - callback && callback(null, true) + callback && callback(null, true, response.header.cas); + break; + case 2: // Key exists (CAS didn't match) + callback && callback(null, false, null); break; default: var errorMessage = 'MemJS SET: ' + errors[response.header.status]; @@ -178,10 +181,10 @@ Client.prototype.add = function(key, value, callback, expires) { } switch (response.header.status) { case 0: - callback && callback(null, true) + callback && callback(null, true, response.header.cas) break; case 2: - callback && callback(null, false); + callback && callback(null, false, null); break; default: var errorMessage = 'MemJS ADD: ' + errors[response.header.status]; @@ -199,10 +202,10 @@ Client.prototype.add = function(key, value, callback, expires) { // `Client.create`). The callback signature is: // // callback(err, success) -Client.prototype.replace = function(key, value, callback, expires) { +Client.prototype.replace = function(key, value, callback, expires, cas) { var extras = Buffer.concat([new Buffer('00000000', 'hex'), makeExpiration(expires || this.options.expires)]); this.seq++; - var request = makeRequestBuffer(3, key, extras, value, this.seq); + var request = makeRequestBuffer(3, key, extras, value, this.seq, cas); var logger = this.options.logger; this.perform(key, request, function(err, response) { if (err) { @@ -211,10 +214,13 @@ Client.prototype.replace = function(key, value, callback, expires) { } switch (response.header.status) { case 0: - callback && callback(null, true) + callback && callback(null, true, response.header.cas); break; case 1: - callback && callback(null, false); + callback && callback(null, false, null); + break; + case 2: + callback && callback(null, false, response.header.cas); break; default: var errorMessage = 'MemJS REPLACE: ' + errors[response.header.status]; diff --git a/lib/memjs/utils.js b/lib/memjs/utils.js index c1ccfdc..55d93f8 100644 --- a/lib/memjs/utils.js +++ b/lib/memjs/utils.js @@ -4,7 +4,7 @@ var bufferify = function(val) { return Buffer.isBuffer(val) ? val : new Buffer(val); } -exports.makeRequestBuffer = function(opcode, key, extras, value, opaque) { +exports.makeRequestBuffer = function(opcode, key, extras, value, opaque, cas) { key = bufferify(key); extras = bufferify(extras); value = bufferify(value); @@ -16,7 +16,8 @@ exports.makeRequestBuffer = function(opcode, key, extras, value, opaque) { keyLength: key.length, extrasLength: extras.length, totalBodyLength: key.length + value.length + extras.length, - opaque: opaque + opaque: opaque, + cas: cas }; header.toBuffer(requestHeader).copy(buf); extras.copy(buf, 24) diff --git a/test/client_test.js b/test/client_test.js index aaf7585..5899e2c 100644 --- a/test/client_test.js +++ b/test/client_test.js @@ -10,14 +10,21 @@ exports.testGetSuccessful = function(beforeExit, assert) { assert.equal('hello', request.key); n += 1; dummyServer.respond( - {header: {status: 0, opaque: request.header.opaque}, - val: 'world', extras: 'flagshere'}); + { + header: { + status: 0, + opaque: request.header.opaque, + cas: new Buffer([0x0a, 0, 0, 0, 0, 0, 0, 0]) + }, + val: 'world', extras: 'flagshere' + }); } var client = new MemJS.Client([dummyServer]); - client.get('hello', function(err, val, flags) { + client.get('hello', function(err, val, flags, cas) { assert.equal('world', val); assert.equal('flagshere', flags); + assert.deepEqual(new Buffer([0x0a, 0, 0, 0, 0, 0, 0, 0]), cas); assert.equal(null, err); callbn += 1; }); @@ -104,6 +111,34 @@ exports.testSetWithExpiration = function(beforeExit, assert) { }); } +exports.testSetWithCas = function(beforeExit, assert) { + var n = 0; + var callbn = 0; + var dummyServer = new MemJS.Server(); + dummyServer.write = function(requestBuf) { + console.log(requestBuf); + request = MemJS.Utils.parseMessage(requestBuf); + assert.equal('hello', request.key); + assert.equal('world', request.val); + assert.deepEqual(new Buffer([0x0a,0,0,0,0,0,0,0]), request.header.cas); + n += 1; + dummyServer.respond({header: {status: 0, opaque: request.header.opaque}}); + } + + var client = new MemJS.Client([dummyServer]); + client.set('hello', 'world', function(err, val) { + assert.equal(null, err); + assert.equal(true, val); + callbn += 1; + }, undefined, new Buffer([0x0a, 0, 0, 0, 0, 0, 0, 0])); + + + beforeExit(function() { + assert.equal(1, n, 'Ensure set is called'); + assert.equal(1, callbn, 'Ensure callback is called'); + }); +} + exports.testSetUnsuccessful = function(beforeExit, assert) { var n = 0; var callbn = 0;