Skip to content

Commit ed1138e

Browse files
author
Nathan Lawrence
committed
Add incrby to zcache
1 parent 5e07f76 commit ed1138e

11 files changed

+140
-1
lines changed

lib/CacheCluster.js

+6
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,12 @@ CacheCluster.prototype.get = function (key) {
149149
return this._wrapPromiseWithProfiling(cacheInstance.get(key), 'get')
150150
}
151151

152+
/** @override */
153+
CacheCluster.prototype.incr = function (key, increment) {
154+
var cacheInstance = this._servers[this._hashRing.get(key)]
155+
return this._wrapPromiseWithProfiling(cacheInstance.incr(key, increment), 'set')
156+
}
157+
152158
/** @override */
153159
CacheCluster.prototype.set = function (key, val, maxAgeMs) {
154160
var cacheInstance = this._servers[this._hashRing.get(key)]

lib/CacheInstance.js

+11
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,17 @@ CacheInstance.prototype.get = function (key) {
9696
throw new Error("get() must be implemented by any class extending CacheInstance")
9797
}
9898

99+
/**
100+
* Increment a key.
101+
*
102+
* @param {string} key The key to set
103+
* @param {number=} increment The value to increment by. 1 if unspecified.
104+
* @return {Q.Promise}
105+
*/
106+
CacheInstance.prototype.incr = function (key, increment) {
107+
throw new Error("incr() must be implemented by any class extending CacheInstance")
108+
}
109+
99110
/**
100111
* Set a key.
101112
*

lib/CachePair.js

+7
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,13 @@ CachePair.prototype.get = function (key) {
138138
})
139139
}
140140

141+
/** @override */
142+
CachePair.prototype.incr = function (key, increment) {
143+
var promises = [this._primary.incr(key, increment)]
144+
if (this._maybeOnSecondary(key)) promises.push(this._secondary.incr(key, increment))
145+
return Q.all(promises)
146+
}
147+
141148
/** @override */
142149
CachePair.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
143150
var promises = [this._primary.set(key, val, maxAgeMs, setWhenNotExist)]

lib/FakeCache.js

+22
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,28 @@ FakeCache.prototype.del = function (key) {
7575
})
7676
}
7777

