mirror of
https://github.com/NodeBB/NodeBB.git
synced 2026-08-31 03:36:51 +02:00
init, just some testing
This commit is contained in:
1
node_modules/redis/.npmignore
generated
vendored
Normal file
1
node_modules/redis/.npmignore
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
707
node_modules/redis/README.md
generated
vendored
Normal file
707
node_modules/redis/README.md
generated
vendored
Normal file
@@ -0,0 +1,707 @@
|
||||
redis - a node.js redis client
|
||||
===========================
|
||||
|
||||
This is a complete Redis client for node.js. It supports all Redis commands, including many recently added commands like EVAL from
|
||||
experimental Redis server branches.
|
||||
|
||||
|
||||
Install with:
|
||||
|
||||
npm install redis
|
||||
|
||||
Pieter Noordhuis has provided a binding to the official `hiredis` C library, which is non-blocking and fast. To use `hiredis`, do:
|
||||
|
||||
npm install hiredis redis
|
||||
|
||||
If `hiredis` is installed, `node_redis` will use it by default. Otherwise, a pure JavaScript parser will be used.
|
||||
|
||||
If you use `hiredis`, be sure to rebuild it whenever you upgrade your version of node. There are mysterious failures that can
|
||||
happen between node and native code modules after a node upgrade.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
Simple example, included as `examples/simple.js`:
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
// if you'd like to select database 3, instead of 0 (default), call
|
||||
// client.select(3, function() { /* ... */ });
|
||||
|
||||
client.on("error", function (err) {
|
||||
console.log("Error " + err);
|
||||
});
|
||||
|
||||
client.set("string key", "string val", redis.print);
|
||||
client.hset("hash key", "hashtest 1", "some value", redis.print);
|
||||
client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
|
||||
client.hkeys("hash key", function (err, replies) {
|
||||
console.log(replies.length + " replies:");
|
||||
replies.forEach(function (reply, i) {
|
||||
console.log(" " + i + ": " + reply);
|
||||
});
|
||||
client.quit();
|
||||
});
|
||||
```
|
||||
|
||||
This will display:
|
||||
|
||||
mjr:~/work/node_redis (master)$ node example.js
|
||||
Reply: OK
|
||||
Reply: 0
|
||||
Reply: 0
|
||||
2 replies:
|
||||
0: hashtest 1
|
||||
1: hashtest 2
|
||||
mjr:~/work/node_redis (master)$
|
||||
|
||||
|
||||
## Performance
|
||||
|
||||
Here are typical results of `multi_bench.js` which is similar to `redis-benchmark` from the Redis distribution.
|
||||
It uses 50 concurrent connections with no pipelining.
|
||||
|
||||
JavaScript parser:
|
||||
|
||||
PING: 20000 ops 42283.30 ops/sec 0/5/1.182
|
||||
SET: 20000 ops 32948.93 ops/sec 1/7/1.515
|
||||
GET: 20000 ops 28694.40 ops/sec 0/9/1.740
|
||||
INCR: 20000 ops 39370.08 ops/sec 0/8/1.269
|
||||
LPUSH: 20000 ops 36429.87 ops/sec 0/8/1.370
|
||||
LRANGE (10 elements): 20000 ops 9891.20 ops/sec 1/9/5.048
|
||||
LRANGE (100 elements): 20000 ops 1384.56 ops/sec 10/91/36.072
|
||||
|
||||
hiredis parser:
|
||||
|
||||
PING: 20000 ops 46189.38 ops/sec 1/4/1.082
|
||||
SET: 20000 ops 41237.11 ops/sec 0/6/1.210
|
||||
GET: 20000 ops 39682.54 ops/sec 1/7/1.257
|
||||
INCR: 20000 ops 40080.16 ops/sec 0/8/1.242
|
||||
LPUSH: 20000 ops 41152.26 ops/sec 0/3/1.212
|
||||
LRANGE (10 elements): 20000 ops 36563.07 ops/sec 1/8/1.363
|
||||
LRANGE (100 elements): 20000 ops 21834.06 ops/sec 0/9/2.287
|
||||
|
||||
The performance of `node_redis` improves dramatically with pipelining, which happens automatically in most normal programs.
|
||||
|
||||
|
||||
### Sending Commands
|
||||
|
||||
Each Redis command is exposed as a function on the `client` object.
|
||||
All functions take either an `args` Array plus optional `callback` Function or
|
||||
a variable number of individual arguments followed by an optional callback.
|
||||
Here is an example of passing an array of arguments and a callback:
|
||||
|
||||
client.mset(["test keys 1", "test val 1", "test keys 2", "test val 2"], function (err, res) {});
|
||||
|
||||
Here is that same call in the second style:
|
||||
|
||||
client.mset("test keys 1", "test val 1", "test keys 2", "test val 2", function (err, res) {});
|
||||
|
||||
Note that in either form the `callback` is optional:
|
||||
|
||||
client.set("some key", "some val");
|
||||
client.set(["some other key", "some val"]);
|
||||
|
||||
If the key is missing, reply will be null (probably):
|
||||
|
||||
client.get("missingkey", function(err, reply) {
|
||||
// reply is null when the key is missing
|
||||
console.log(reply);
|
||||
});
|
||||
|
||||
For a list of Redis commands, see [Redis Command Reference](http://redis.io/commands)
|
||||
|
||||
The commands can be specified in uppercase or lowercase for convenience. `client.get()` is the same as `client.GET()`.
|
||||
|
||||
Minimal parsing is done on the replies. Commands that return a single line reply return JavaScript Strings,
|
||||
integer replies return JavaScript Numbers, "bulk" replies return node Buffers, and "multi bulk" replies return a
|
||||
JavaScript Array of node Buffers. `HGETALL` returns an Object with Buffers keyed by the hash keys.
|
||||
|
||||
# API
|
||||
|
||||
## Connection Events
|
||||
|
||||
`client` will emit some events about the state of the connection to the Redis server.
|
||||
|
||||
### "ready"
|
||||
|
||||
`client` will emit `ready` a connection is established to the Redis server and the server reports
|
||||
that it is ready to receive commands. Commands issued before the `ready` event are queued,
|
||||
then replayed just before this event is emitted.
|
||||
|
||||
### "connect"
|
||||
|
||||
`client` will emit `connect` at the same time as it emits `ready` unless `client.options.no_ready_check`
|
||||
is set. If this options is set, `connect` will be emitted when the stream is connected, and then
|
||||
you are free to try to send commands.
|
||||
|
||||
### "error"
|
||||
|
||||
`client` will emit `error` when encountering an error connecting to the Redis server.
|
||||
|
||||
Note that "error" is a special event type in node. If there are no listeners for an
|
||||
"error" event, node will exit. This is usually what you want, but it can lead to some
|
||||
cryptic error messages like this:
|
||||
|
||||
mjr:~/work/node_redis (master)$ node example.js
|
||||
|
||||
node.js:50
|
||||
throw e;
|
||||
^
|
||||
Error: ECONNREFUSED, Connection refused
|
||||
at IOWatcher.callback (net:870:22)
|
||||
at node.js:607:9
|
||||
|
||||
Not very useful in diagnosing the problem, but if your program isn't ready to handle this,
|
||||
it is probably the right thing to just exit.
|
||||
|
||||
`client` will also emit `error` if an exception is thrown inside of `node_redis` for whatever reason.
|
||||
It would be nice to distinguish these two cases.
|
||||
|
||||
### "end"
|
||||
|
||||
`client` will emit `end` when an established Redis server connection has closed.
|
||||
|
||||
### "drain"
|
||||
|
||||
`client` will emit `drain` when the TCP connection to the Redis server has been buffering, but is now
|
||||
writable. This event can be used to stream commands in to Redis and adapt to backpressure. Right now,
|
||||
you need to check `client.command_queue.length` to decide when to reduce your send rate. Then you can
|
||||
resume sending when you get `drain`.
|
||||
|
||||
### "idle"
|
||||
|
||||
`client` will emit `idle` when there are no outstanding commands that are awaiting a response.
|
||||
|
||||
## redis.createClient(port, host, options)
|
||||
|
||||
Create a new client connection. `port` defaults to `6379` and `host` defaults
|
||||
to `127.0.0.1`. If you have `redis-server` running on the same computer as node, then the defaults for
|
||||
port and host are probably fine. `options` in an object with the following possible properties:
|
||||
|
||||
* `parser`: which Redis protocol reply parser to use. Defaults to `hiredis` if that module is installed.
|
||||
This may also be set to `javascript`.
|
||||
* `return_buffers`: defaults to `false`. If set to `true`, then all replies will be sent to callbacks as node Buffer
|
||||
objects instead of JavaScript Strings.
|
||||
* `detect_buffers`: default to `false`. If set to `true`, then replies will be sent to callbacks as node Buffer objects
|
||||
if any of the input arguments to the original command were Buffer objects.
|
||||
This option lets you switch between Buffers and Strings on a per-command basis, whereas `return_buffers` applies to
|
||||
every command on a client.
|
||||
* `socket_nodelay`: defaults to `true`. Whether to call setNoDelay() on the TCP stream, which disables the
|
||||
Nagle algorithm on the underlying socket. Setting this option to `false` can result in additional throughput at the
|
||||
cost of more latency. Most applications will want this set to `true`.
|
||||
* `no_ready_check`: defaults to `false`. When a connection is established to the Redis server, the server might still
|
||||
be loading the database from disk. While loading, the server not respond to any commands. To work around this,
|
||||
`node_redis` has a "ready check" which sends the `INFO` command to the server. The response from the `INFO` command
|
||||
indicates whether the server is ready for more commands. When ready, `node_redis` emits a `ready` event.
|
||||
Setting `no_ready_check` to `true` will inhibit this check.
|
||||
* `enable_offline_queue`: defaults to `true`. By default, if there is no active
|
||||
connection to the redis server, commands are added to a queue and are executed
|
||||
once the connection has been established. Setting `enable_offline_queue` to
|
||||
`false` will disable this feature and the callback will be execute immediately
|
||||
with an error, or an error will be thrown if no callback is specified.
|
||||
* `retry_max_delay`: defaults to `null`. By default every time the client tries to connect and fails time before
|
||||
reconnection (delay) almost doubles. This delay normally grows infinitely, but setting `retry_max_delay` limits delay
|
||||
to maximum value, provided in milliseconds.
|
||||
* `connect_timeout` defaults to `false`. By default client will try reconnecting until connected. Setting `connect_timeout`
|
||||
limits total time for client to reconnect. Value is provided in milliseconds and is counted once the disconnect occured.
|
||||
* `max_attempts` defaults to `null`. By default client will try reconnecting until connected. Setting `max_attempts`
|
||||
limits total amount of reconnects.
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(null, null, {detect_buffers: true});
|
||||
|
||||
client.set("foo_rand000000000000", "OK");
|
||||
|
||||
// This will return a JavaScript String
|
||||
client.get("foo_rand000000000000", function (err, reply) {
|
||||
console.log(reply.toString()); // Will print `OK`
|
||||
});
|
||||
|
||||
// This will return a Buffer since original key is specified as a Buffer
|
||||
client.get(new Buffer("foo_rand000000000000"), function (err, reply) {
|
||||
console.log(reply.toString()); // Will print `<Buffer 4f 4b>`
|
||||
});
|
||||
client.end();
|
||||
```
|
||||
|
||||
`createClient()` returns a `RedisClient` object that is named `client` in all of the examples here.
|
||||
|
||||
## client.auth(password, callback)
|
||||
|
||||
When connecting to Redis servers that require authentication, the `AUTH` command must be sent as the
|
||||
first command after connecting. This can be tricky to coordinate with reconnections, the ready check,
|
||||
etc. To make this easier, `client.auth()` stashes `password` and will send it after each connection,
|
||||
including reconnections. `callback` is invoked only once, after the response to the very first
|
||||
`AUTH` command sent.
|
||||
NOTE: Your call to `client.auth()` should not be inside the ready handler. If
|
||||
you are doing this wrong, `client` will emit an error that looks
|
||||
something like this `Error: Ready check failed: ERR operation not permitted`.
|
||||
|
||||
## client.end()
|
||||
|
||||
Forcibly close the connection to the Redis server. Note that this does not wait until all replies have been parsed.
|
||||
If you want to exit cleanly, call `client.quit()` to send the `QUIT` command after you have handled all replies.
|
||||
|
||||
This example closes the connection to the Redis server before the replies have been read. You probably don't
|
||||
want to do this:
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
client.set("foo_rand000000000000", "some fantastic value");
|
||||
client.get("foo_rand000000000000", function (err, reply) {
|
||||
console.log(reply.toString());
|
||||
});
|
||||
client.end();
|
||||
```
|
||||
|
||||
`client.end()` is useful for timeout cases where something is stuck or taking too long and you want
|
||||
to start over.
|
||||
|
||||
## Friendlier hash commands
|
||||
|
||||
Most Redis commands take a single String or an Array of Strings as arguments, and replies are sent back as a single String or an Array of Strings.
|
||||
When dealing with hash values, there are a couple of useful exceptions to this.
|
||||
|
||||
### client.hgetall(hash)
|
||||
|
||||
The reply from an HGETALL command will be converted into a JavaScript Object by `node_redis`. That way you can interact
|
||||
with the responses using JavaScript syntax.
|
||||
|
||||
Example:
|
||||
|
||||
client.hmset("hosts", "mjr", "1", "another", "23", "home", "1234");
|
||||
client.hgetall("hosts", function (err, obj) {
|
||||
console.dir(obj);
|
||||
});
|
||||
|
||||
Output:
|
||||
|
||||
{ mjr: '1', another: '23', home: '1234' }
|
||||
|
||||
### client.hmset(hash, obj, [callback])
|
||||
|
||||
Multiple values in a hash can be set by supplying an object:
|
||||
|
||||
client.HMSET(key2, {
|
||||
"0123456789": "abcdefghij", // NOTE: key and value will be coerced to strings
|
||||
"some manner of key": "a type of value"
|
||||
});
|
||||
|
||||
The properties and values of this Object will be set as keys and values in the Redis hash.
|
||||
|
||||
### client.hmset(hash, key1, val1, ... keyn, valn, [callback])
|
||||
|
||||
Multiple values may also be set by supplying a list:
|
||||
|
||||
client.HMSET(key1, "0123456789", "abcdefghij", "some manner of key", "a type of value");
|
||||
|
||||
|
||||
## Publish / Subscribe
|
||||
|
||||
Here is a simple example of the API for publish / subscribe. This program opens two
|
||||
client connections, subscribes to a channel on one of them, and publishes to that
|
||||
channel on the other:
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client1 = redis.createClient(), client2 = redis.createClient(),
|
||||
msg_count = 0;
|
||||
|
||||
client1.on("subscribe", function (channel, count) {
|
||||
client2.publish("a nice channel", "I am sending a message.");
|
||||
client2.publish("a nice channel", "I am sending a second message.");
|
||||
client2.publish("a nice channel", "I am sending my last message.");
|
||||
});
|
||||
|
||||
client1.on("message", function (channel, message) {
|
||||
console.log("client1 channel " + channel + ": " + message);
|
||||
msg_count += 1;
|
||||
if (msg_count === 3) {
|
||||
client1.unsubscribe();
|
||||
client1.end();
|
||||
client2.end();
|
||||
}
|
||||
});
|
||||
|
||||
client1.incr("did a thing");
|
||||
client1.subscribe("a nice channel");
|
||||
```
|
||||
|
||||
When a client issues a `SUBSCRIBE` or `PSUBSCRIBE`, that connection is put into "pub/sub" mode.
|
||||
At that point, only commands that modify the subscription set are valid. When the subscription
|
||||
set is empty, the connection is put back into regular mode.
|
||||
|
||||
If you need to send regular commands to Redis while in pub/sub mode, just open another connection.
|
||||
|
||||
## Pub / Sub Events
|
||||
|
||||
If a client has subscriptions active, it may emit these events:
|
||||
|
||||
### "message" (channel, message)
|
||||
|
||||
Client will emit `message` for every message received that matches an active subscription.
|
||||
Listeners are passed the channel name as `channel` and the message Buffer as `message`.
|
||||
|
||||
### "pmessage" (pattern, channel, message)
|
||||
|
||||
Client will emit `pmessage` for every message received that matches an active subscription pattern.
|
||||
Listeners are passed the original pattern used with `PSUBSCRIBE` as `pattern`, the sending channel
|
||||
name as `channel`, and the message Buffer as `message`.
|
||||
|
||||
### "subscribe" (channel, count)
|
||||
|
||||
Client will emit `subscribe` in response to a `SUBSCRIBE` command. Listeners are passed the
|
||||
channel name as `channel` and the new count of subscriptions for this client as `count`.
|
||||
|
||||
### "psubscribe" (pattern, count)
|
||||
|
||||
Client will emit `psubscribe` in response to a `PSUBSCRIBE` command. Listeners are passed the
|
||||
original pattern as `pattern`, and the new count of subscriptions for this client as `count`.
|
||||
|
||||
### "unsubscribe" (channel, count)
|
||||
|
||||
Client will emit `unsubscribe` in response to a `UNSUBSCRIBE` command. Listeners are passed the
|
||||
channel name as `channel` and the new count of subscriptions for this client as `count`. When
|
||||
`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted.
|
||||
|
||||
### "punsubscribe" (pattern, count)
|
||||
|
||||
Client will emit `punsubscribe` in response to a `PUNSUBSCRIBE` command. Listeners are passed the
|
||||
channel name as `channel` and the new count of subscriptions for this client as `count`. When
|
||||
`count` is 0, this client has left pub/sub mode and no more pub/sub events will be emitted.
|
||||
|
||||
## client.multi([commands])
|
||||
|
||||
`MULTI` commands are queued up until an `EXEC` is issued, and then all commands are run atomically by
|
||||
Redis. The interface in `node_redis` is to return an individual `Multi` object by calling `client.multi()`.
|
||||
|
||||
```js
|
||||
var redis = require("./index"),
|
||||
client = redis.createClient(), set_size = 20;
|
||||
|
||||
client.sadd("bigset", "a member");
|
||||
client.sadd("bigset", "another member");
|
||||
|
||||
while (set_size > 0) {
|
||||
client.sadd("bigset", "member " + set_size);
|
||||
set_size -= 1;
|
||||
}
|
||||
|
||||
// multi chain with an individual callback
|
||||
client.multi()
|
||||
.scard("bigset")
|
||||
.smembers("bigset")
|
||||
.keys("*", function (err, replies) {
|
||||
// NOTE: code in this callback is NOT atomic
|
||||
// this only happens after the the .exec call finishes.
|
||||
client.mget(replies, redis.print);
|
||||
})
|
||||
.dbsize()
|
||||
.exec(function (err, replies) {
|
||||
console.log("MULTI got " + replies.length + " replies");
|
||||
replies.forEach(function (reply, index) {
|
||||
console.log("Reply " + index + ": " + reply.toString());
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
`client.multi()` is a constructor that returns a `Multi` object. `Multi` objects share all of the
|
||||
same command methods as `client` objects do. Commands are queued up inside the `Multi` object
|
||||
until `Multi.exec()` is invoked.
|
||||
|
||||
You can either chain together `MULTI` commands as in the above example, or you can queue individual
|
||||
commands while still sending regular client command as in this example:
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(), multi;
|
||||
|
||||
// start a separate multi command queue
|
||||
multi = client.multi();
|
||||
multi.incr("incr thing", redis.print);
|
||||
multi.incr("incr other thing", redis.print);
|
||||
|
||||
// runs immediately
|
||||
client.mset("incr thing", 100, "incr other thing", 1, redis.print);
|
||||
|
||||
// drains multi queue and runs atomically
|
||||
multi.exec(function (err, replies) {
|
||||
console.log(replies); // 101, 2
|
||||
});
|
||||
|
||||
// you can re-run the same transaction if you like
|
||||
multi.exec(function (err, replies) {
|
||||
console.log(replies); // 102, 3
|
||||
client.quit();
|
||||
});
|
||||
```
|
||||
|
||||
In addition to adding commands to the `MULTI` queue individually, you can also pass an array
|
||||
of commands and arguments to the constructor:
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(), multi;
|
||||
|
||||
client.multi([
|
||||
["mget", "multifoo", "multibar", redis.print],
|
||||
["incr", "multifoo"],
|
||||
["incr", "multibar"]
|
||||
]).exec(function (err, replies) {
|
||||
console.log(replies);
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Monitor mode
|
||||
|
||||
Redis supports the `MONITOR` command, which lets you see all commands received by the Redis server
|
||||
across all client connections, including from other client libraries and other computers.
|
||||
|
||||
After you send the `MONITOR` command, no other commands are valid on that connection. `node_redis`
|
||||
will emit a `monitor` event for every new monitor message that comes across. The callback for the
|
||||
`monitor` event takes a timestamp from the Redis server and an array of command arguments.
|
||||
|
||||
Here is a simple example:
|
||||
|
||||
```js
|
||||
var client = require("redis").createClient(),
|
||||
util = require("util");
|
||||
|
||||
client.monitor(function (err, res) {
|
||||
console.log("Entering monitoring mode.");
|
||||
});
|
||||
|
||||
client.on("monitor", function (time, args) {
|
||||
console.log(time + ": " + util.inspect(args));
|
||||
});
|
||||
```
|
||||
|
||||
# Extras
|
||||
|
||||
Some other things you might like to know about.
|
||||
|
||||
## client.server_info
|
||||
|
||||
After the ready probe completes, the results from the INFO command are saved in the `client.server_info`
|
||||
object.
|
||||
|
||||
The `versions` key contains an array of the elements of the version string for easy comparison.
|
||||
|
||||
> client.server_info.redis_version
|
||||
'2.3.0'
|
||||
> client.server_info.versions
|
||||
[ 2, 3, 0 ]
|
||||
|
||||
## redis.print()
|
||||
|
||||
A handy callback function for displaying return values when testing. Example:
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
client.on("connect", function () {
|
||||
client.set("foo_rand000000000000", "some fantastic value", redis.print);
|
||||
client.get("foo_rand000000000000", redis.print);
|
||||
});
|
||||
```
|
||||
|
||||
This will print:
|
||||
|
||||
Reply: OK
|
||||
Reply: some fantastic value
|
||||
|
||||
Note that this program will not exit cleanly because the client is still connected.
|
||||
|
||||
## redis.debug_mode
|
||||
|
||||
Boolean to enable debug mode and protocol tracing.
|
||||
|
||||
```js
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
redis.debug_mode = true;
|
||||
|
||||
client.on("connect", function () {
|
||||
client.set("foo_rand000000000000", "some fantastic value");
|
||||
});
|
||||
```
|
||||
|
||||
This will display:
|
||||
|
||||
mjr:~/work/node_redis (master)$ node ~/example.js
|
||||
send command: *3
|
||||
$3
|
||||
SET
|
||||
$20
|
||||
foo_rand000000000000
|
||||
$20
|
||||
some fantastic value
|
||||
|
||||
on_data: +OK
|
||||
|
||||
`send command` is data sent into Redis and `on_data` is data received from Redis.
|
||||
|
||||
## Multi-word commands
|
||||
|
||||
To execute redis multi-word commands like `SCRIPT LOAD` or `CLIENT LIST` pass
|
||||
the second word as first parameter:
|
||||
|
||||
client.script('load', 'return 1');
|
||||
client.multi().script('load', 'return 1').exec(...);
|
||||
client.multi([['script', 'load', 'return 1']]).exec(...);
|
||||
|
||||
## client.send_command(command_name, args, callback)
|
||||
|
||||
Used internally to send commands to Redis. For convenience, nearly all commands that are published on the Redis
|
||||
Wiki have been added to the `client` object. However, if I missed any, or if new commands are introduced before
|
||||
this library is updated, you can use `send_command()` to send arbitrary commands to Redis.
|
||||
|
||||
All commands are sent as multi-bulk commands. `args` can either be an Array of arguments, or omitted.
|
||||
|
||||
## client.connected
|
||||
|
||||
Boolean tracking the state of the connection to the Redis server.
|
||||
|
||||
## client.command_queue.length
|
||||
|
||||
The number of commands that have been sent to the Redis server but not yet replied to. You can use this to
|
||||
enforce some kind of maximum queue depth for commands while connected.
|
||||
|
||||
Don't mess with `client.command_queue` though unless you really know what you are doing.
|
||||
|
||||
## client.offline_queue.length
|
||||
|
||||
The number of commands that have been queued up for a future connection. You can use this to enforce
|
||||
some kind of maximum queue depth for pre-connection commands.
|
||||
|
||||
## client.retry_delay
|
||||
|
||||
Current delay in milliseconds before a connection retry will be attempted. This starts at `250`.
|
||||
|
||||
## client.retry_backoff
|
||||
|
||||
Multiplier for future retry timeouts. This should be larger than 1 to add more time between retries.
|
||||
Defaults to 1.7. The default initial connection retry is 250, so the second retry will be 425, followed by 723.5, etc.
|
||||
|
||||
### Commands with Optional and Keyword arguments
|
||||
|
||||
This applies to anything that uses an optional `[WITHSCORES]` or `[LIMIT offset count]` in the [redis.io/commands](http://redis.io/commands) documentation.
|
||||
|
||||
Example:
|
||||
```js
|
||||
var args = [ 'myzset', 1, 'one', 2, 'two', 3, 'three', 99, 'ninety-nine' ];
|
||||
client.zadd(args, function (err, response) {
|
||||
if (err) throw err;
|
||||
console.log('added '+response+' items.');
|
||||
|
||||
// -Infinity and +Infinity also work
|
||||
var args1 = [ 'myzset', '+inf', '-inf' ];
|
||||
client.zrevrangebyscore(args1, function (err, response) {
|
||||
if (err) throw err;
|
||||
console.log('example1', response);
|
||||
// write your code here
|
||||
});
|
||||
|
||||
var max = 3, min = 1, offset = 1, count = 2;
|
||||
var args2 = [ 'myzset', max, min, 'WITHSCORES', 'LIMIT', offset, count ];
|
||||
client.zrevrangebyscore(args2, function (err, response) {
|
||||
if (err) throw err;
|
||||
console.log('example2', response);
|
||||
// write your code here
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## TODO
|
||||
|
||||
Better tests for auth, disconnect/reconnect, and all combinations thereof.
|
||||
|
||||
Stream large set/get values into and out of Redis. Otherwise the entire value must be in node's memory.
|
||||
|
||||
Performance can be better for very large values.
|
||||
|
||||
I think there are more performance improvements left in there for smaller values, especially for large lists of small values.
|
||||
|
||||
## How to Contribute
|
||||
- open a pull request and then wait for feedback (if
|
||||
[DTrejo](http://github.com/dtrejo) does not get back to you within 2 days,
|
||||
comment again with indignation!)
|
||||
|
||||
## Contributors
|
||||
Some people have have added features and fixed bugs in `node_redis` other than me.
|
||||
|
||||
Ordered by date of first contribution.
|
||||
[Auto-generated](http://github.com/dtrejo/node-authors) on Wed Jul 25 2012 19:14:59 GMT-0700 (PDT).
|
||||
|
||||
- [Matt Ranney aka `mranney`](https://github.com/mranney)
|
||||
- [Tim-Smart aka `tim-smart`](https://github.com/tim-smart)
|
||||
- [Tj Holowaychuk aka `visionmedia`](https://github.com/visionmedia)
|
||||
- [rick aka `technoweenie`](https://github.com/technoweenie)
|
||||
- [Orion Henry aka `orionz`](https://github.com/orionz)
|
||||
- [Aivo Paas aka `aivopaas`](https://github.com/aivopaas)
|
||||
- [Hank Sims aka `hanksims`](https://github.com/hanksims)
|
||||
- [Paul Carey aka `paulcarey`](https://github.com/paulcarey)
|
||||
- [Pieter Noordhuis aka `pietern`](https://github.com/pietern)
|
||||
- [nithesh aka `nithesh`](https://github.com/nithesh)
|
||||
- [Andy Ray aka `andy2ray`](https://github.com/andy2ray)
|
||||
- [unknown aka `unknowdna`](https://github.com/unknowdna)
|
||||
- [Dave Hoover aka `redsquirrel`](https://github.com/redsquirrel)
|
||||
- [Vladimir Dronnikov aka `dvv`](https://github.com/dvv)
|
||||
- [Umair Siddique aka `umairsiddique`](https://github.com/umairsiddique)
|
||||
- [Louis-Philippe Perron aka `lp`](https://github.com/lp)
|
||||
- [Mark Dawson aka `markdaws`](https://github.com/markdaws)
|
||||
- [Ian Babrou aka `bobrik`](https://github.com/bobrik)
|
||||
- [Felix Geisendörfer aka `felixge`](https://github.com/felixge)
|
||||
- [Jean-Hugues Pinson aka `undefined`](https://github.com/undefined)
|
||||
- [Maksim Lin aka `maks`](https://github.com/maks)
|
||||
- [Owen Smith aka `orls`](https://github.com/orls)
|
||||
- [Zachary Scott aka `zzak`](https://github.com/zzak)
|
||||
- [TEHEK Firefox aka `TEHEK`](https://github.com/TEHEK)
|
||||
- [Isaac Z. Schlueter aka `isaacs`](https://github.com/isaacs)
|
||||
- [David Trejo aka `DTrejo`](https://github.com/DTrejo)
|
||||
- [Brian Noguchi aka `bnoguchi`](https://github.com/bnoguchi)
|
||||
- [Philip Tellis aka `bluesmoon`](https://github.com/bluesmoon)
|
||||
- [Marcus Westin aka `marcuswestin2`](https://github.com/marcuswestin2)
|
||||
- [Jed Schmidt aka `jed`](https://github.com/jed)
|
||||
- [Dave Peticolas aka `jdavisp3`](https://github.com/jdavisp3)
|
||||
- [Trae Robrock aka `trobrock`](https://github.com/trobrock)
|
||||
- [Shankar Karuppiah aka `shankar0306`](https://github.com/shankar0306)
|
||||
- [Ignacio Burgueño aka `ignacio`](https://github.com/ignacio)
|
||||
|
||||
Thanks.
|
||||
|
||||
## LICENSE - "MIT License"
|
||||
|
||||
Copyright (c) 2010 Matthew Ranney, http://ranney.com/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without
|
||||
restriction, including without limitation the rights to use,
|
||||
copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||

|
||||
89
node_modules/redis/benches/buffer_bench.js
generated
vendored
Normal file
89
node_modules/redis/benches/buffer_bench.js
generated
vendored
Normal file
@@ -0,0 +1,89 @@
|
||||
var source = new Buffer(100),
|
||||
dest = new Buffer(100), i, j, k, tmp, count = 1000000, bytes = 100;
|
||||
|
||||
for (i = 99 ; i >= 0 ; i--) {
|
||||
source[i] = 120;
|
||||
}
|
||||
|
||||
var str = "This is a nice String.",
|
||||
buf = new Buffer("This is a lovely Buffer.");
|
||||
|
||||
var start = new Date();
|
||||
for (i = count * 100; i > 0 ; i--) {
|
||||
if (Buffer.isBuffer(str)) {}
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("Buffer.isBuffer(str) " + (end - start) + " ms");
|
||||
|
||||
var start = new Date();
|
||||
for (i = count * 100; i > 0 ; i--) {
|
||||
if (Buffer.isBuffer(buf)) {}
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("Buffer.isBuffer(buf) " + (end - start) + " ms");
|
||||
|
||||
var start = new Date();
|
||||
for (i = count * 100; i > 0 ; i--) {
|
||||
if (str instanceof Buffer) {}
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("str instanceof Buffer " + (end - start) + " ms");
|
||||
|
||||
var start = new Date();
|
||||
for (i = count * 100; i > 0 ; i--) {
|
||||
if (buf instanceof Buffer) {}
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("buf instanceof Buffer " + (end - start) + " ms");
|
||||
|
||||
for (i = bytes ; i > 0 ; i --) {
|
||||
var start = new Date();
|
||||
for (j = count ; j > 0; j--) {
|
||||
tmp = source.toString("ascii", 0, bytes);
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("toString() " + i + " bytes " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
for (i = bytes ; i > 0 ; i --) {
|
||||
var start = new Date();
|
||||
for (j = count ; j > 0; j--) {
|
||||
tmp = "";
|
||||
for (k = 0; k <= i ; k++) {
|
||||
tmp += String.fromCharCode(source[k]);
|
||||
}
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("manual string " + i + " bytes " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
for (i = bytes ; i > 0 ; i--) {
|
||||
var start = new Date();
|
||||
for (j = count ; j > 0 ; j--) {
|
||||
for (k = i ; k > 0 ; k--) {
|
||||
dest[k] = source[k];
|
||||
}
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("Manual copy " + i + " bytes " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
for (i = bytes ; i > 0 ; i--) {
|
||||
var start = new Date();
|
||||
for (j = count ; j > 0 ; j--) {
|
||||
for (k = i ; k > 0 ; k--) {
|
||||
dest[k] = 120;
|
||||
}
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("Direct assignment " + i + " bytes " + (end - start) + " ms");
|
||||
}
|
||||
|
||||
for (i = bytes ; i > 0 ; i--) {
|
||||
var start = new Date();
|
||||
for (j = count ; j > 0 ; j--) {
|
||||
source.copy(dest, 0, 0, i);
|
||||
}
|
||||
var end = new Date();
|
||||
console.log("Buffer.copy() " + i + " bytes " + (end - start) + " ms");
|
||||
}
|
||||
38
node_modules/redis/benches/hiredis_parser.js
generated
vendored
Normal file
38
node_modules/redis/benches/hiredis_parser.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
var Parser = require('../lib/parser/hiredis').Parser;
|
||||
var assert = require('assert');
|
||||
|
||||
/*
|
||||
This test makes sure that exceptions thrown inside of "reply" event handlers
|
||||
are not trapped and mistakenly emitted as parse errors.
|
||||
*/
|
||||
(function testExecuteDoesNotCatchReplyCallbackExceptions() {
|
||||
var parser = new Parser();
|
||||
var replies = [{}];
|
||||
|
||||
parser.reader = {
|
||||
feed: function() {},
|
||||
get: function() {
|
||||
return replies.shift();
|
||||
}
|
||||
};
|
||||
|
||||
var emittedError = false;
|
||||
var caughtException = false;
|
||||
|
||||
parser
|
||||
.on('error', function() {
|
||||
emittedError = true;
|
||||
})
|
||||
.on('reply', function() {
|
||||
throw new Error('bad');
|
||||
});
|
||||
|
||||
try {
|
||||
parser.execute();
|
||||
} catch (err) {
|
||||
caughtException = true;
|
||||
}
|
||||
|
||||
assert.equal(caughtException, true);
|
||||
assert.equal(emittedError, false);
|
||||
})();
|
||||
14
node_modules/redis/benches/re_sub_test.js
generated
vendored
Normal file
14
node_modules/redis/benches/re_sub_test.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
var client = require('../index').createClient()
|
||||
, client2 = require('../index').createClient()
|
||||
, assert = require('assert');
|
||||
|
||||
client.once('subscribe', function (channel, count) {
|
||||
client.unsubscribe('x');
|
||||
client.subscribe('x', function () {
|
||||
client.quit();
|
||||
client2.quit();
|
||||
});
|
||||
client2.publish('x', 'hi');
|
||||
});
|
||||
|
||||
client.subscribe('x');
|
||||
29
node_modules/redis/benches/reconnect_test.js
generated
vendored
Normal file
29
node_modules/redis/benches/reconnect_test.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
var redis = require("../index").createClient(null, null, {
|
||||
// max_attempts: 4
|
||||
});
|
||||
|
||||
redis.on("error", function (err) {
|
||||
console.log("Redis says: " + err);
|
||||
});
|
||||
|
||||
redis.on("ready", function () {
|
||||
console.log("Redis ready.");
|
||||
});
|
||||
|
||||
redis.on("reconnecting", function (arg) {
|
||||
console.log("Redis reconnecting: " + JSON.stringify(arg));
|
||||
});
|
||||
redis.on("connect", function () {
|
||||
console.log("Redis connected.");
|
||||
});
|
||||
|
||||
setInterval(function () {
|
||||
var now = Date.now();
|
||||
redis.set("now", now, function (err, res) {
|
||||
if (err) {
|
||||
console.log(now + " Redis reply error: " + err);
|
||||
} else {
|
||||
console.log(now + " Redis reply: " + res);
|
||||
}
|
||||
});
|
||||
}, 100);
|
||||
16
node_modules/redis/benches/stress/codec.js
generated
vendored
Normal file
16
node_modules/redis/benches/stress/codec.js
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
var json = {
|
||||
encode: JSON.stringify,
|
||||
decode: JSON.parse
|
||||
};
|
||||
|
||||
var MsgPack = require('node-msgpack');
|
||||
msgpack = {
|
||||
encode: MsgPack.pack,
|
||||
decode: function(str) { return MsgPack.unpack(new Buffer(str)); }
|
||||
};
|
||||
|
||||
bison = require('bison');
|
||||
|
||||
module.exports = json;
|
||||
//module.exports = msgpack;
|
||||
//module.exports = bison;
|
||||
38
node_modules/redis/benches/stress/pubsub/pub.js
generated
vendored
Normal file
38
node_modules/redis/benches/stress/pubsub/pub.js
generated
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
'use strict';
|
||||
|
||||
var freemem = require('os').freemem;
|
||||
var profiler = require('v8-profiler');
|
||||
var codec = require('../codec');
|
||||
|
||||
var sent = 0;
|
||||
|
||||
var pub = require('redis').createClient(null, null, {
|
||||
//command_queue_high_water: 5,
|
||||
//command_queue_low_water: 1
|
||||
})
|
||||
.on('ready', function() {
|
||||
this.emit('drain');
|
||||
})
|
||||
.on('drain', function() {
|
||||
process.nextTick(exec);
|
||||
});
|
||||
|
||||
var payload = '1'; for (var i = 0; i < 12; ++i) payload += payload;
|
||||
console.log('Message payload length', payload.length);
|
||||
|
||||
function exec() {
|
||||
pub.publish('timeline', codec.encode({ foo: payload }));
|
||||
++sent;
|
||||
if (!pub.should_buffer) {
|
||||
process.nextTick(exec);
|
||||
}
|
||||
}
|
||||
|
||||
profiler.takeSnapshot('s_0');
|
||||
|
||||
exec();
|
||||
|
||||
setInterval(function() {
|
||||
profiler.takeSnapshot('s_' + sent);
|
||||
console.error('sent', sent, 'free', freemem(), 'cmdqlen', pub.command_queue.length, 'offqlen', pub.offline_queue.length);
|
||||
}, 2000);
|
||||
10
node_modules/redis/benches/stress/pubsub/run
generated
vendored
Normal file
10
node_modules/redis/benches/stress/pubsub/run
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
node server.js &
|
||||
node server.js &
|
||||
node server.js &
|
||||
node server.js &
|
||||
node server.js &
|
||||
node server.js &
|
||||
node server.js &
|
||||
node server.js &
|
||||
node --debug pub.js
|
||||
23
node_modules/redis/benches/stress/pubsub/server.js
generated
vendored
Normal file
23
node_modules/redis/benches/stress/pubsub/server.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
'use strict';
|
||||
|
||||
var freemem = require('os').freemem;
|
||||
var codec = require('../codec');
|
||||
|
||||
var id = Math.random();
|
||||
var recv = 0;
|
||||
|
||||
var sub = require('redis').createClient()
|
||||
.on('ready', function() {
|
||||
this.subscribe('timeline');
|
||||
})
|
||||
.on('message', function(channel, message) {
|
||||
var self = this;
|
||||
if (message) {
|
||||
message = codec.decode(message);
|
||||
++recv;
|
||||
}
|
||||
});
|
||||
|
||||
setInterval(function() {
|
||||
console.error('id', id, 'received', recv, 'free', freemem());
|
||||
}, 2000);
|
||||
49
node_modules/redis/benches/stress/rpushblpop/pub.js
generated
vendored
Normal file
49
node_modules/redis/benches/stress/rpushblpop/pub.js
generated
vendored
Normal file
@@ -0,0 +1,49 @@
|
||||
'use strict';
|
||||
|
||||
var freemem = require('os').freemem;
|
||||
//var profiler = require('v8-profiler');
|
||||
var codec = require('../codec');
|
||||
|
||||
var sent = 0;
|
||||
|
||||
var pub = require('redis').createClient(null, null, {
|
||||
//command_queue_high_water: 5,
|
||||
//command_queue_low_water: 1
|
||||
})
|
||||
.on('ready', function() {
|
||||
this.del('timeline');
|
||||
this.emit('drain');
|
||||
})
|
||||
.on('drain', function() {
|
||||
process.nextTick(exec);
|
||||
});
|
||||
|
||||
var payload = '1'; for (var i = 0; i < 12; ++i) payload += payload;
|
||||
console.log('Message payload length', payload.length);
|
||||
|
||||
function exec() {
|
||||
pub.rpush('timeline', codec.encode({ foo: payload }));
|
||||
++sent;
|
||||
if (!pub.should_buffer) {
|
||||
process.nextTick(exec);
|
||||
}
|
||||
}
|
||||
|
||||
//profiler.takeSnapshot('s_0');
|
||||
|
||||
exec();
|
||||
|
||||
setInterval(function() {
|
||||
//var ss = profiler.takeSnapshot('s_' + sent);
|
||||
//console.error(ss.stringify());
|
||||
pub.llen('timeline', function(err, result) {
|
||||
console.error('sent', sent, 'free', freemem(),
|
||||
'cmdqlen', pub.command_queue.length, 'offqlen', pub.offline_queue.length,
|
||||
'llen', result
|
||||
);
|
||||
});
|
||||
}, 2000);
|
||||
|
||||
/*setTimeout(function() {
|
||||
process.exit();
|
||||
}, 30000);*/
|
||||
6
node_modules/redis/benches/stress/rpushblpop/run
generated
vendored
Normal file
6
node_modules/redis/benches/stress/rpushblpop/run
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
node server.js &
|
||||
#node server.js &
|
||||
#node server.js &
|
||||
#node server.js &
|
||||
node --debug pub.js
|
||||
30
node_modules/redis/benches/stress/rpushblpop/server.js
generated
vendored
Normal file
30
node_modules/redis/benches/stress/rpushblpop/server.js
generated
vendored
Normal file
@@ -0,0 +1,30 @@
|
||||
'use strict';
|
||||
|
||||
var freemem = require('os').freemem;
|
||||
var codec = require('../codec');
|
||||
|
||||
var id = Math.random();
|
||||
var recv = 0;
|
||||
|
||||
var cmd = require('redis').createClient();
|
||||
var sub = require('redis').createClient()
|
||||
.on('ready', function() {
|
||||
this.emit('timeline');
|
||||
})
|
||||
.on('timeline', function() {
|
||||
var self = this;
|
||||
this.blpop('timeline', 0, function(err, result) {
|
||||
var message = result[1];
|
||||
if (message) {
|
||||
message = codec.decode(message);
|
||||
++recv;
|
||||
}
|
||||
self.emit('timeline');
|
||||
});
|
||||
});
|
||||
|
||||
setInterval(function() {
|
||||
cmd.llen('timeline', function(err, result) {
|
||||
console.error('id', id, 'received', recv, 'free', freemem(), 'llen', result);
|
||||
});
|
||||
}, 2000);
|
||||
13
node_modules/redis/benches/stress/speed/00
generated
vendored
Normal file
13
node_modules/redis/benches/stress/speed/00
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
# size JSON msgpack bison
|
||||
26602 2151.0170848180414
|
||||
25542 ? 2842.589272665782
|
||||
24835 ? ? 7280.4538397469805
|
||||
6104 6985.234528557929
|
||||
5045 ? 7217.461392841478
|
||||
4341 ? ? 14261.406335354604
|
||||
4180 15864.633685636572
|
||||
4143 ? 12954.806235781925
|
||||
4141 ? ? 44650.70733912719
|
||||
75 114227.07313350472
|
||||
40 ? 30162.440062810834
|
||||
39 ? ? 119815.66013519121
|
||||
13
node_modules/redis/benches/stress/speed/plot
generated
vendored
Normal file
13
node_modules/redis/benches/stress/speed/plot
generated
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
#!/bin/sh
|
||||
|
||||
gnuplot >size-rate.jpg << _EOF_
|
||||
|
||||
set terminal png nocrop enhanced font verdana 12 size 640,480
|
||||
set logscale x
|
||||
set logscale y
|
||||
set grid
|
||||
set xlabel 'Serialized object size, octets'
|
||||
set ylabel 'decode(encode(obj)) rate, 1/sec'
|
||||
plot '00' using 1:2 title 'json' smooth bezier, '00' using 1:3 title 'msgpack' smooth bezier, '00' using 1:4 title 'bison' smooth bezier
|
||||
|
||||
_EOF_
|
||||
BIN
node_modules/redis/benches/stress/speed/size-rate.png
generated
vendored
Normal file
BIN
node_modules/redis/benches/stress/speed/size-rate.png
generated
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
84
node_modules/redis/benches/stress/speed/speed.js
generated
vendored
Normal file
84
node_modules/redis/benches/stress/speed/speed.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
var msgpack = require('node-msgpack');
|
||||
var bison = require('bison');
|
||||
var codec = {
|
||||
JSON: {
|
||||
encode: JSON.stringify,
|
||||
decode: JSON.parse
|
||||
},
|
||||
msgpack: {
|
||||
encode: msgpack.pack,
|
||||
decode: msgpack.unpack
|
||||
},
|
||||
bison: bison
|
||||
};
|
||||
|
||||
var obj, l;
|
||||
|
||||
var s = '0';
|
||||
for (var i = 0; i < 12; ++i) s += s;
|
||||
|
||||
obj = {
|
||||
foo: s,
|
||||
arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
|
||||
rand: [],
|
||||
a: s,
|
||||
ccc: s,
|
||||
b: s + s + s
|
||||
};
|
||||
for (i = 0; i < 100; ++i) obj.rand.push(Math.random());
|
||||
forObj(obj);
|
||||
|
||||
obj = {
|
||||
foo: s,
|
||||
arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
|
||||
rand: []
|
||||
};
|
||||
for (i = 0; i < 100; ++i) obj.rand.push(Math.random());
|
||||
forObj(obj);
|
||||
|
||||
obj = {
|
||||
foo: s,
|
||||
arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
|
||||
rand: []
|
||||
};
|
||||
forObj(obj);
|
||||
|
||||
obj = {
|
||||
arrrrrr: [{a:1,b:false,c:null,d:1.0}, 1111, 2222, 33333333],
|
||||
rand: []
|
||||
};
|
||||
forObj(obj);
|
||||
|
||||
function run(obj, codec) {
|
||||
var t1 = Date.now();
|
||||
var n = 10000;
|
||||
for (var i = 0; i < n; ++i) {
|
||||
codec.decode(l = codec.encode(obj));
|
||||
}
|
||||
var t2 = Date.now();
|
||||
//console.log('DONE', n*1000/(t2-t1), 'codecs/sec, length=', l.length);
|
||||
return [n*1000/(t2-t1), l.length];
|
||||
}
|
||||
|
||||
function series(obj, cname, n) {
|
||||
var rate = 0;
|
||||
var len = 0;
|
||||
for (var i = 0; i < n; ++i) {
|
||||
var r = run(obj, codec[cname]);
|
||||
rate += r[0];
|
||||
len += r[1];
|
||||
}
|
||||
rate /= n;
|
||||
len /= n;
|
||||
console.log(cname + ' ' + rate + ' ' + len);
|
||||
return [rate, len];
|
||||
}
|
||||
|
||||
function forObj(obj) {
|
||||
var r = {
|
||||
JSON: series(obj, 'JSON', 20),
|
||||
msgpack: series(obj, 'msgpack', 20),
|
||||
bison: series(obj, 'bison', 20)
|
||||
};
|
||||
return r;
|
||||
}
|
||||
18
node_modules/redis/benches/sub_quit_test.js
generated
vendored
Normal file
18
node_modules/redis/benches/sub_quit_test.js
generated
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
var client = require("redis").createClient(),
|
||||
client2 = require("redis").createClient();
|
||||
|
||||
client.subscribe("something");
|
||||
client.on("subscribe", function (channel, count) {
|
||||
console.log("Got sub: " + channel);
|
||||
client.unsubscribe("something");
|
||||
});
|
||||
|
||||
client.on("unsubscribe", function (channel, count) {
|
||||
console.log("Got unsub: " + channel + ", quitting");
|
||||
client.quit();
|
||||
});
|
||||
|
||||
// exercise unsub before sub
|
||||
client2.unsubscribe("something");
|
||||
client2.subscribe("another thing");
|
||||
client2.quit();
|
||||
240
node_modules/redis/changelog.md
generated
vendored
Normal file
240
node_modules/redis/changelog.md
generated
vendored
Normal file
@@ -0,0 +1,240 @@
|
||||
Changelog
|
||||
=========
|
||||
|
||||
## v0.8.2 - November 11, 2012
|
||||
|
||||
Another version bump because 0.8.1 didn't get applied properly for some mysterious reason.
|
||||
Sorry about that.
|
||||
|
||||
Changed name of "faster" parser to "javascript".
|
||||
|
||||
## v0.8.1 - September 11, 2012
|
||||
|
||||
Important bug fix for null responses (Jerry Sievert)
|
||||
|
||||
## v0.8.0 - September 10, 2012
|
||||
|
||||
Many contributed features and fixes, including:
|
||||
|
||||
* Pure JavaScript reply parser that is usually faster than hiredis (Jerry Sievert)
|
||||
* Remove hiredis as optionalDependency from package.json. It still works if you want it.
|
||||
* Restore client state on reconnect, including select, subscribe, and monitor. (Ignacio Burgueño)
|
||||
* Fix idle event (Trae Robrock)
|
||||
* Many documentation improvements and bug fixes (David Trejo)
|
||||
|
||||
## v0.7.2 - April 29, 2012
|
||||
|
||||
Many contributed fixes. Thank you, contributors.
|
||||
|
||||
* [GH-190] - pub/sub mode fix (Brian Noguchi)
|
||||
* [GH-165] - parser selection fix (TEHEK)
|
||||
* numerous documentation and examples updates
|
||||
* auth errors emit Errors instead of Strings (David Trejo)
|
||||
|
||||
## v0.7.1 - November 15, 2011
|
||||
|
||||
Fix regression in reconnect logic.
|
||||
|
||||
Very much need automated tests for reconnection and queue logic.
|
||||
|
||||
## v0.7.0 - November 14, 2011
|
||||
|
||||
Many contributed fixes. Thanks everybody.
|
||||
|
||||
* [GH-127] - properly re-initialize parser on reconnect
|
||||
* [GH-136] - handle passing undefined as callback (Ian Babrou)
|
||||
* [GH-139] - properly handle exceptions thrown in pub/sub event handlers (Felix Geisendörfer)
|
||||
* [GH-141] - detect closing state on stream error (Felix Geisendörfer)
|
||||
* [GH-142] - re-select database on reconnection (Jean-Hugues Pinson)
|
||||
* [GH-146] - add sort example (Maksim Lin)
|
||||
|
||||
Some more goodies:
|
||||
|
||||
* Fix bugs with node 0.6
|
||||
* Performance improvements
|
||||
* New version of `multi_bench.js` that tests more realistic scenarios
|
||||
* [GH-140] - support optional callback for subscribe commands
|
||||
* Properly flush and error out command queue when connection fails
|
||||
* Initial work on reconnection thresholds
|
||||
|
||||
## v0.6.7 - July 30, 2011
|
||||
|
||||
(accidentally skipped v0.6.6)
|
||||
|
||||
Fix and test for [GH-123]
|
||||
|
||||
Passing an Array as as the last argument should expand as users
|
||||
expect. The old behavior was to coerce the arguments into Strings,
|
||||
which did surprising things with Arrays.
|
||||
|
||||
## v0.6.5 - July 6, 2011
|
||||
|
||||
Contributed changes:
|
||||
|
||||
* Support SlowBuffers (Umair Siddique)
|
||||
* Add Multi to exports (Louis-Philippe Perron)
|
||||
* Fix for drain event calculation (Vladimir Dronnikov)
|
||||
|
||||
Thanks!
|
||||
|
||||
## v0.6.4 - June 30, 2011
|
||||
|
||||
Fix bug with optional callbacks for hmset.
|
||||
|
||||
## v0.6.2 - June 30, 2011
|
||||
|
||||
Bugs fixed:
|
||||
|
||||
* authentication retry while server is loading db (danmaz74) [GH-101]
|
||||
* command arguments processing issue with arrays
|
||||
|
||||
New features:
|
||||
|
||||
* Auto update of new commands from redis.io (Dave Hoover)
|
||||
* Performance improvements and backpressure controls.
|
||||
* Commands now return the true/false value from the underlying socket write(s).
|
||||
* Implement command_queue high water and low water for more better control of queueing.
|
||||
|
||||
See `examples/backpressure_drain.js` for more information.
|
||||
|
||||
## v0.6.1 - June 29, 2011
|
||||
|
||||
Add support and tests for Redis scripting through EXEC command.
|
||||
|
||||
Bug fix for monitor mode. (forddg)
|
||||
|
||||
Auto update of new commands from redis.io (Dave Hoover)
|
||||
|
||||
## v0.6.0 - April 21, 2011
|
||||
|
||||
Lots of bugs fixed.
|
||||
|
||||
* connection error did not properly trigger reconnection logic [GH-85]
|
||||
* client.hmget(key, [val1, val2]) was not expanding properly [GH-66]
|
||||
* client.quit() while in pub/sub mode would throw an error [GH-87]
|
||||
* client.multi(['hmset', 'key', {foo: 'bar'}]) fails [GH-92]
|
||||
* unsubscribe before subscribe would make things very confused [GH-88]
|
||||
* Add BRPOPLPUSH [GH-79]
|
||||
|
||||
## v0.5.11 - April 7, 2011
|
||||
|
||||
Added DISCARD
|
||||
|
||||
I originally didn't think DISCARD would do anything here because of the clever MULTI interface, but somebody
|
||||
pointed out to me that DISCARD can be used to flush the WATCH set.
|
||||
|
||||
## v0.5.10 - April 6, 2011
|
||||
|
||||
Added HVALS
|
||||
|
||||
## v0.5.9 - March 14, 2011
|
||||
|
||||
Fix bug with empty Array arguments - Andy Ray
|
||||
|
||||
## v0.5.8 - March 14, 2011
|
||||
|
||||
Add `MONITOR` command and special monitor command reply parsing.
|
||||
|
||||
## v0.5.7 - February 27, 2011
|
||||
|
||||
Add magical auth command.
|
||||
|
||||
Authentication is now remembered by the client and will be automatically sent to the server
|
||||
on every connection, including any reconnections.
|
||||
|
||||
## v0.5.6 - February 22, 2011
|
||||
|
||||
Fix bug in ready check with `return_buffers` set to `true`.
|
||||
|
||||
Thanks to Dean Mao and Austin Chau.
|
||||
|
||||
## v0.5.5 - February 16, 2011
|
||||
|
||||
Add probe for server readiness.
|
||||
|
||||
When a Redis server starts up, it might take a while to load the dataset into memory.
|
||||
During this time, the server will accept connections, but will return errors for all non-INFO
|
||||
commands. Now node_redis will send an INFO command whenever it connects to a server.
|
||||
If the info command indicates that the server is not ready, the client will keep trying until
|
||||
the server is ready. Once it is ready, the client will emit a "ready" event as well as the
|
||||
"connect" event. The client will queue up all commands sent before the server is ready, just
|
||||
like it did before. When the server is ready, all offline/non-ready commands will be replayed.
|
||||
This should be backward compatible with previous versions.
|
||||
|
||||
To disable this ready check behavior, set `options.no_ready_check` when creating the client.
|
||||
|
||||
As a side effect of this change, the key/val params from the info command are available as
|
||||
`client.server_options`. Further, the version string is decomposed into individual elements
|
||||
in `client.server_options.versions`.
|
||||
|
||||
## v0.5.4 - February 11, 2011
|
||||
|
||||
Fix excess memory consumption from Queue backing store.
|
||||
|
||||
Thanks to Gustaf Sjöberg.
|
||||
|
||||
## v0.5.3 - February 5, 2011
|
||||
|
||||
Fix multi/exec error reply callback logic.
|
||||
|
||||
Thanks to Stella Laurenzo.
|
||||
|
||||
## v0.5.2 - January 18, 2011
|
||||
|
||||
Fix bug where unhandled error replies confuse the parser.
|
||||
|
||||
## v0.5.1 - January 18, 2011
|
||||
|
||||
Fix bug where subscribe commands would not handle redis-server startup error properly.
|
||||
|
||||
## v0.5.0 - December 29, 2010
|
||||
|
||||
Some bug fixes:
|
||||
|
||||
* An important bug fix in reconnection logic. Previously, reply callbacks would be invoked twice after
|
||||
a reconnect.
|
||||
* Changed error callback argument to be an actual Error object.
|
||||
|
||||
New feature:
|
||||
|
||||
* Add friendly syntax for HMSET using an object.
|
||||
|
||||
## v0.4.1 - December 8, 2010
|
||||
|
||||
Remove warning about missing hiredis. You probably do want it though.
|
||||
|
||||
## v0.4.0 - December 5, 2010
|
||||
|
||||
Support for multiple response parsers and hiredis C library from Pieter Noordhuis.
|
||||
Return Strings instead of Buffers by default.
|
||||
Empty nested mb reply bug fix.
|
||||
|
||||
## v0.3.9 - November 30, 2010
|
||||
|
||||
Fix parser bug on failed EXECs.
|
||||
|
||||
## v0.3.8 - November 10, 2010
|
||||
|
||||
Fix for null MULTI response when WATCH condition fails.
|
||||
|
||||
## v0.3.7 - November 9, 2010
|
||||
|
||||
Add "drain" and "idle" events.
|
||||
|
||||
## v0.3.6 - November 3, 2010
|
||||
|
||||
Add all known Redis commands from Redis master, even ones that are coming in 2.2 and beyond.
|
||||
|
||||
Send a friendlier "error" event message on stream errors like connection refused / reset.
|
||||
|
||||
## v0.3.5 - October 21, 2010
|
||||
|
||||
A few bug fixes.
|
||||
|
||||
* Fixed bug with `nil` multi-bulk reply lengths that showed up with `BLPOP` timeouts.
|
||||
* Only emit `end` once when connection goes away.
|
||||
* Fixed bug in `test.js` where driver finished before all tests completed.
|
||||
|
||||
## unversioned wasteland
|
||||
|
||||
See the git history for what happened before.
|
||||
90
node_modules/redis/diff_multi_bench_output.js
generated
vendored
Normal file
90
node_modules/redis/diff_multi_bench_output.js
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
var colors = require('colors'),
|
||||
fs = require('fs'),
|
||||
_ = require('underscore'),
|
||||
metrics = require('metrics'),
|
||||
|
||||
// `node diff_multi_bench_output.js before.txt after.txt`
|
||||
before = process.argv[2],
|
||||
after = process.argv[3];
|
||||
|
||||
if (!before || !after) {
|
||||
console.log('Please supply two file arguments:');
|
||||
var n = __filename;
|
||||
n = n.substring(n.lastIndexOf('/', n.length));
|
||||
console.log(' ./' + n + ' multiBenchBefore.txt multiBenchAfter.txt');
|
||||
console.log('To generate multiBenchBefore.txt, run');
|
||||
console.log(' node multi_bench.js > multiBenchBefore.txt');
|
||||
console.log('Thank you for benchmarking responsibly.');
|
||||
return;
|
||||
}
|
||||
|
||||
var before_lines = fs.readFileSync(before, 'utf8').split('\n'),
|
||||
after_lines = fs.readFileSync(after, 'utf8').split('\n');
|
||||
|
||||
console.log('Comparing before,', before.green, '(', before_lines.length,
|
||||
'lines)', 'to after,', after.green, '(', after_lines.length, 'lines)');
|
||||
|
||||
var total_ops = new metrics.Histogram.createUniformHistogram();
|
||||
|
||||
before_lines.forEach(function(b, i) {
|
||||
var a = after_lines[i];
|
||||
if (!a || !b || !b.trim() || !a.trim()) {
|
||||
// console.log('#ignored#', '>'+a+'<', '>'+b+'<');
|
||||
return;
|
||||
}
|
||||
|
||||
b_words = b.split(' ').filter(is_whitespace);
|
||||
a_words = a.split(' ').filter(is_whitespace);
|
||||
|
||||
var ops =
|
||||
[b_words, a_words]
|
||||
.map(function(words) {
|
||||
// console.log(words);
|
||||
return parseInt10(words.slice(-2, -1));
|
||||
}).filter(function(num) {
|
||||
var isNaN = !num && num !== 0;
|
||||
return !isNaN;
|
||||
});
|
||||
if (ops.length != 2) return
|
||||
|
||||
var delta = ops[1] - ops[0];
|
||||
var pct = ((delta / ops[0]) * 100).toPrecision(3);
|
||||
|
||||
total_ops.update(delta);
|
||||
|
||||
delta = humanize_diff(delta);
|
||||
pct = humanize_diff(pct, '%');
|
||||
console.log(
|
||||
// name of test
|
||||
command_name(a_words) == command_name(b_words)
|
||||
? command_name(a_words) + ':'
|
||||
: '404:',
|
||||
// results of test
|
||||
ops.join(' -> '), 'ops/sec (∆', delta, pct, ')');
|
||||
});
|
||||
|
||||
console.log('Mean difference in ops/sec:', humanize_diff(total_ops.mean().toPrecision(6)));
|
||||
|
||||
function is_whitespace(s) {
|
||||
return !!s.trim();
|
||||
}
|
||||
|
||||
function parseInt10(s) {
|
||||
return parseInt(s, 10);
|
||||
}
|
||||
|
||||
// green if greater than 0, red otherwise
|
||||
function humanize_diff(num, unit) {
|
||||
unit = unit || "";
|
||||
if (num > 0) {
|
||||
return ('+' + num + unit).green;
|
||||
}
|
||||
return ('' + num + unit).red;
|
||||
}
|
||||
|
||||
function command_name(words) {
|
||||
var line = words.join(' ');
|
||||
return line.substr(0, line.indexOf(','));
|
||||
}
|
||||
5
node_modules/redis/examples/auth.js
generated
vendored
Normal file
5
node_modules/redis/examples/auth.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
// This command is magical. Client stashes the password and will issue on every connect.
|
||||
client.auth("somepass");
|
||||
33
node_modules/redis/examples/backpressure_drain.js
generated
vendored
Normal file
33
node_modules/redis/examples/backpressure_drain.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
var redis = require("../index"),
|
||||
client = redis.createClient(null, null, {
|
||||
command_queue_high_water: 5,
|
||||
command_queue_low_water: 1
|
||||
}),
|
||||
remaining_ops = 100000, paused = false;
|
||||
|
||||
function op() {
|
||||
if (remaining_ops <= 0) {
|
||||
console.error("Finished.");
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
remaining_ops--;
|
||||
if (client.hset("test hash", "val " + remaining_ops, remaining_ops) === false) {
|
||||
console.log("Pausing at " + remaining_ops);
|
||||
paused = true;
|
||||
} else {
|
||||
process.nextTick(op);
|
||||
}
|
||||
}
|
||||
|
||||
client.on("drain", function () {
|
||||
if (paused) {
|
||||
console.log("Resuming at " + remaining_ops);
|
||||
paused = false;
|
||||
process.nextTick(op);
|
||||
} else {
|
||||
console.log("Got drain while not paused at " + remaining_ops);
|
||||
}
|
||||
});
|
||||
|
||||
op();
|
||||
14
node_modules/redis/examples/eval.js
generated
vendored
Normal file
14
node_modules/redis/examples/eval.js
generated
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
var redis = require("../index"),
|
||||
client = redis.createClient();
|
||||
|
||||
redis.debug_mode = true;
|
||||
|
||||
client.eval("return 100.5", 0, function (err, res) {
|
||||
console.dir(err);
|
||||
console.dir(res);
|
||||
});
|
||||
|
||||
client.eval([ "return 100.5", 0 ], function (err, res) {
|
||||
console.dir(err);
|
||||
console.dir(res);
|
||||
});
|
||||
24
node_modules/redis/examples/extend.js
generated
vendored
Normal file
24
node_modules/redis/examples/extend.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
// Extend the RedisClient prototype to add a custom method
|
||||
// This one converts the results from "INFO" into a JavaScript Object
|
||||
|
||||
redis.RedisClient.prototype.parse_info = function (callback) {
|
||||
this.info(function (err, res) {
|
||||
var lines = res.toString().split("\r\n").sort();
|
||||
var obj = {};
|
||||
lines.forEach(function (line) {
|
||||
var parts = line.split(':');
|
||||
if (parts[1]) {
|
||||
obj[parts[0]] = parts[1];
|
||||
}
|
||||
});
|
||||
callback(obj)
|
||||
});
|
||||
};
|
||||
|
||||
client.parse_info(function (info) {
|
||||
console.dir(info);
|
||||
client.quit();
|
||||
});
|
||||
32
node_modules/redis/examples/file.js
generated
vendored
Normal file
32
node_modules/redis/examples/file.js
generated
vendored
Normal file
@@ -0,0 +1,32 @@
|
||||
// Read a file from disk, store it in Redis, then read it back from Redis.
|
||||
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(),
|
||||
fs = require("fs"),
|
||||
filename = "kids_in_cart.jpg";
|
||||
|
||||
// Get the file I use for testing like this:
|
||||
// curl http://ranney.com/kids_in_cart.jpg -o kids_in_cart.jpg
|
||||
// or just use your own file.
|
||||
|
||||
// Read a file from fs, store it in Redis, get it back from Redis, write it back to fs.
|
||||
fs.readFile(filename, function (err, data) {
|
||||
if (err) throw err
|
||||
console.log("Read " + data.length + " bytes from filesystem.");
|
||||
|
||||
client.set(filename, data, redis.print); // set entire file
|
||||
client.get(filename, function (err, reply) { // get entire file
|
||||
if (err) {
|
||||
console.log("Get error: " + err);
|
||||
} else {
|
||||
fs.writeFile("duplicate_" + filename, reply, function (err) {
|
||||
if (err) {
|
||||
console.log("Error on write: " + err)
|
||||
} else {
|
||||
console.log("File written.");
|
||||
}
|
||||
client.end();
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
5
node_modules/redis/examples/mget.js
generated
vendored
Normal file
5
node_modules/redis/examples/mget.js
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
||||
var client = require("redis").createClient();
|
||||
|
||||
client.mget(["sessions started", "sessions started", "foo"], function (err, res) {
|
||||
console.dir(res);
|
||||
});
|
||||
10
node_modules/redis/examples/monitor.js
generated
vendored
Normal file
10
node_modules/redis/examples/monitor.js
generated
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
var client = require("../index").createClient(),
|
||||
util = require("util");
|
||||
|
||||
client.monitor(function (err, res) {
|
||||
console.log("Entering monitoring mode.");
|
||||
});
|
||||
|
||||
client.on("monitor", function (time, args) {
|
||||
console.log(time + ": " + util.inspect(args));
|
||||
});
|
||||
46
node_modules/redis/examples/multi.js
generated
vendored
Normal file
46
node_modules/redis/examples/multi.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(), set_size = 20;
|
||||
|
||||
client.sadd("bigset", "a member");
|
||||
client.sadd("bigset", "another member");
|
||||
|
||||
while (set_size > 0) {
|
||||
client.sadd("bigset", "member " + set_size);
|
||||
set_size -= 1;
|
||||
}
|
||||
|
||||
// multi chain with an individual callback
|
||||
client.multi()
|
||||
.scard("bigset")
|
||||
.smembers("bigset")
|
||||
.keys("*", function (err, replies) {
|
||||
client.mget(replies, redis.print);
|
||||
})
|
||||
.dbsize()
|
||||
.exec(function (err, replies) {
|
||||
console.log("MULTI got " + replies.length + " replies");
|
||||
replies.forEach(function (reply, index) {
|
||||
console.log("Reply " + index + ": " + reply.toString());
|
||||
});
|
||||
});
|
||||
|
||||
client.mset("incr thing", 100, "incr other thing", 1, redis.print);
|
||||
|
||||
// start a separate multi command queue
|
||||
var multi = client.multi();
|
||||
multi.incr("incr thing", redis.print);
|
||||
multi.incr("incr other thing", redis.print);
|
||||
|
||||
// runs immediately
|
||||
client.get("incr thing", redis.print); // 100
|
||||
|
||||
// drains multi queue and runs atomically
|
||||
multi.exec(function (err, replies) {
|
||||
console.log(replies); // 101, 2
|
||||
});
|
||||
|
||||
// you can re-run the same transaction if you like
|
||||
multi.exec(function (err, replies) {
|
||||
console.log(replies); // 102, 3
|
||||
client.quit();
|
||||
});
|
||||
29
node_modules/redis/examples/multi2.js
generated
vendored
Normal file
29
node_modules/redis/examples/multi2.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient(), multi;
|
||||
|
||||
// start a separate command queue for multi
|
||||
multi = client.multi();
|
||||
multi.incr("incr thing", redis.print);
|
||||
multi.incr("incr other thing", redis.print);
|
||||
|
||||
// runs immediately
|
||||
client.mset("incr thing", 100, "incr other thing", 1, redis.print);
|
||||
|
||||
// drains multi queue and runs atomically
|
||||
multi.exec(function (err, replies) {
|
||||
console.log(replies); // 101, 2
|
||||
});
|
||||
|
||||
// you can re-run the same transaction if you like
|
||||
multi.exec(function (err, replies) {
|
||||
console.log(replies); // 102, 3
|
||||
client.quit();
|
||||
});
|
||||
|
||||
client.multi([
|
||||
["mget", "multifoo", "multibar", redis.print],
|
||||
["incr", "multifoo"],
|
||||
["incr", "multibar"]
|
||||
]).exec(function (err, replies) {
|
||||
console.log(replies.toString());
|
||||
});
|
||||
33
node_modules/redis/examples/psubscribe.js
generated
vendored
Normal file
33
node_modules/redis/examples/psubscribe.js
generated
vendored
Normal file
@@ -0,0 +1,33 @@
|
||||
var redis = require("redis"),
|
||||
client1 = redis.createClient(),
|
||||
client2 = redis.createClient(),
|
||||
client3 = redis.createClient(),
|
||||
client4 = redis.createClient(),
|
||||
msg_count = 0;
|
||||
|
||||
redis.debug_mode = false;
|
||||
|
||||
client1.on("psubscribe", function (pattern, count) {
|
||||
console.log("client1 psubscribed to " + pattern + ", " + count + " total subscriptions");
|
||||
client2.publish("channeltwo", "Me!");
|
||||
client3.publish("channelthree", "Me too!");
|
||||
client4.publish("channelfour", "And me too!");
|
||||
});
|
||||
|
||||
client1.on("punsubscribe", function (pattern, count) {
|
||||
console.log("client1 punsubscribed from " + pattern + ", " + count + " total subscriptions");
|
||||
client4.end();
|
||||
client3.end();
|
||||
client2.end();
|
||||
client1.end();
|
||||
});
|
||||
|
||||
client1.on("pmessage", function (pattern, channel, message) {
|
||||
console.log("("+ pattern +")" + " client1 received message on " + channel + ": " + message);
|
||||
msg_count += 1;
|
||||
if (msg_count === 3) {
|
||||
client1.punsubscribe();
|
||||
}
|
||||
});
|
||||
|
||||
client1.psubscribe("channel*");
|
||||
41
node_modules/redis/examples/pub_sub.js
generated
vendored
Normal file
41
node_modules/redis/examples/pub_sub.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
var redis = require("redis"),
|
||||
client1 = redis.createClient(), msg_count = 0,
|
||||
client2 = redis.createClient();
|
||||
|
||||
redis.debug_mode = false;
|
||||
|
||||
// Most clients probably don't do much on "subscribe". This example uses it to coordinate things within one program.
|
||||
client1.on("subscribe", function (channel, count) {
|
||||
console.log("client1 subscribed to " + channel + ", " + count + " total subscriptions");
|
||||
if (count === 2) {
|
||||
client2.publish("a nice channel", "I am sending a message.");
|
||||
client2.publish("another one", "I am sending a second message.");
|
||||
client2.publish("a nice channel", "I am sending my last message.");
|
||||
}
|
||||
});
|
||||
|
||||
client1.on("unsubscribe", function (channel, count) {
|
||||
console.log("client1 unsubscribed from " + channel + ", " + count + " total subscriptions");
|
||||
if (count === 0) {
|
||||
client2.end();
|
||||
client1.end();
|
||||
}
|
||||
});
|
||||
|
||||
client1.on("message", function (channel, message) {
|
||||
console.log("client1 channel " + channel + ": " + message);
|
||||
msg_count += 1;
|
||||
if (msg_count === 3) {
|
||||
client1.unsubscribe();
|
||||
}
|
||||
});
|
||||
|
||||
client1.on("ready", function () {
|
||||
// if you need auth, do it here
|
||||
client1.incr("did a thing");
|
||||
client1.subscribe("a nice channel", "another one");
|
||||
});
|
||||
|
||||
client2.on("ready", function () {
|
||||
// if you need auth, do it here
|
||||
});
|
||||
24
node_modules/redis/examples/simple.js
generated
vendored
Normal file
24
node_modules/redis/examples/simple.js
generated
vendored
Normal file
@@ -0,0 +1,24 @@
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
client.on("error", function (err) {
|
||||
console.log("error event - " + client.host + ":" + client.port + " - " + err);
|
||||
});
|
||||
|
||||
client.set("string key", "string val", redis.print);
|
||||
client.hset("hash key", "hashtest 1", "some value", redis.print);
|
||||
client.hset(["hash key", "hashtest 2", "some other value"], redis.print);
|
||||
client.hkeys("hash key", function (err, replies) {
|
||||
if (err) {
|
||||
return console.error("error response - " + err);
|
||||
}
|
||||
|
||||
console.log(replies.length + " replies:");
|
||||
replies.forEach(function (reply, i) {
|
||||
console.log(" " + i + ": " + reply);
|
||||
});
|
||||
});
|
||||
|
||||
client.quit(function (err, res) {
|
||||
console.log("Exiting from quit command.");
|
||||
});
|
||||
17
node_modules/redis/examples/sort.js
generated
vendored
Normal file
17
node_modules/redis/examples/sort.js
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient();
|
||||
|
||||
client.sadd("mylist", 1);
|
||||
client.sadd("mylist", 2);
|
||||
client.sadd("mylist", 3);
|
||||
|
||||
client.set("weight_1", 5);
|
||||
client.set("weight_2", 500);
|
||||
client.set("weight_3", 1);
|
||||
|
||||
client.set("object_1", "foo");
|
||||
client.set("object_2", "bar");
|
||||
client.set("object_3", "qux");
|
||||
|
||||
client.sort("mylist", "by", "weight_*", "get", "object_*", redis.print);
|
||||
// Prints Reply: qux,foo,bar
|
||||
15
node_modules/redis/examples/subqueries.js
generated
vendored
Normal file
15
node_modules/redis/examples/subqueries.js
generated
vendored
Normal file
@@ -0,0 +1,15 @@
|
||||
// Sending commands in response to other commands.
|
||||
// This example runs "type" against every key in the database
|
||||
//
|
||||
var client = require("redis").createClient();
|
||||
|
||||
client.keys("*", function (err, keys) {
|
||||
keys.forEach(function (key, pos) {
|
||||
client.type(key, function (err, keytype) {
|
||||
console.log(key + " is " + keytype);
|
||||
if (pos === (keys.length - 1)) {
|
||||
client.quit();
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
19
node_modules/redis/examples/subquery.js
generated
vendored
Normal file
19
node_modules/redis/examples/subquery.js
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
var client = require("redis").createClient();
|
||||
|
||||
function print_results(obj) {
|
||||
console.dir(obj);
|
||||
}
|
||||
|
||||
// build a map of all keys and their types
|
||||
client.keys("*", function (err, all_keys) {
|
||||
var key_types = {};
|
||||
|
||||
all_keys.forEach(function (key, pos) { // use second arg of forEach to get pos
|
||||
client.type(key, function (err, type) {
|
||||
key_types[key] = type;
|
||||
if (pos === all_keys.length - 1) { // callbacks all run in order
|
||||
print_results(key_types);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
29
node_modules/redis/examples/unix_socket.js
generated
vendored
Normal file
29
node_modules/redis/examples/unix_socket.js
generated
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
var redis = require("redis"),
|
||||
client = redis.createClient("/tmp/redis.sock"),
|
||||
profiler = require("v8-profiler");
|
||||
|
||||
client.on("connect", function () {
|
||||
console.log("Got Unix socket connection.")
|
||||
});
|
||||
|
||||
client.on("error", function (err) {
|
||||
console.log(err.message);
|
||||
});
|
||||
|
||||
client.set("space chars", "space value");
|
||||
|
||||
setInterval(function () {
|
||||
client.get("space chars");
|
||||
}, 100);
|
||||
|
||||
function done() {
|
||||
client.info(function (err, reply) {
|
||||
console.log(reply.toString());
|
||||
client.quit();
|
||||
});
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
console.log("Taking snapshot.");
|
||||
var snap = profiler.takeSnapshot();
|
||||
}, 5000);
|
||||
31
node_modules/redis/examples/web_server.js
generated
vendored
Normal file
31
node_modules/redis/examples/web_server.js
generated
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
// A simple web server that generates dyanmic content based on responses from Redis
|
||||
|
||||
var http = require("http"), server,
|
||||
redis_client = require("redis").createClient();
|
||||
|
||||
server = http.createServer(function (request, response) {
|
||||
response.writeHead(200, {
|
||||
"Content-Type": "text/plain"
|
||||
});
|
||||
|
||||
var redis_info, total_requests;
|
||||
|
||||
redis_client.info(function (err, reply) {
|
||||
redis_info = reply; // stash response in outer scope
|
||||
});
|
||||
redis_client.incr("requests", function (err, reply) {
|
||||
total_requests = reply; // stash response in outer scope
|
||||
});
|
||||
redis_client.hincrby("ip", request.connection.remoteAddress, 1);
|
||||
redis_client.hgetall("ip", function (err, reply) {
|
||||
// This is the last reply, so all of the previous replies must have completed already
|
||||
response.write("This page was generated after talking to redis.\n\n" +
|
||||
"Redis info:\n" + redis_info + "\n" +
|
||||
"Total requests: " + total_requests + "\n\n" +
|
||||
"IP count: \n");
|
||||
Object.keys(reply).forEach(function (ip) {
|
||||
response.write(" " + ip + ": " + reply[ip] + "\n");
|
||||
});
|
||||
response.end();
|
||||
});
|
||||
}).listen(80);
|
||||
39
node_modules/redis/generate_commands.js
generated
vendored
Normal file
39
node_modules/redis/generate_commands.js
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
var http = require("http"),
|
||||
fs = require("fs");
|
||||
|
||||
function prettyCurrentTime() {
|
||||
var date = new Date();
|
||||
return date.toLocaleString();
|
||||
}
|
||||
|
||||
function write_file(commands, path) {
|
||||
var file_contents, out_commands;
|
||||
|
||||
console.log("Writing " + Object.keys(commands).length + " commands to " + path);
|
||||
|
||||
file_contents = "// This file was generated by ./generate_commands.js on " + prettyCurrentTime() + "\n";
|
||||
|
||||
out_commands = Object.keys(commands).map(function (key) {
|
||||
return key.toLowerCase();
|
||||
});
|
||||
|
||||
file_contents += "module.exports = " + JSON.stringify(out_commands, null, " ") + ";\n";
|
||||
|
||||
fs.writeFile(path, file_contents);
|
||||
}
|
||||
|
||||
http.get({host: "redis.io", path: "/commands.json"}, function (res) {
|
||||
var body = "";
|
||||
|
||||
console.log("Response from redis.io/commands.json: " + res.statusCode);
|
||||
|
||||
res.on('data', function (chunk) {
|
||||
body += chunk;
|
||||
});
|
||||
|
||||
res.on('end', function () {
|
||||
write_file(JSON.parse(body), "lib/commands.js");
|
||||
});
|
||||
}).on('error', function (e) {
|
||||
console.log("Error fetching command list from redis.io: " + e.message);
|
||||
});
|
||||
1144
node_modules/redis/index.js
generated
vendored
Normal file
1144
node_modules/redis/index.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
149
node_modules/redis/lib/commands.js
generated
vendored
Normal file
149
node_modules/redis/lib/commands.js
generated
vendored
Normal file
@@ -0,0 +1,149 @@
|
||||
// This file was generated by ./generate_commands.js on Sun Feb 17 2013 19:04:47 GMT-0500 (EST)
|
||||
module.exports = [
|
||||
"append",
|
||||
"auth",
|
||||
"bgrewriteaof",
|
||||
"bgsave",
|
||||
"bitcount",
|
||||
"bitop",
|
||||
"blpop",
|
||||
"brpop",
|
||||
"brpoplpush",
|
||||
"client kill",
|
||||
"client list",
|
||||
"client getname",
|
||||
"client setname",
|
||||
"config get",
|
||||
"config set",
|
||||
"config resetstat",
|
||||
"dbsize",
|
||||
"debug object",
|
||||
"debug segfault",
|
||||
"decr",
|
||||
"decrby",
|
||||
"del",
|
||||
"discard",
|
||||
"dump",
|
||||
"echo",
|
||||
"eval",
|
||||
"evalsha",
|
||||
"exec",
|
||||
"exists",
|
||||
"expire",
|
||||
"expireat",
|
||||
"flushall",
|
||||
"flushdb",
|
||||
"get",
|
||||
"getbit",
|
||||
"getrange",
|
||||
"getset",
|
||||
"hdel",
|
||||
"hexists",
|
||||
"hget",
|
||||
"hgetall",
|
||||
"hincrby",
|
||||
"hincrbyfloat",
|
||||
"hkeys",
|
||||
"hlen",
|
||||
"hmget",
|
||||
"hmset",
|
||||
"hset",
|
||||
"hsetnx",
|
||||
"hvals",
|
||||
"incr",
|
||||
"incrby",
|
||||
"incrbyfloat",
|
||||
"info",
|
||||
"keys",
|
||||
"lastsave",
|
||||
"lindex",
|
||||
"linsert",
|
||||
"llen",
|
||||
"lpop",
|
||||
"lpush",
|
||||
"lpushx",
|
||||
"lrange",
|
||||
"lrem",
|
||||
"lset",
|
||||
"ltrim",
|
||||
"mget",
|
||||
"migrate",
|
||||
"monitor",
|
||||
"move",
|
||||
"mset",
|
||||
"msetnx",
|
||||
"multi",
|
||||
"object",
|
||||
"persist",
|
||||
"pexpire",
|
||||
"pexpireat",
|
||||
"ping",
|
||||
"psetex",
|
||||
"psubscribe",
|
||||
"pttl",
|
||||
"publish",
|
||||
"punsubscribe",
|
||||
"quit",
|
||||
"randomkey",
|
||||
"rename",
|
||||
"renamenx",
|
||||
"restore",
|
||||
"rpop",
|
||||
"rpoplpush",
|
||||
"rpush",
|
||||
"rpushx",
|
||||
"sadd",
|
||||
"save",
|
||||
"scard",
|
||||
"script exists",
|
||||
"script flush",
|
||||
"script kill",
|
||||
"script load",
|
||||
"sdiff",
|
||||
"sdiffstore",
|
||||
"select",
|
||||
"set",
|
||||
"setbit",
|
||||
"setex",
|
||||
"setnx",
|
||||
"setrange",
|
||||
"shutdown",
|
||||
"sinter",
|
||||
"sinterstore",
|
||||
"sismember",
|
||||
"slaveof",
|
||||
"slowlog",
|
||||
"smembers",
|
||||
"smove",
|
||||
"sort",
|
||||
"spop",
|
||||
"srandmember",
|
||||
"srem",
|
||||
"strlen",
|
||||
"subscribe",
|
||||
"sunion",
|
||||
"sunionstore",
|
||||
"sync",
|
||||
"time",
|
||||
"ttl",
|
||||
"type",
|
||||
"unsubscribe",
|
||||
"unwatch",
|
||||
"watch",
|
||||
"zadd",
|
||||
"zcard",
|
||||
"zcount",
|
||||
"zincrby",
|
||||
"zinterstore",
|
||||
"zrange",
|
||||
"zrangebyscore",
|
||||
"zrank",
|
||||
"zrem",
|
||||
"zremrangebyrank",
|
||||
"zremrangebyscore",
|
||||
"zrevrange",
|
||||
"zrevrangebyscore",
|
||||
"zrevrank",
|
||||
"zscore",
|
||||
"zunionstore"
|
||||
];
|
||||
46
node_modules/redis/lib/parser/hiredis.js
generated
vendored
Normal file
46
node_modules/redis/lib/parser/hiredis.js
generated
vendored
Normal file
@@ -0,0 +1,46 @@
|
||||
var events = require("events"),
|
||||
util = require("../util"),
|
||||
hiredis = require("hiredis");
|
||||
|
||||
exports.debug_mode = false;
|
||||
exports.name = "hiredis";
|
||||
|
||||
function HiredisReplyParser(options) {
|
||||
this.name = exports.name;
|
||||
this.options = options || {};
|
||||
this.reset();
|
||||
events.EventEmitter.call(this);
|
||||
}
|
||||
|
||||
util.inherits(HiredisReplyParser, events.EventEmitter);
|
||||
|
||||
exports.Parser = HiredisReplyParser;
|
||||
|
||||
HiredisReplyParser.prototype.reset = function () {
|
||||
this.reader = new hiredis.Reader({
|
||||
return_buffers: this.options.return_buffers || false
|
||||
});
|
||||
};
|
||||
|
||||
HiredisReplyParser.prototype.execute = function (data) {
|
||||
var reply;
|
||||
this.reader.feed(data);
|
||||
while (true) {
|
||||
try {
|
||||
reply = this.reader.get();
|
||||
} catch (err) {
|
||||
this.emit("error", err);
|
||||
break;
|
||||
}
|
||||
|
||||
if (reply === undefined) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (reply && reply.constructor === Error) {
|
||||
this.emit("reply error", reply);
|
||||
} else {
|
||||
this.emit("reply", reply);
|
||||
}
|
||||
}
|
||||
};
|
||||
301
node_modules/redis/lib/parser/javascript.js
generated
vendored
Normal file
301
node_modules/redis/lib/parser/javascript.js
generated
vendored
Normal file
@@ -0,0 +1,301 @@
|
||||
var events = require("events"),
|
||||
util = require("../util");
|
||||
|
||||
function Packet(type, size) {
|
||||
this.type = type;
|
||||
this.size = +size;
|
||||
}
|
||||
|
||||
exports.name = "javascript";
|
||||
exports.debug_mode = false;
|
||||
|
||||
function ReplyParser(options) {
|
||||
this.name = exports.name;
|
||||
this.options = options || { };
|
||||
|
||||
this._buffer = null;
|
||||
this._offset = 0;
|
||||
this._encoding = "utf-8";
|
||||
this._debug_mode = options.debug_mode;
|
||||
this._reply_type = null;
|
||||
}
|
||||
|
||||
util.inherits(ReplyParser, events.EventEmitter);
|
||||
|
||||
exports.Parser = ReplyParser;
|
||||
|
||||
function IncompleteReadBuffer(message) {
|
||||
this.name = "IncompleteReadBuffer";
|
||||
this.message = message;
|
||||
}
|
||||
util.inherits(IncompleteReadBuffer, Error);
|
||||
|
||||
// Buffer.toString() is quite slow for small strings
|
||||
function small_toString(buf, start, end) {
|
||||
var tmp = "", i;
|
||||
|
||||
for (i = start; i < end; i++) {
|
||||
tmp += String.fromCharCode(buf[i]);
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
ReplyParser.prototype._parseResult = function (type) {
|
||||
var start, end, offset, packetHeader;
|
||||
|
||||
if (type === 43 || type === 45) { // + or -
|
||||
// up to the delimiter
|
||||
end = this._packetEndOffset() - 1;
|
||||
start = this._offset;
|
||||
|
||||
// include the delimiter
|
||||
this._offset = end + 2;
|
||||
|
||||
if (end > this._buffer.length) {
|
||||
this._offset = start;
|
||||
throw new IncompleteReadBuffer("Wait for more data.");
|
||||
}
|
||||
|
||||
if (this.options.return_buffers) {
|
||||
return this._buffer.slice(start, end);
|
||||
} else {
|
||||
if (end - start < 65536) { // completely arbitrary
|
||||
return small_toString(this._buffer, start, end);
|
||||
} else {
|
||||
return this._buffer.toString(this._encoding, start, end);
|
||||
}
|
||||
}
|
||||
} else if (type === 58) { // :
|
||||
// up to the delimiter
|
||||
end = this._packetEndOffset() - 1;
|
||||
start = this._offset;
|
||||
|
||||
// include the delimiter
|
||||
this._offset = end + 2;
|
||||
|
||||
if (end > this._buffer.length) {
|
||||
this._offset = start;
|
||||
throw new IncompleteReadBuffer("Wait for more data.");
|
||||
}
|
||||
|
||||
if (this.options.return_buffers) {
|
||||
return this._buffer.slice(start, end);
|
||||
}
|
||||
|
||||
// return the coerced numeric value
|
||||
return +small_toString(this._buffer, start, end);
|
||||
} else if (type === 36) { // $
|
||||
// set a rewind point, as the packet could be larger than the
|
||||
// buffer in memory
|
||||
offset = this._offset - 1;
|
||||
|
||||
packetHeader = new Packet(type, this.parseHeader());
|
||||
|
||||
// packets with a size of -1 are considered null
|
||||
if (packetHeader.size === -1) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
end = this._offset + packetHeader.size;
|
||||
start = this._offset;
|
||||
|
||||
// set the offset to after the delimiter
|
||||
this._offset = end + 2;
|
||||
|
||||
if (end > this._buffer.length) {
|
||||
this._offset = offset;
|
||||
throw new IncompleteReadBuffer("Wait for more data.");
|
||||
}
|
||||
|
||||
if (this.options.return_buffers) {
|
||||
return this._buffer.slice(start, end);
|
||||
} else {
|
||||
return this._buffer.toString(this._encoding, start, end);
|
||||
}
|
||||
} else if (type === 42) { // *
|
||||
offset = this._offset;
|
||||
packetHeader = new Packet(type, this.parseHeader());
|
||||
|
||||
if (packetHeader.size < 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (packetHeader.size > this._bytesRemaining()) {
|
||||
this._offset = offset - 1;
|
||||
throw new IncompleteReadBuffer("Wait for more data.");
|
||||
}
|
||||
|
||||
var reply = [ ];
|
||||
var ntype, i, res;
|
||||
|
||||
offset = this._offset - 1;
|
||||
|
||||
for (i = 0; i < packetHeader.size; i++) {
|
||||
ntype = this._buffer[this._offset++];
|
||||
|
||||
if (this._offset > this._buffer.length) {
|
||||
throw new IncompleteReadBuffer("Wait for more data.");
|
||||
}
|
||||
res = this._parseResult(ntype);
|
||||
if (res === undefined) {
|
||||
res = null;
|
||||
}
|
||||
reply.push(res);
|
||||
}
|
||||
|
||||
return reply;
|
||||
}
|
||||
};
|
||||
|
||||
ReplyParser.prototype.execute = function (buffer) {
|
||||
this.append(buffer);
|
||||
|
||||
var type, ret, offset;
|
||||
|
||||
while (true) {
|
||||
offset = this._offset;
|
||||
try {
|
||||
// at least 4 bytes: :1\r\n
|
||||
if (this._bytesRemaining() < 4) {
|
||||
break;
|
||||
}
|
||||
|
||||
type = this._buffer[this._offset++];
|
||||
|
||||
if (type === 43) { // +
|
||||
ret = this._parseResult(type);
|
||||
|
||||
if (ret === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.send_reply(ret);
|
||||
} else if (type === 45) { // -
|
||||
ret = this._parseResult(type);
|
||||
|
||||
if (ret === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.send_error(ret);
|
||||
} else if (type === 58) { // :
|
||||
ret = this._parseResult(type);
|
||||
|
||||
if (ret === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
this.send_reply(ret);
|
||||
} else if (type === 36) { // $
|
||||
ret = this._parseResult(type);
|
||||
|
||||
if (ret === null) {
|
||||
break;
|
||||
}
|
||||
|
||||
// check the state for what is the result of
|
||||
// a -1, set it back up for a null reply
|
||||
if (ret === undefined) {
|
||||
ret = null;
|
||||
}
|
||||
|
||||
this.send_reply(ret);
|
||||
} else if (type === 42) { // *
|
||||
// set a rewind point. if a failure occurs,
|
||||
// wait for the next execute()/append() and try again
|
||||
offset = this._offset - 1;
|
||||
|
||||
ret = this._parseResult(type);
|
||||
|
||||
this.send_reply(ret);
|
||||
}
|
||||
} catch (err) {
|
||||
// catch the error (not enough data), rewind, and wait
|
||||
// for the next packet to appear
|
||||
if (! (err instanceof IncompleteReadBuffer)) {
|
||||
throw err;
|
||||
}
|
||||
this._offset = offset;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ReplyParser.prototype.append = function (newBuffer) {
|
||||
if (!newBuffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// first run
|
||||
if (this._buffer === null) {
|
||||
this._buffer = newBuffer;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// out of data
|
||||
if (this._offset >= this._buffer.length) {
|
||||
this._buffer = newBuffer;
|
||||
this._offset = 0;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// very large packet
|
||||
// check for concat, if we have it, use it
|
||||
if (Buffer.concat !== undefined) {
|
||||
this._buffer = Buffer.concat([this._buffer.slice(this._offset), newBuffer]);
|
||||
} else {
|
||||
var remaining = this._bytesRemaining(),
|
||||
newLength = remaining + newBuffer.length,
|
||||
tmpBuffer = new Buffer(newLength);
|
||||
|
||||
this._buffer.copy(tmpBuffer, 0, this._offset);
|
||||
newBuffer.copy(tmpBuffer, remaining, 0);
|
||||
|
||||
this._buffer = tmpBuffer;
|
||||
}
|
||||
|
||||
this._offset = 0;
|
||||
};
|
||||
|
||||
ReplyParser.prototype.parseHeader = function () {
|
||||
var end = this._packetEndOffset(),
|
||||
value = small_toString(this._buffer, this._offset, end - 1);
|
||||
|
||||
this._offset = end + 1;
|
||||
|
||||
return value;
|
||||
};
|
||||
|
||||
ReplyParser.prototype._packetEndOffset = function () {
|
||||
var offset = this._offset;
|
||||
|
||||
while (this._buffer[offset] !== 0x0d && this._buffer[offset + 1] !== 0x0a) {
|
||||
offset++;
|
||||
|
||||
if (offset >= this._buffer.length) {
|
||||
throw new IncompleteReadBuffer("didn't see LF after NL reading multi bulk count (" + offset + " => " + this._buffer.length + ", " + this._offset + ")");
|
||||
}
|
||||
}
|
||||
|
||||
offset++;
|
||||
return offset;
|
||||
};
|
||||
|
||||
ReplyParser.prototype._bytesRemaining = function () {
|
||||
return (this._buffer.length - this._offset) < 0 ? 0 : (this._buffer.length - this._offset);
|
||||
};
|
||||
|
||||
ReplyParser.prototype.parser_error = function (message) {
|
||||
this.emit("error", message);
|
||||
};
|
||||
|
||||
ReplyParser.prototype.send_error = function (reply) {
|
||||
this.emit("reply error", reply);
|
||||
};
|
||||
|
||||
ReplyParser.prototype.send_reply = function (reply) {
|
||||
this.emit("reply", reply);
|
||||
};
|
||||
59
node_modules/redis/lib/queue.js
generated
vendored
Normal file
59
node_modules/redis/lib/queue.js
generated
vendored
Normal file
@@ -0,0 +1,59 @@
|
||||
// Queue class adapted from Tim Caswell's pattern library
|
||||
// http://github.com/creationix/pattern/blob/master/lib/pattern/queue.js
|
||||
|
||||
function Queue() {
|
||||
this.tail = [];
|
||||
this.head = [];
|
||||
this.offset = 0;
|
||||
}
|
||||
|
||||
Queue.prototype.shift = function () {
|
||||
if (this.offset === this.head.length) {
|
||||
var tmp = this.head;
|
||||
tmp.length = 0;
|
||||
this.head = this.tail;
|
||||
this.tail = tmp;
|
||||
this.offset = 0;
|
||||
if (this.head.length === 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
return this.head[this.offset++]; // sorry, JSLint
|
||||
};
|
||||
|
||||
Queue.prototype.push = function (item) {
|
||||
return this.tail.push(item);
|
||||
};
|
||||
|
||||
Queue.prototype.forEach = function (fn, thisv) {
|
||||
var array = this.head.slice(this.offset), i, il;
|
||||
|
||||
array.push.apply(array, this.tail);
|
||||
|
||||
if (thisv) {
|
||||
for (i = 0, il = array.length; i < il; i += 1) {
|
||||
fn.call(thisv, array[i], i, array);
|
||||
}
|
||||
} else {
|
||||
for (i = 0, il = array.length; i < il; i += 1) {
|
||||
fn(array[i], i, array);
|
||||
}
|
||||
}
|
||||
|
||||
return array;
|
||||
};
|
||||
|
||||
Queue.prototype.getLength = function () {
|
||||
return this.head.length - this.offset + this.tail.length;
|
||||
};
|
||||
|
||||
Object.defineProperty(Queue.prototype, "length", {
|
||||
get: function () {
|
||||
return this.getLength();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
if (typeof module !== "undefined" && module.exports) {
|
||||
module.exports = Queue;
|
||||
}
|
||||
12
node_modules/redis/lib/to_array.js
generated
vendored
Normal file
12
node_modules/redis/lib/to_array.js
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
function to_array(args) {
|
||||
var len = args.length,
|
||||
arr = new Array(len), i;
|
||||
|
||||
for (i = 0; i < len; i += 1) {
|
||||
arr[i] = args[i];
|
||||
}
|
||||
|
||||
return arr;
|
||||
}
|
||||
|
||||
module.exports = to_array;
|
||||
11
node_modules/redis/lib/util.js
generated
vendored
Normal file
11
node_modules/redis/lib/util.js
generated
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
// Support for very old versions of node where the module was called "sys". At some point, we should abandon this.
|
||||
|
||||
var util;
|
||||
|
||||
try {
|
||||
util = require("util");
|
||||
} catch (err) {
|
||||
util = require("sys");
|
||||
}
|
||||
|
||||
module.exports = util;
|
||||
222
node_modules/redis/multi_bench.js
generated
vendored
Normal file
222
node_modules/redis/multi_bench.js
generated
vendored
Normal file
@@ -0,0 +1,222 @@
|
||||
var redis = require("./index"),
|
||||
metrics = require("metrics"),
|
||||
num_clients = parseInt(process.argv[2], 10) || 5,
|
||||
num_requests = 20000,
|
||||
tests = [],
|
||||
versions_logged = false,
|
||||
client_options = {
|
||||
return_buffers: false
|
||||
},
|
||||
small_str, large_str, small_buf, large_buf;
|
||||
|
||||
redis.debug_mode = false;
|
||||
|
||||
function lpad(input, len, chr) {
|
||||
var str = input.toString();
|
||||
chr = chr || " ";
|
||||
|
||||
while (str.length < len) {
|
||||
str = chr + str;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
metrics.Histogram.prototype.print_line = function () {
|
||||
var obj = this.printObj();
|
||||
|
||||
return lpad(obj.min, 4) + "/" + lpad(obj.max, 4) + "/" + lpad(obj.mean.toFixed(2), 7) + "/" + lpad(obj.p95.toFixed(2), 7);
|
||||
};
|
||||
|
||||
function Test(args) {
|
||||
this.args = args;
|
||||
|
||||
this.callback = null;
|
||||
this.clients = [];
|
||||
this.clients_ready = 0;
|
||||
this.commands_sent = 0;
|
||||
this.commands_completed = 0;
|
||||
this.max_pipeline = this.args.pipeline || num_requests;
|
||||
this.client_options = args.client_options || client_options;
|
||||
|
||||
this.connect_latency = new metrics.Histogram();
|
||||
this.ready_latency = new metrics.Histogram();
|
||||
this.command_latency = new metrics.Histogram();
|
||||
}
|
||||
|
||||
Test.prototype.run = function (callback) {
|
||||
var i;
|
||||
|
||||
this.callback = callback;
|
||||
|
||||
for (i = 0; i < num_clients ; i++) {
|
||||
this.new_client(i);
|
||||
}
|
||||
};
|
||||
|
||||
Test.prototype.new_client = function (id) {
|
||||
var self = this, new_client;
|
||||
|
||||
new_client = redis.createClient(6379, "127.0.0.1", this.client_options);
|
||||
new_client.create_time = Date.now();
|
||||
|
||||
new_client.on("connect", function () {
|
||||
self.connect_latency.update(Date.now() - new_client.create_time);
|
||||
});
|
||||
|
||||
new_client.on("ready", function () {
|
||||
if (! versions_logged) {
|
||||
console.log("Client count: " + num_clients + ", node version: " + process.versions.node + ", server version: " +
|
||||
new_client.server_info.redis_version + ", parser: " + new_client.reply_parser.name);
|
||||
versions_logged = true;
|
||||
}
|
||||
self.ready_latency.update(Date.now() - new_client.create_time);
|
||||
self.clients_ready++;
|
||||
if (self.clients_ready === self.clients.length) {
|
||||
self.on_clients_ready();
|
||||
}
|
||||
});
|
||||
|
||||
self.clients[id] = new_client;
|
||||
};
|
||||
|
||||
Test.prototype.on_clients_ready = function () {
|
||||
process.stdout.write(lpad(this.args.descr, 13) + ", " + lpad(this.args.pipeline, 5) + "/" + this.clients_ready + " ");
|
||||
this.test_start = Date.now();
|
||||
|
||||
this.fill_pipeline();
|
||||
};
|
||||
|
||||
Test.prototype.fill_pipeline = function () {
|
||||
var pipeline = this.commands_sent - this.commands_completed;
|
||||
|
||||
while (this.commands_sent < num_requests && pipeline < this.max_pipeline) {
|
||||
this.commands_sent++;
|
||||
pipeline++;
|
||||
this.send_next();
|
||||
}
|
||||
|
||||
if (this.commands_completed === num_requests) {
|
||||
this.print_stats();
|
||||
this.stop_clients();
|
||||
}
|
||||
};
|
||||
|
||||
Test.prototype.stop_clients = function () {
|
||||
var self = this;
|
||||
|
||||
this.clients.forEach(function (client, pos) {
|
||||
if (pos === self.clients.length - 1) {
|
||||
client.quit(function (err, res) {
|
||||
self.callback();
|
||||
});
|
||||
} else {
|
||||
client.quit();
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
Test.prototype.send_next = function () {
|
||||
var self = this,
|
||||
cur_client = this.commands_sent % this.clients.length,
|
||||
start = Date.now();
|
||||
|
||||
this.clients[cur_client][this.args.command](this.args.args, function (err, res) {
|
||||
if (err) {
|
||||
throw err;
|
||||
}
|
||||
self.commands_completed++;
|
||||
self.command_latency.update(Date.now() - start);
|
||||
self.fill_pipeline();
|
||||
});
|
||||
};
|
||||
|
||||
Test.prototype.print_stats = function () {
|
||||
var duration = Date.now() - this.test_start;
|
||||
|
||||
console.log("min/max/avg/p95: " + this.command_latency.print_line() + " " + lpad(duration, 6) + "ms total, " +
|
||||
lpad((num_requests / (duration / 1000)).toFixed(2), 8) + " ops/sec");
|
||||
};
|
||||
|
||||
small_str = "1234";
|
||||
small_buf = new Buffer(small_str);
|
||||
large_str = (new Array(4097).join("-"));
|
||||
large_buf = new Buffer(large_str);
|
||||
|
||||
tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 1}));
|
||||
tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 50}));
|
||||
tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 200}));
|
||||
tests.push(new Test({descr: "PING", command: "ping", args: [], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 50}));
|
||||
tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 200}));
|
||||
tests.push(new Test({descr: "SET small str", command: "set", args: ["foo_rand000000000000", small_str], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 50}));
|
||||
tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 200}));
|
||||
tests.push(new Test({descr: "SET small buf", command: "set", args: ["foo_rand000000000000", small_buf], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "GET small str", command: "get", args: ["foo_rand000000000000"], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 1, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 50, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 200, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET small buf", command: "get", args: ["foo_rand000000000000"], pipeline: 20000, client_opts: { return_buffers: true} }));
|
||||
|
||||
tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 50}));
|
||||
tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 200}));
|
||||
tests.push(new Test({descr: "SET large str", command: "set", args: ["foo_rand000000000001", large_str], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 1}));
|
||||
tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 50}));
|
||||
tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 200}));
|
||||
tests.push(new Test({descr: "SET large buf", command: "set", args: ["foo_rand000000000001", large_buf], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "GET large str", command: "get", args: ["foo_rand000000000001"], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 1, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 50, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 200, client_opts: { return_buffers: true} }));
|
||||
tests.push(new Test({descr: "GET large buf", command: "get", args: ["foo_rand000000000001"], pipeline: 20000, client_opts: { return_buffers: true} }));
|
||||
|
||||
tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "INCR", command: "incr", args: ["counter_rand000000000000"], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 1}));
|
||||
tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 50}));
|
||||
tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 200}));
|
||||
tests.push(new Test({descr: "LPUSH", command: "lpush", args: ["mylist", small_str], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "LRANGE 10", command: "lrange", args: ["mylist", "0", "9"], pipeline: 20000}));
|
||||
|
||||
tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 1}));
|
||||
tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 50}));
|
||||
tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 200}));
|
||||
tests.push(new Test({descr: "LRANGE 100", command: "lrange", args: ["mylist", "0", "99"], pipeline: 20000}));
|
||||
|
||||
function next() {
|
||||
var test = tests.shift();
|
||||
if (test) {
|
||||
test.run(function () {
|
||||
next();
|
||||
});
|
||||
} else {
|
||||
console.log("End of tests.");
|
||||
process.exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
next();
|
||||
40
node_modules/redis/package.json
generated
vendored
Normal file
40
node_modules/redis/package.json
generated
vendored
Normal file
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"name": "redis",
|
||||
"version": "0.8.3",
|
||||
"description": "Redis client library",
|
||||
"keywords": [
|
||||
"redis",
|
||||
"database"
|
||||
],
|
||||
"author": {
|
||||
"name": "Matt Ranney",
|
||||
"email": "mjr@ranney.com"
|
||||
},
|
||||
"main": "./index.js",
|
||||
"scripts": {
|
||||
"test": "node ./test.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"metrics": ">=0.1.5",
|
||||
"colors": "~0.6.0-1",
|
||||
"underscore": "~1.4.4"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/mranney/node_redis.git"
|
||||
},
|
||||
"_id": "redis@0.8.3",
|
||||
"dependencies": {},
|
||||
"optionalDependencies": {},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"_engineSupported": true,
|
||||
"_npmVersion": "1.1.4",
|
||||
"_nodeVersion": "v0.6.12",
|
||||
"_defaultsLoaded": true,
|
||||
"dist": {
|
||||
"shasum": "bda57a05e1f0d9a69996dbcdcd6010c8ca1de0c9"
|
||||
},
|
||||
"_from": "redis@0.8.3"
|
||||
}
|
||||
1955
node_modules/redis/test.js
generated
vendored
Normal file
1955
node_modules/redis/test.js
generated
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user