Skip to content

Commit

Permalink
Merge pull request #72 from Medium/nathan-IncrBy
Browse files Browse the repository at this point in the history
Add incrby to zcache
  • Loading branch information
chaosgame committed Apr 13, 2015
2 parents 5e07f76 + ed1138e commit c73ee28
Show file tree
Hide file tree
Showing 11 changed files with 140 additions and 1 deletion.
6 changes: 6 additions & 0 deletions lib/CacheCluster.js
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,12 @@ CacheCluster.prototype.get = function (key) {
return this._wrapPromiseWithProfiling(cacheInstance.get(key), 'get')
}

/** @override */
CacheCluster.prototype.incr = function (key, increment) {
var cacheInstance = this._servers[this._hashRing.get(key)]
return this._wrapPromiseWithProfiling(cacheInstance.incr(key, increment), 'set')
}

/** @override */
CacheCluster.prototype.set = function (key, val, maxAgeMs) {
var cacheInstance = this._servers[this._hashRing.get(key)]
Expand Down
11 changes: 11 additions & 0 deletions lib/CacheInstance.js
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ CacheInstance.prototype.get = function (key) {
throw new Error("get() must be implemented by any class extending CacheInstance")
}

/**
* Increment a key.
*
* @param {string} key The key to set
* @param {number=} increment The value to increment by. 1 if unspecified.
* @return {Q.Promise}
*/
CacheInstance.prototype.incr = function (key, increment) {
throw new Error("incr() must be implemented by any class extending CacheInstance")
}

/**
* Set a key.
*
Expand Down
7 changes: 7 additions & 0 deletions lib/CachePair.js
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,13 @@ CachePair.prototype.get = function (key) {
})
}

/** @override */
CachePair.prototype.incr = function (key, increment) {
var promises = [this._primary.incr(key, increment)]
if (this._maybeOnSecondary(key)) promises.push(this._secondary.incr(key, increment))
return Q.all(promises)
}

/** @override */
CachePair.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
var promises = [this._primary.set(key, val, maxAgeMs, setWhenNotExist)]
Expand Down
22 changes: 22 additions & 0 deletions lib/FakeCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,28 @@ FakeCache.prototype.del = function (key) {
})
}

/** @override */
FakeCache.prototype.incr = function (key, increment) {
if (this._failureCount > 0) return this._fakeFail('set')
this._logger.fine('FakeCache - incr', key, increment)

if (increment === undefined) {
increment = 1
}

var self = this
// Add an artificial delay to mimic real world cache latency.
return Q.delay(this._latencyMs)
.then(function actualIncr() {
self._requestCounts.incr += 1
if (key in self._data) {
self._data[key] += increment
} else {
self._data[key] = increment
}
})
}

/** @override */
FakeCache.prototype.set = function (key, value, maxAgeMs, setWhenNotExist) {
if (this._failureCount > 0) return this._fakeFail('set')
Expand Down
14 changes: 14 additions & 0 deletions lib/InMemoryCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,20 @@ InMemoryCache.prototype.mget = function (keys) {
return Q.resolve(ret)
}

/** @override */
InMemoryCache.prototype.incr = function (key, increment) {
if (increment === undefined) {
increment = 1
}

if (key in this._data) {
this._data[key] += increment
} else {
this._data[key] = increment
}
return Q.resolve(null)
}

/** @override */
InMemoryCache.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
if ((maxAgeMs === undefined || maxAgeMs <= 0) && !this._maxAgeOverride) {
Expand Down
7 changes: 7 additions & 0 deletions lib/MultiplexingCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,13 @@ MultiplexingCache.prototype.mset = function (items, maxAgeMs, setWhenNotExist) {
}


/** @override */
MultiplexingCache.prototype.incr = function (key, increment) {
this._invalidateKeys([key])
return this._delegate.incr(key, increment)
}


/** @override */
MultiplexingCache.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
this._invalidateKeys([key])
Expand Down
12 changes: 12 additions & 0 deletions lib/RedisConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ RedisConnection.prototype.isAvailable = function () {
return this._isAvailable
}

/** @override */
RedisConnection.prototype.incr = function (key, increment) {
if (increment === undefined) {
increment = 1
}

var deferred = Q.defer()
var params = [key, increment]
this._client.incrby(params, this._makeNodeResolverWithTimeout(deferred, 'incrby', 'Redis [incr] key: ' + key))
return deferred.promise
}

/** @override */
RedisConnection.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
return this._compress(val)
Expand Down
13 changes: 13 additions & 0 deletions lib/RedundantCacheGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,19 @@ RedundantCacheGroup.prototype.mset = function (items, maxAgeMs, setWhenNotExist)
.then(returnTrue)
}

/** @override */
RedundantCacheGroup.prototype.incr = function (key, increment) {
var instances = this._getAllInstances()
var promises = []

for (var i = 0; i < instances.length; i++) {
promises.push(instances[i].incr(key, increment))
}

return Q.all(promises)
.then(returnTrue)
}

/** @override */
RedundantCacheGroup.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
var instances = this._getAllInstances()
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "zcache",
"description": "AWS zone-aware multi-layer cache",
"version": "0.5.0",
"version": "0.5.1",
"homepage": "https://github.com/Medium/zcache",
"authors": [
"Jeremy Stanley <[email protected]> (https://github.com/azulus)",
Expand Down
15 changes: 15 additions & 0 deletions test/test_InMemoryCache.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,21 @@ exports.testInMemoryCache = function (test) {
test.done()
}

exports.testCacheIncr = function (test) {
var self = this
test.equal(0, this.cI.getKeyCount(), 'There is no key in cache')
this.cI.incr('counter', 15)
.then(function() {
test.equal(self.cI._data['counter'], 15, '15 should be returned')
test.equal(1, self.cI.getKeyCount(), 'There is 1 key in cache')
return self.cI.incr('counter')
}).then(function() {
test.equal(self.cI._data['counter'], 16, '16 should be returned')
test.equal(1, self.cI.getKeyCount(), 'There is 1 key in cache')
test.done()
})
}

exports.testCacheSet = function (test) {
var self = this
test.equal(0, this.cI.getKeyCount(), 'There is no key in cache')
Expand Down
32 changes: 32 additions & 0 deletions test/test_RedisConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,38 @@ builder.add(function testRedisConnection(test) {
cacheInstance.connect()
})

builder.add(function testIncr(test) {
var cacheInstance = new zcache.RedisConnection('localhost', 6379)

cacheInstance.on('connect', function () {
cacheInstance.removeAllListeners('connect')
test.equal(cacheInstance.isAvailable(), true, 'Connection should be available')

cacheInstance.incr('counter', 15)
.then(function () {
return cacheInstance.incr('counter')
})
.then(function (val) {
return cacheInstance.get('counter')
})
.then(function (val) {
test.equal(val, '16')
cacheInstance.destroy()
})
.fail(function (e) {
console.error(e)
test.fail(e.message)
test.done()
})
})

cacheInstance.on('destroy', function () {
test.done()
})

cacheInstance.connect()
})

builder.add(function testSetNotExist(test) {
var cacheInstance = new zcache.RedisConnection('localhost', 6379)

Expand Down

0 comments on commit c73ee28

Please sign in to comment.