78+
/** @override */
79+
FakeCache.prototype.incr = function (key, increment) {
80+
if (this._failureCount > 0) return this._fakeFail('set')
81+
this._logger.fine('FakeCache - incr', key, increment)
82+
83+
if (increment === undefined) {
84+
increment = 1
85+
}
86+
87+
var self = this
88+
// Add an artificial delay to mimic real world cache latency.
89+
return Q.delay(this._latencyMs)
90+
.then(function actualIncr() {
91+
self._requestCounts.incr += 1
92+
if (key in self._data) {
93+
self._data[key] += increment
94+
} else {
95+
self._data[key] = increment
96+
}
97+
})
98+
}
99+
78100
/** @override */
79101
FakeCache.prototype.set = function (key, value, maxAgeMs, setWhenNotExist) {
80102
if (this._failureCount > 0) return this._fakeFail('set')

lib/InMemoryCache.js

+14
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,20 @@ InMemoryCache.prototype.mget = function (keys) {
121121
return Q.resolve(ret)
122122
}
123123

124+
/** @override */
125+
InMemoryCache.prototype.incr = function (key, increment) {
126+
if (increment === undefined) {
127+
increment = 1
128+
}
129+
130+
if (key in this._data) {
131+
this._data[key] += increment
132+
} else {
133+
this._data[key] = increment
134+
}
135+
return Q.resolve(null)
136+
}
137+
124138
/** @override */
125139
InMemoryCache.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
126140
if ((maxAgeMs === undefined || maxAgeMs <= 0) && !this._maxAgeOverride) {

lib/MultiplexingCache.js

+7
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,13 @@ MultiplexingCache.prototype.mset = function (items, maxAgeMs, setWhenNotExist) {
152152
}
153153

154154

155+
/** @override */
156+
MultiplexingCache.prototype.incr = function (key, increment) {
157+
this._invalidateKeys([key])
158+
return this._delegate.incr(key, increment)
159+
}
160+
161+
155162
/** @override */
156163
MultiplexingCache.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
157164
this._invalidateKeys([key])

lib/RedisConnection.js

+12
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,18 @@ RedisConnection.prototype.isAvailable = function () {
4545
return this._isAvailable
4646
}
4747

48+
/** @override */
49+
RedisConnection.prototype.incr = function (key, increment) {
50+
if (increment === undefined) {
51+
increment = 1
52+
}
53+
54+
var deferred = Q.defer()
55+
var params = [key, increment]
56+
this._client.incrby(params, this._makeNodeResolverWithTimeout(deferred, 'incrby', 'Redis [incr] key: ' + key))
57+
return deferred.promise
58+
}
59+
4860
/** @override */
4961
RedisConnection.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
5062
return this._compress(val)

lib/RedundantCacheGroup.js

+13
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,19 @@ RedundantCacheGroup.prototype.mset = function (items, maxAgeMs, setWhenNotExist)
179179
.then(returnTrue)
180180
}
181181

182+
/** @override */
183+
RedundantCacheGroup.prototype.incr = function (key, increment) {
184+
var instances = this._getAllInstances()
185+
var promises = []
186+
187+
for (var i = 0; i < instances.length; i++) {
188+
promises.push(instances[i].incr(key, increment))
189+
}
190+
191+
return Q.all(promises)
192+
.then(returnTrue)
193+
}
194+
182195
/** @override */
183196
RedundantCacheGroup.prototype.set = function (key, val, maxAgeMs, setWhenNotExist) {
184197
var instances = this._getAllInstances()

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "zcache",
33
"description": "AWS zone-aware multi-layer cache",
4-
"version": "0.5.0",
4+
"version": "0.5.1",
55
"homepage": "https://github.com/Medium/zcache",
66
"authors": [
77
"Jeremy Stanley <[email protected]> (https://github.com/azulus)",

test/test_InMemoryCache.js

+15
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,21 @@ exports.testInMemoryCache = function (test) {
2525
test.done()
2626
}
2727

28+
exports.testCacheIncr = function (test) {
29+
var self = this
30+
test.equal(0, this.cI.getKeyCount(), 'There is no key in cache')
31+
this.cI.incr('counter', 15)
32+
.then(function() {
33+
test.equal(self.cI._data['counter'], 15, '15 should be returned')
34+
test.equal(1, self.cI.getKeyCount(), 'There is 1 key in cache')
35+
return self.cI.incr('counter')
36+
}).then(function() {
37+
test.equal(self.cI._data['counter'], 16, '16 should be returned')
38+
test.equal(1, self.cI.getKeyCount(), 'There is 1 key in cache')
39+
test.done()
40+
})
41+
}
42+
2843
exports.testCacheSet = function (test) {
2944
var self = this
3045
test.equal(0, this.cI.getKeyCount(), 'There is no key in cache')

test/test_RedisConnection.js

+32
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,38 @@ builder.add(function testRedisConnection(test) {
108108
cacheInstance.connect()
109109
})
110110

111+
builder.add(function testIncr(test) {
112+
var cacheInstance = new zcache.RedisConnection('localhost', 6379)
113+
114+
cacheInstance.on('connect', function () {
115+
cacheInstance.removeAllListeners('connect')
116+
test.equal(cacheInstance.isAvailable(), true, 'Connection should be available')
117+
118+
cacheInstance.incr('counter', 15)
119+
.then(function () {
120+
return cacheInstance.incr('counter')
121+
})
122+
.then(function (val) {
123+
return cacheInstance.get('counter')
124+
})
125+
.then(function (val) {
126+
test.equal(val, '16')
127+
cacheInstance.destroy()
128+
})
129+
.fail(function (e) {
130+
console.error(e)
131+
test.fail(e.message)
132+
test.done()
133+
})
134+
})
135+
136+
cacheInstance.on('destroy', function () {
137+
test.done()
138+
})
139+
140+
cacheInstance.connect()
141+
})
142+
111143
builder.add(function testSetNotExist(test) {
112144
var cacheInstance = new zcache.RedisConnection('localhost', 6379)
113145

0 commit comments

Comments
 (0)