Coder Social home page Coder Social logo

3rd-eden / memcached Goto Github PK

View Code? Open in Web Editor NEW
1.3K 48.0 276.0 726 KB

A fully featured Memcached client build on top of Node.js. Build with scaling in mind so it will support Memcached clusters and consistent hashing.

License: MIT License

JavaScript 99.88% Shell 0.12%

memcached's Introduction

Memcached Build Status

memcached is a fully featured Memcached client for Node.js. memcached is built with scaling, high availability and exceptional performance in mind. We use consistent hashing to store the data across different nodes. Consistent hashing is a scheme that provides a hash table functionality in a way that adding or removing a server node does not significantly change the mapping of the keys to server nodes. The algorithm that is used for consistent hashing is the same as libketama.

There are different ways to handle errors for example, when a server becomes unavailable you can configure the client to see all requests to that server as cache misses until it goes up again. It's also possible to automatically remove the affected server from the consistent hashing algorithm or provide memcached with a failover server that can take the place of the unresponsive server.

When these issues occur the memcached client will emit different events where you can subscribe to containing detailed information about the issues.

The client is configurable on different levels. There's a global configuration that you update so all your Memcached clusters will use the same failure configuration for example, but it's also possible to overwrite these changes per memcached instance.

protocol

As in other databases and message queues, this module uses the ASCII protocol to communicate with the server, which means that you can see what is send over the wire. For debugging this is easier for both the users and the developers however this also means that SASL auth is not supported because it demands the binary protocol.

Installation

npm install memcached

Setting up the client

The constructor of the memcached client take 2 different arguments server locations and options. Syntax:

var Memcached = require('memcached');
var memcached = new Memcached(Server locations, options);

Server locations

The server locations is designed to work with different formats. These formats are all internally parsed to the correct format so our consistent hashing scheme can work with it. You can either use:

  1. String, this only works if you are running a single server instance of Memcached. It's as easy a suppling a string in the following format: hostname:port. For example 192.168.0.102:11211 This would tell the client to connect to host 192.168.0.102 on port number 11211.

  2. Array, if you are running a single server you would only have to supply one item in the array. The array format is particularly useful if you are running a cluster of Memcached servers. This will allow you to spread the keys and load between the different servers. Giving you higher availability when one of your Memcached servers goes down.

  3. Object, when running a cluster of Memcached servers, some servers may allocate different amounts of memory, e.g. 128, 512, and 128mb. While by default all servers are equally important and dispatch consistently the keys between the servers (33/33/33%), it is possible to send more keys in servers having more memory. To do so, define an object whose key represents the server location and whose value represents a server weight, the default weight for a server being 1; so, for instance { '192.168.0.102:11211': 1, '192.168.0.103:11211': 2, '192.168.0.104:11211': 1 } distributes 50% of the keys on server 103, but only 25% on 104 and 25% on 102.

To implement one of the above formats, your constructor would look like this:

var memcached = new Memcached({ '192.168.0.102:11211': 1, '192.168.0.103:11211': 2, '192.168.0.104:11211': 1 });
var memcached = new Memcached([ '192.168.0.102:11211', '192.168.0.103:11211', '192.168.0.104:11211' ]);
var memcached = new Memcached('192.168.0.102:11211');

Options

Memcached accepts two option schemes. The first one inherits of all Memcached server instances while the second one is client specific and overwrites the globals. To define these options, Memcached server uses the same properties:

  • maxKeySize: 250, the maximum key size allowed.
  • maxExpiration: 2592000, the maximum expiration time of keys (in seconds).
  • maxValue: 1048576, the maximum size of a value.
  • poolSize: 10, the maximum size of the connection pool.
  • algorithm: md5, the hashing algorithm used to generate the hashRing values.
  • reconnect: 18000000, the time between reconnection attempts (in milliseconds).
  • timeout: 5000, the time after which Memcached sends a connection timeout (in milliseconds).
  • retries: 5, the number of socket allocation retries per request.
  • failures: 5, the number of failed-attempts to a server before it is regarded as 'dead'.
  • retry: 30000, the time between a server failure and an attempt to set it up back in service.
  • remove: false, if true, authorizes the automatic removal of dead servers from the pool.
  • failOverServers: undefined, an array of server_locations to replace servers that fail and that are removed from the consistent hashing scheme.
  • keyCompression: true, whether to use md5 as hashing scheme when keys exceed maxKeySize.
  • idle: 5000, the idle timeout for the connections.
  • encoding: utf8, encoding of data when socket as a readable stream

Example usage:

var memcached = new Memcached('localhost:11211', {retries:10,retry:10000,remove:true,failOverServers:['192.168.0.103:11211']});

If you wish to configure the options globally:

var Memcached = require('memcached');
// all global configurations should be applied to the .config object of the Client.
Memcached.config.poolSize = 25;

API

Public methods

memcached.touch Touches the given key.

  • key: String The key
  • lifetime: Number After how long should the key expire measured in seconds
  • callback: Function
memcached.touch('key', 10, function (err) { /* stuff */ });

memcached.get Get the value for the given key.

  • key: String, the key
  • callback: Function, the callback.
memcached.get('foo', function (err, data) {
  console.log(data);
});

memcached.gets Get the value and the CAS id.

  • key: String, the key
  • callback: Function, the callback.
memcached.gets('foo', function (err, data) {
  console.log(data.foo);
  console.log(data.cas);

  // Please note that the data is stored under the name of the given key.
});

memcached.getMulti Retrieves a bunch of values from multiple keys.

  • keys: Array, all the keys that needs to be fetched
  • callback: Function, the callback.
memcached.getMulti(['foo', 'bar'], function (err, data) {
  console.log(data.foo);
  console.log(data.bar);
});

memcached.set Stores a new value in Memcached.

  • key: String the name of the key
  • value: Mixed Either a buffer, JSON, number or string that you want to store.
  • lifetime: Number, how long the data needs to be stored measured in seconds
  • callback: Function the callback
memcached.set('foo', 'bar', 10, function (err) { /* stuff */ });

memcached.replace Replaces the value in memcached.

  • key: String the name of the key
  • value: Mixed Either a buffer, JSON, number or string that you want to store.
  • lifetime: Number, how long the data needs to be replaced measured in seconds
  • callback: Function the callback
memcached.replace('foo', 'bar', 10, function (err) { /* stuff */ });

memcached.add Add the value, only if it's not in memcached already.

  • key: String the name of the key
  • value: Mixed Either a buffer, JSON, number or string that you want to store.
  • lifetime: Number, how long the data needs to be replaced measured in seconds
  • callback: Function the callback
memcached.add('foo', 'bar', 10, function (err) { /* stuff */ });

memcached.cas Add the value, only if it matches the given CAS value.

  • key: String the name of the key
  • value: Mixed Either a buffer, JSON, number or string that you want to store.
  • lifetime: Number, how long the data needs to be replaced measured in seconds
  • cas: String the CAS value
  • callback: Function the callback
memcached.gets('foo', function (err, data) {
  memcached.cas('foo', 'bar', data.cas, 10, function (err) { /* stuff */ });
});

memcached.append Add the given value string to the value of an existing item.

  • key: String the name of the key
  • value: Mixed Either a buffer, JSON, number or string that you want to store.
  • callback: Function the callback
memcached.append('foo', 'bar', function (err) { /* stuff */ });

memcached.prepend Add the given value string to the value of an existing item.

  • key: String the name of the key
  • value: Mixed Either a buffer, JSON, number or string that you want to store.
  • callback: Function the callback
memcached.prepend('foo', 'bar', function (err) { /* stuff */ });

memcached.incr Increment a given key.

  • key: String the name of the key
  • amount: Number The increment
  • callback: Function the callback
memcached.incr('foo', 10, function (err) { /* stuff */ });

memcached.decr Decrement a given key.

  • key: String the name of the key
  • amount: Number The increment
  • callback: Function the callback
memcached.decr('foo', 10, function (err) { /* stuff */ });

memcached.del Remove the key from memcached.

  • key: String the name of the key
  • callback: Function the callback
memcached.del('foo', function (err) { /* stuff */ });

memcached.version Retrieves the version number of your server.

  • callback

memcached.flush Flushes the memcached server.

  • callback

memcached.stats Retrieves stats from your memcached server.

  • callback

memcached.settings Retrieves your stats settings.

  • callback

memcached.slabs Retrieves stats slabs information.

  • callback

memcached.items Retrieves stats items information.

  • callback

memcached.cachedump Inspect cache, see examples for a detailed explanation.

  • server
  • slabid
  • number
  • callback

memcached.end Closes all active memcached connections.

Private methods

The following methods are intended for private usage

.connect Fetches or generates a connection for the given server. The supplied callback function will receive a reference to the connection as argument. If there are issues with the server connection, we are going to respond with cache-miss pattern.

  • server: String, The server that needs a connection, the format must be confirm the server_locations specification.
  • callback: Function, The callback function that receives the net.Stre
memcached.connect( '192.168.0.103:11211', function( err, conn ){
  if( err ) throw new Error( err );
  console.log( conn.server );
});

.multi A small wrapper function that makes it easier to query multiple Memcached servers. It will return the location for each key or the complete list of servers.

  • keys: Array (optional), They keys that needs to be converted to a server.
  • callback: Function, The callback function for the data, it will be called for each key. It will be called with 4 arguments:
  1. server: String, The server location.
  2. key: String, The key associated with the server, if you didn't specify keys, this variable will be undefined.
  3. index: Number, The current index of the loop
  4. total: Number, The total amount server retrieved.
memcached.multi( false, function( server, key, index, totals ){
  if( err ) throw new Error( err );

  this.connect( server, function( err, conn ){
    console.log( "connection ready" )
  })
});

.command This is the core functionality of the memcached client. All public API's are routed through this function. It takes care of the argument validations Server retrieval ( If the server argument isn't specified ). After all data ready a connection is asked for the private connect method and the command is written to the Memcached server.

  • query: Object, The metaData object, see the Callbacks section for the specification.
  • server: String, The server the to connect. This is only needed when the metaData object doesn't contain a key property to retrieve the server from.
memcached.command({
  key: 'key', callback: function(){ console.dir( arguments ); },

  // validate the arguments
  validate: [[ 'key', String ], [ 'callback', Function ]],

  // used for the query
  type: 'delete',
  command: 'delete key'
});

.connectionIssue A internal function for logging issues with connections. As there can be various of ways that an error occurs we need solid issue manager to handle all these cases. For example server could crash or the Memcached server could respond with SERVER ERROR <broken>.

  • error: String, The actual error message.
  • Stream: net.Stream, A reference to the connection stream where the error occurred on.
  • callback: Function (optional), The callback function of a potential request, it will be marked as cache miss if it was provided
memcached.connectionIssue( "Server down", connectionReference );

Callbacks

Each method requires a callback function. Once this function get executed there will be 2 variables applied:

  • error: A error response if something went wrong while retrieving data from the Memcached server. Depending on the type of request this will either be an string or an Array with multiple errors.
  • response: The actual result from the Memcached server. If the response is false or undefined than a cache miss occurred. Cache misses will also occur when there is an error. So you might want to check on errors first.

When we have a successful response, the context of the callback function will shift to a metaData object. The metaData object contains all information that we used to generate the request for the Memcached server. The metaData object contains the following properties:

  • start: Date in milliseconds when the request was received
  • execution: Total execution time for the request, including response parsing.
  • callback: Reference to the callback function
  • type: The type of Memcached command
  • command: The compiled command that was send through the sockets
  • validate: The properties of metaData object that needs type validation.

And all the arguments you have send to the method, this depends on the method you have called.

Events

When connection issues occur we send out different notifications using the EventEmitter protocol. This can be useful for logging, notification and debugging purposes. Each event will receive details Object containing detailed information about the issues that occurred.

Details Object

The details Object contains the various of error messages that caused, the following 3 will always be present in all error events:

  • server: the server where the issue occurred on
  • tokens: a array of the parsed server string in [port, hostname] format.
  • messages: a array containing all error messages that this server received. As messages are added to the array using .push(), the first issue will at the beginning and the latest error at the end of the array.

The following properties depend on the type of event that is send. If we are still in our retry phase the details will also contain:

  • failures: the amount of failures left before we mark the server as dead.
  • totalFailures: the total amount of failures that occurred on this server, as when the server has been reconnected after it's dead the failures will be rest to defaults and messages will be removed.

If the server is dead these details will be added:

  • totalReconnectsAttempted: the total reconnects we have attempted. This is the success and failure combined.
  • totalReconnectsSuccess: the total successful reconnects we have made.
  • totalReconnectsFailed: the total failed reconnects we have made.
  • totalDownTime: the total down time that was generated. Formula: ( totalReconnectsFailed * reconnect_timeout ) + ( totalRetries * retry_timeout).

Events

There are 5 different events that the memcached client emits when connection issues occur.

  • issue: a issue occurred on one a server, we are going to attempt a retry next.
  • failure: a server has been marked as failure or dead.
  • reconnecting: we are going to attempt to reconnect the to the failed server.
  • reconnect: successfully reconnected to the memcached server.
  • remove: removing the server from our consistent hashing.

Example implementations:

var memcached = new Memcached([ '192.168.0.102:11211', '192.168.0.103:11211' ]);
memcached.on('failure', function( details ){ sys.error( "Server " + details.server + "went down due to: " + details.messages.join( '' ) ) });
memcached.on('reconnecting', function( details ){ sys.debug( "Total downtime caused by server " + details.server + " :" + details.totalDownTime + "ms")});

Compatibility

For compatibility with other libmemcached clients they need to have the behavior ketama_weighted set to true and the hash set to the same as node-memcached's algorithm.

Due to client dependent type flags it is unlikely that any types other than string will work.

Test

You may encounter several problems when run the test. Be sure you already made these preparations:

  1. Start the memcached service. (If in Mac env, you can install it via homebrew, and brew services start memcached)
  2. Start 3 memcached servers at port 11211, 11212, 11213. (You first service will start at default port 11211, so you need to start 2 other servers manually. memcached -p 11212 -d, memcached -p 11213 -d)
  3. Run export MEMCACHED__HOST=localhost in your terminal. (This will make sure that the test case use localhost as your memcached server IP address other than it's default IP)

Contributors

This project wouldn't be possible without the hard work of our amazing contributors. See the contributors tab in Github for an up to date list of contributors.

Thanks for all your hard work on this project!

License

The driver is released under the MIT license. See the LICENSE for more information.

memcached's People

Contributors

3rd-eden avatar bbamsch avatar ctavan avatar fkei avatar fouber avatar gamedev8 avatar hiramatsu-kosuke avatar ianshward avatar icecubed avatar jpalardy avatar kahing avatar kcarlson avatar kevin-greene-ck avatar lackac avatar makerandrew avatar mapleeit avatar peters avatar pmark avatar privman avatar qard avatar rcoup avatar rdzar avatar roylines avatar ryansname avatar safarishi avatar schloerke avatar scott-leung avatar sebastianseilund avatar tmuellerleile avatar yyydao avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

memcached's Issues

probes or events for metric collections

We should add more probes to the memcached driver to expose useful events and metrics to the users. Such as the time it has taken to do a single call, etc.

Kernel buffer full not detected correctly on recent nodejs versions

Manager.isAvailable() does not detect correctly whether kernel buffer is full, causing reuse of connections in the pool which are busy. On high loads, this causes a performance degradation.

Recent Node.js versions do not have _writeQueue in socket instances, instead they have a _handle object which has writeQueueSize. Look at Socket.prototype._write in node's lib/net.js, it checks for this._handle.writeQueueSize == 0. Alternatively, type:

``` console.log(require('net').Socket.prototype._write.toString())````

Tests not working?

When I run node-memcached tests it instantly says 0 tests complete? I've changed exports.servers to my localhost 127.0.0.1 instances. I don't see any errors. Am I doing something wrong?

Certain errors do not pass an error argument into callback

When I do sets or gets, if the connection has an issue, an error is not returned into my callback. This means that my code will assume the "set" was successful, or in the case of "get", that the value of the retrieved key is false.

Also, the connect() function does a check if the server is in a failed state. Yet, in both cases where connect() is called, this very same check is executed right before connect() is called. This is duplicate code. One slight nuance here, is that on line 208 of memcached.js, no callback is called if the server check failed.

Server never marked as down and never removed

When a server is unavailable the library doesn't mark it as down.

I initialize the client with this code:

    cache = new Memcached([ '127.0.0.1:11211', '127.0.0.1:11212' ], {
        remove: true,
        poolSize: 20,
        timeout: 3000,
        retries: 5,
        retry: 1000,
        reconnect: 1000
    });

Where 127.0.0.1:11212 is intentionally down.

And when I set a new object with:

cache.set(key, value, 0, function(err, result) {
    // Do something
});

I get the following exception:

Error: Can't set an object into cache: false
    at Object.callback (/Users/user/test/lib/cache.js:44:11)
    at EventEmitter.memcachedCommand [as command] (/Users/user/test/lib/memcached/memcached.js:184:93)
    at EventEmitter.setters (/Users/user/test/lib/memcached/memcached.js:610:15)
    at EventEmitter.set (/Users/user/test/lib/memcached/utils.js:68:17)

Which I shouldn't get because the other server is up and running.

I added some listeners like:

    cache.on('failure', function(details) { 
        console.log("Server " + details.server + " went down due to: " + details.messages.join( '' ));
    });

    cache.on('issue', function(details) { 
        console.log("Server " + details.server + " has an issue due to: " + details.messages.join( '' ));
    });

    cache.on('remove', function(details) { 
        console.log("Server " + details.server + " has been removed due to: " + details.messages.join( '' ));
    });

    cache.on('reconnecting', function(details) { 
        console.log("Reconnecting to server " + details.server + " due to: " + details.messages.join( '' ));
    });

    cache.on('reconnected', function(details) { 
        console.log("Successfully reconnected to server " + details.server);
    });

And I only get this message before the exception:

Server undefined has an issue due to: Error: ECONNREFUSED, Connection refused

Thus the library is not attempting to reconnect, and it's not removing the server. And in the message above it can't get the server address (it's "undefined").

Cannot call method 'connectionIssue' of undefined

I'm using node-memcached in my node app. Setup: 6 node processes behind HAproxy (load balancer).

I get this error during heavy load/multiple writes.

/home/shripad/CODE/Hydra-3.0/node_modules/memcached/lib/memcached.js:273
OR': function(tokens, dataSet, err, queue, S, memcached){ memcached.connection
                                                                    ^
TypeError: Cannot call method 'connectionIssue' of undefined
    at Socket.<anonymous> (/home/shripad/CODE/Hydra-3.0/node_modules/memcached/lib/memcached.js:273:84)
    at EventEmitter.rawDataReceived (/home/shripad/CODE/Hydra-3.0/node_modules/memcached/lib/memcached.js:460:50)
    at EventEmitter.BufferBuffer (/home/shripad/CODE/Hydra-3.0/node_modules/memcached/lib/memcached.js:416:12)
    at Socket.<anonymous> (/home/shripad/CODE/Hydra-3.0/node_modules/memcached/lib/utils.js:68:17)
    at Socket.emit (events.js:64:17)
    at Socket._onReadable (net.js:676:14)
    at IOWatcher.onReadable [as callback] (net.js:177:10)

Image parsing returning a blank white image

I am storing images in a memcache. Some images, however, return a white blank image. The storage on the memcache server side seems to be ok, so I think the issue is with the parsing.

The following image works: http://i.imgur.com/z5IUt.jpg

The following image does NOT work: http://ichef.bbci.co.uk/wwhomepage-3.5/ic/news/144-81/64179000/jpg/_64179346_cheteshwar_pujara_getty3.jpg

Most images on bbc.com don't work. From my investigation, all of the images that don't work have a XMP header inside of them:
<x:xmpmeta xmlns:x="adobe:ns:meta/"><rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:Description rdf:about="uuid:faf5bdd5-ba3d-11da-ad31-d33d75182f1b" xmlns:dc="http://purl.org/dc/elements/1.1/"><dc:creator><rdf:Seq xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"><rdf:li>Thinkstock</rdf:li></rdf:Seq> </dc:creator></rdf:Description></rdf:RDF></x:xmpmeta>

The images return white blank on both Firefox and Chrome.
I am using node version 0.8.14.
I am running Windows 7.

Object has no method '_emitCloseIfDrained'

We're getting an error in our node logs after an upgrade to node v0.6.5 & node_memcached 0.0.5 with memcached version 1.4.2-1ubuntu3. This didn't manifest before our upgrade.

TypeError: Object cache-01:11211 has no method '_emitCloseIfDrained'
    at Socket.destroy (net.js:290:17)
    at TCP.onread (net.js:347:30)
Arguments:  [ '_emitCloseIfDrained',
  'cache-01:11211' ]

Please advise.

Potential bug: passing servers as object

I don't use this feature myself, so I am not running into any trouble, but it seems to me the switch statement in the Client constructor is missing a break statement in case '[object Object]'. Something tells me the { server: priority } case won't be able to function this way, since the servers variable now gets overwritten by the '[object Array]' case.

[Feature request] key validation

After spending half a day trying to figure out what was wrong in my code and finally realizing the keys that were provided to me contained spaces, I think a very small check to test the keys validity would be a very sweet addition to this module.

Stream error and timeout handled differently

I was running into issues today when trying to connect to a single host that did not exist. I expected the memcached API function calls I made to complete after "timeout" milliseconds, but they did not.

Upon inspecting the code, I noticed that the handling for connection errors (line 113 in memcached.js) is different than the handling for timeouts (line 115 in memcached.js). I would expect them to be handled similarly.

To reproduce/verify that memcached API calls are not completing after "timeout" milliseconds, set your timeout to a low value and try to connect to a bogus host. The API call does not execute the supplied callback after Stream emits "timeout", but instead calls the callback when Stream emits "error".

node gets memory leak

test script is below:

https://github.com/aleafs/node-memcached/blob/master/tests/memcached-memory-leak.js

run it:

$ nohup node ./tests/memcached-memory-leak.js &

After a long time, node crashed

$ tail nohup.out
11176348    960507904   949406528   943923480
11178501    962871296   949666624   943506072
11180496    963133440   949926720   943954032
11180506    959148032   946780992   943499176
11180507    958418944   946008832   943017032
11180508    958418944   946008832   943061888
11181768    960524288   947309376   943285216
11183025    960737280   947561344   943419184
11184430    961871872   949658496   943609384
FATAL ERROR: CALL_AND_RETRY_0 Allocation failed - process out of memory

Feature Request: Add ability to stream get/set requests

Howdy, I'd like to be able to stream objects to/from Memcached (rather than needing to load them up into a buffer before moving forward)

I would imagine get() could just accept a ReadableStream and set() would of course take a WriteableStream in place of the value parameter.

get error if value begins with "OK"

Here's a gist with a test program. I've been seeing this on my production servers and it's a fun bug--if the value that comes back from a get begins with OK it confuses the memcached client:

https://gist.github.com/3876730

After looking over the source, I bet this is a possibility for the other protocol keywords as well.

thanks!

corrupted data on concurrent requests

Hi,
we are experiencing some problems using this memcache client. We have implemented it in our project, but after testing under high load with concurrent requests we found out that sometimes data from memcache are corrupted. Either there are trailing characters from memcache command ("/r/nEND" after data or some numbers and /r/n before data) or there is /r/n in the middle of result.

This is tested on debian lenny, and ubuntu

Sample script:

var originalString = 'abcdefghijklmnopqrstuvwxyz0123456789';
var nMemcached = require('./3rd-Eden-node-memcached/nMemcached').Client;
var memcache = new nMemcached('localhost:11211');

memcache.set('testIndex1', originalString, 3600, function(err) {
if(err) console.log(err);

require('http').createServer(function (request, response) {
memcache.get('testIndex1', function(err, result) {
if( err ) console.error( err );

  if(result !== originalString) 
    console.log(result);

  memcache.end();
});

response.writeHead(200, {"Content-Type": "text/html"});
response.end();

}).listen(8124, "localhost");
});

high load can be simulated running this bash script:

(sharp)!/bin/bash
for i in seq 1 50;
do
./bash.sh (new line)
done

./bash.sh file:

(sharp)!/bin/bash
for i in seq 1 50;
do
curl http://localhost:8124/ (new line)
done

get is ok, but can not set

Memcached = require('memcached'),
memcached = new Memcached(['127.0.0.1:11311'], {maxKeySize:1000}),
memcached.set('node', 'hello node', 10000, function(err, result){
memcached.end();
});

debug message :

TypeError: Cannot read property 'length' of undefined
at EventEmitter.memcachedCommand as command
at EventEmitter.setters (/home/www/nodejs/node_modules/memcached/lib/memcached.js:745:15)
at EventEmitter.set (/home/www/nodejs/node_modules/memcached/lib/utils.js:70:17)

so i look memcached.js line 228 and debug it:

if (!server) {
// no need to do a hashring lookup if we only have one server assigned to
// us
console.log('servers:'+this.servers); // my add
if (this.servers.length === 1) {

print servers: undefined

Failed connection throws exception

In version 0.1.0, failed connections did not throw an exception, but this seems to be happening in 0.1.2. Is this a regression or expected behavior? Will I need to do my own handling now?

events.js:66
        throw arguments[1]; // Unhandled 'error' event
                       ^
Error: connect ECONNREFUSED
    at errnoException (net.js:768:11)
    at Object.afterConnect [as oncomplete] (net.js:759:19)

private.singles() always has an error Parameter

I try to use function stats() in memcached like this:
memcached.version(function(err,data){
if(err){
console.error(err);
}
console.log( JSON.stringify ( data ));
});

the output always like this:
[]
[{"server":"127.0.0.1:11211","pid":2508,"uptime":1922,"time":1320131967,"version":"1.4.9","libevent":"2.0.15-stable","pointer_size":64,"rusage_user":"0.030000","rusage_system":"0.080000","curr_connections":11,"total_connections":34,"connection_structures":12,"reserved_fds":20,"cmd_get":24,"cmd_set":21,"cmd_flush":0,"cmd_touch":0,"get_hits":23,"get_misses":1,"delete_misses":0,"delete_hits":1,"incr_misses":0,"incr_hits":2,"decr_misses":0,"decr_hits":0,"cas_misses":0,"cas_hits":0,"cas_badval":0,"touch_hits":0,"touch_misses":0,"auth_cmds":0,"auth_errors":0,"bytes_read":1529,"bytes_written":10502,"limit_maxbytes":67108864,"accepting_conns":1,"listen_disabled_num":0,"threads":4,"conn_yields":0,"hash_power_level":16,"hash_bytes":524288,"hash_is_expanding":0,"expired_unfetched":0,"evicted_unfetched":0,"bytes":144,"curr_items":2,"total_items":17,"evictions":0,"reclaimed":0}]

the first null [] must be console by cnosole.error(err). I try version() again ,the result is same as before.
I read some source code and find the private.singles() maybe has a little bug.
private.singles = function singles(type, callback){
var memcached = this
, responses = []
, errors = []
, calls

  // handle multiple servers
  , handle = function(err, results){
    if (err) errors.push(err);
    if (results) responses = responses.concat(results);

    // multi calls should ALWAYS return an array!
    if (!--calls) callback(errors, responses);
  };

since errors be defined to [],it can be test by callback,I'm an Chinese C++ coder and can't ensure this is right,so expected your replay.

Cannot read property 'length' of undefined (memcached.set)

A simple memcache.set already fails (on [email protected]) with memcached client talking to domain socket.

probablenews-lm:memcache dkoehler$ cat test.js

var memcached = new (require( 'memcached' ))('/tmp/.memcached.sock');

memcached.set( "hello", 1, 10000, function( err, result ){
    memcached.gets( "hello", function( err, result ){
        if( err ) console.error( err );

        console.dir( result );
        memcached.end();
    });
});
}

probablenews-lm:memcache dkoehler$ node test.js

node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Cannot read property 'length' of undefined
at EventEmitter.memcachedCommand as command
at EventEmitter.setters (/Users/dkoehler/node_modules/memcached/lib/memcached.js:744:15)
at EventEmitter.set (/Users/dkoehler/node_modules/memcached/lib/utils.js:70:17)
at Object. (/Users/dkoehler/dev/memcache/test.js:3:11)
at Module._compile (module.js:402:26)
at Object..js (module.js:408:10)
at Module.load (module.js:334:31)
at Function._load (module.js:293:12)
at Array. (module.js:421:10)
at EventEmitter._tickCallback (node.js:126:26)

Query returning routine errors

I have the following query and when i return the routine it errors out

qry = "SELECT g.Guid, g.Name, g.Description, g.Address1, g.Address2," +
" c.Name as City, s.Name as State, g.Phone, g.Zip, g.Latitude, g.Longitude" +
" ,DISTANCE(g.Latitude, g.Longitude, ?, ?) as Distance"
" FROM Store g INNER JOIN State s on g.StateId=s.StateId" +
" INNER JOIN City c on c.CityId = g.CityId" +
" WHERE DISTANCE(g.Latitude, g.Longitude, ?, ?) < 50.0" +
" ORDER BY DISTANCE(g.Latitude, g.Longitude, ?, ?) LIMIT ?"

This is the error I get:
{ [Error: ER_UNKNOWN_TABLE: Unknown table 'g' in field list] code: 'ER_UNKNOWN_TABLE', index: 0 }

When I remove this line, it works:
" ,DISTANCE(g.Latitude, g.Longitude, ?, ?) as Distance"

Incorrect error handling in validate

We discovered some problematic code when the API caller fails to pass an appropriate callback to memcached calls.

In function memcached.command:

// validate the arguments
if (query.validate && !Utils.validateArg(query, this)) return;

This results in a silent error which is undesirable.

Instead, this code should throw an exception to inform the API caller that they did something wrong.

No error returned when trying to add a key which already exists

Not sure if this is by design, but it surprised me.
If I add the same key twice, memcached server returns a "NOT_STORED" reply for the second attempt, which is listed as an error response under privates.parsers (but the parser returns a CONTINUE value), and node-memcached does not return an error.
I imagine the same behaviour applies to other error parsers which return a CONTINUE value.
Test case for this issue: privman@9e597f8 (hasn't been run because I haven't been able to run mocha on my Windows machine)

SASL Support

Just wondering if there were any plans on supporting SASL authentication. The use case for this is heroku's memcache deployment requires SASL to work. Thanks for your time.

Get in Cluster environment

Problem :

  • memcache1
    -key1
  • memcache2
    -key1
    -key2

Using the library to connect to cluster, i'm trying to get key2 ( present on memcache2), but nothing returned :(

loading the memcached

I have a portgresql table called testtab 2 columns key (character 20) and val (text) - i insert key1... key and text1 ... text5 into theses.

I want to cache the content - I pgconnect , select and then using a for loop memcached.set ( results.rows[i].key, results.rows[i].val.lifetime .....
no return true, false or result - just ends
the content is not loaded into the cache - I cannot retrieve it using a memcached.get a loop

if on the other hand i load content in a for loop using memcached.set('wtf'+i, 'que passa', lifetime ...
and later use the get to retrieve content, it works as expected.

( i even tried the cal column to be a fixed character length)

The set and get are from the examples

              memcached.set( testresult.rows[i].key ,testresult.rows[i].val, lifetime, function( err, result ){
                if( err ) console.error( err );
                    console.dir( result );
               });

where the testresult is from a select run against the testtab - the query works every time

MemCache get callback called multiple times when MemCache can't connect

When 'get' is called on a MemCache Connection that is unable to connect to the MemCache server. The callback is being called multiple times with 'Connect did not give a server' as the first parameter.

This seems like the wrong behavior. The callback should really only be called once. If the fallback is to make a data request for the data that it was not able to retrieve from the cache, the current behavior causes multiple data requests to be continually made.

TypeError: Cannot call method 'substr' of undefined

I've got a reasonable traffic and concurrency workload with a set of servers all hitting a single AWS ElastiCache memcached server. I encounter bunches of errors like the following:

/PATH/TO/node_modules/memcached/lib/memcached.js:357
      , b: +tokens[2].substr(1)
                      ^
TypeError: Cannot call method 'substr' of undefined
    at Socket.<anonymous> (/PATH/TO/node_modules/memcached/lib/memcached.js:357:23)
    at EventEmitter.rawDataReceived (/PATH/TO/node_modules/memcached/lib/memcached.js:484:50)
    at EventEmitter.BufferBuffer (/PATH/TO/node_modules/memcached/lib/memcached.js:440:12)
    at Socket.<anonymous> (/PATH/TO/node_modules/memcached/lib/utils.js:68:17)
    at Socket.emit (events.js:67:17)
    at TCP.onread (net.js:347:14)

I'm not sure what the underlying issues is, but could the node-memcached library permissively handle this and just bubble up an error instead, as the TypeError kills my entire node process. Thanks!

multi get - missing results

Hi,
I found another problem lately. If I get multiple keys from memcache, and some keys are not in memcache, it will ignore them and returns found keys only, with no warning or info which one is missing.

exapmle:

memcached.get(['first','second','third'] ...

'first' is not in memcache so it returns ['2nd', '3rd'] , but I have no chance to find out which one is missing.

I would prefer it to return ['', '2nd', '3rd'] or something similar if its possible.

thank u.

Saturating memcached takes down node

When Manager.allocate() goes through the whole connection pool and finds all the connections busy, it just re-schedules on nextTick(). In the case where we actually produce more requests than memcached server can handle, these scheduled allocate() calls pile up (since they are produced faster than they are consumed) and eventually choke down the server.

Global options

Hi when I try change the global options for memcached using docs code:

var Memcached = require( 'memcached' ).Client;
// all global configurations should be applied to the .config object of the Client.
Memcached.config.poolSize = 25;

got: TypeError: Cannot read property 'config' of undefined

Cannot read property 'length' of undefined (memcached.set)

I'm trying to use run memcached with unix sockets, but seems a simple 'set' already fails (using [email protected])

probablenews-lm:memcache dkoehler$ cat test.js
var memcached = new (require( 'memcached' ))('/tmp/.memcached.sock');

memcached.set( "hello", 1, 10000, function( err, result ){
memcached.gets( "hello", function( err, result ){
if( err ) console.error( err );

    console.dir( result );
    memcached.end();
});

});
probablenews-lm:memcache dkoehler$ node test.js

node.js:134
throw e; // process.nextTick error, or 'error' event on first tick
^
TypeError: Cannot read property 'length' of undefined
at EventEmitter.memcachedCommand as command
at EventEmitter.setters (/Users/dkoehler/node_modules/memcached/lib/memcached.js:744:15)
at EventEmitter.set (/Users/dkoehler/node_modules/memcached/lib/utils.js:70:17)
at Object. (/Users/dkoehler/dev/memcache/test.js:3:11)
at Module._compile (module.js:402:26)
at Object..js (module.js:408:10)
at Module.load (module.js:334:31)
at Function._load (module.js:293:12)
at Array. (module.js:421:10)
at EventEmitter._tickCallback (node.js:126:26)

Crash when instantiating with empty server string v0.0.8

var memcache = require('memcached');
undefined
var m = new memcache();

TypeError: Cannot read property 'length' of undefined
at EventEmitter.Client (~/node_modules/memcached/lib/memcached.js:51:15)
at repl:1:9
at REPLServer.eval (repl.js:80:21)
at repl.js:190:20
at REPLServer.eval (repl.js:87:5)
at Interface. (repl.js:182:12)
at Interface.emit (events.js:67:17)
at Interface._onLine (readline.js:162:10)
at Interface._line (readline.js:426:8)
at Interface._ttyWrite (readline.js:603:14)

Object has no method '_emitCloseIfDrained'

Every time i attempt an nMemcached command, the memcached write or get completes successfully, but my server crashes.

Here's the stack trace I run into:

net_legacy.js:847
    this.server._emitCloseIfDrained();
                ^
TypeError: Object db01.pzkvw.com:11211 has no method '_emitCloseIfDrained'
    at Socket.destroy (net_legacy.js:847:17)
    at Socket._onConnect (net_legacy.js:606:10)
    at IOWatcher.onWritable [as callback] (net_legacy.js:186:12)

I debugged for a little while and determined the cause to be around line 114 in memcached.connect:

S.connect.apply( S, serverTokens );

basically, when S is bound to "this" in the context of S.connect, S.server is a string (The server name, in this case "db01.pzkvw.com:11211") and not an object, so it has no methods or fields attached to it. "_emitCloseIfDrained" is one of the methods that is expected to exist.

It seems like a pretty fundamental error, so I wonder if I should be running a certain version of nodejs (i have 'v0.5.5-pre') or if I'm just instantiating things incorrectly. I tried to follow the examples pretty closely, here is a simple example that still breaks for me:

var nMemcached = require('nMemcached');
var memcached = new nMemcached('db01.pzkvw.com:11211')
memcached.set(
    'someKey', 100, 10000, function(){}
);

Connection issue

Hi all,

Looks like that something in code does not work properly and I'm having an error when I'm trying to run many commands at once:

    var Memcached = require('memcached');
    var _client = new Memcached('localhost:11211');

    for (var i = 0; i < 100; i++) {
        _client.set('test' + i, 'value', 1000, function(err, res) {
            if (err) throw err;
            else console.log('ok');
        });
    };
Error: All the connections in the memcached pool are busy

However the following code works splendidly:

   _client.set('foo', 'bar', 1000, function(err, res) {
        for (var i = 0; i < 100; i++) {
            _client.set('test' + i, 'value', 1000, function(err, res) {
                if (err) throw err;
                else console.log('ok');
            });
        };
    });

I think the problem because in the first example, library tries to connect 100 times (because there was no connection). In contract, in the second example library is already connected and do not perform another 100 attempts to connect.
Hope that helps!

Unexpected behaviour when key too long

Memcached has length limitation for keys and values. Value length limit could be ignored as it's pretty high (about 1MB), but key is limited to 250 characters and it's easy to go over it.

While trying to set/get longer keys my memcached starts behaving very weirdly, messing up the order of responses and throwing errors once and then.

FR: ability to not use the hashring

For those of us using node-memcached to connect to a single Moxi server, the hashring is overkill and generating the crc32 hashes for every key, and storing those in a cache (which is what hashring does), are a relatively heavy overhead. It would be therefore be great if there was an option to disable the hashring, which I guess would have the requirement that exactly 1 server host is provided. That would save us a lot of cpu cycles, and ram usage.

Memcached.item(...) crashes when no items

The result set actually contains [ false ] at line 384 if memcached has no items (fresh startup). Doesn't seem right... but that's what happens.

/root/proxy/modules/memcached/lib/memcached.js:384
var identifier = statSet[0].split(':');
^
TypeError: Cannot call method 'split' of undefined
at /root/proxy/modules/memcached/lib/memcached.js:384:37
at Array.forEach (native)
at Socket. (/root/proxy/modules/memcached/lib/memcached.js:383:17)
at EventEmitter.rawDataReceived (/root/proxy/modules/memcached/lib/memcached.js:478:93)
at EventEmitter.BufferBuffer (/root/proxy/modules/memcached/lib/memcached.js:416:12)
at Socket. (/root/proxy/modules/memcached/lib/utils.js:68:17)
at Socket.emit (events.js:64:17)
at Socket._onReadable (net.js:678:14)
at IOWatcher.onReadable as callback

Basic API documentation for get()/set()

Can you provide some very basic documentation for performing get()/set() operations? I've tried the following (trying to infer function arguments from source code) but it doesn't seem to work:

var nMemcached = require('nMemcached');
var memcache = new nMemcached(['127.0.0.1:11211', '127.0.0.1:11212']);

memcache.set('key1', 10000, 'my first value', function() {});
memcache.get('key1', function(value) { console.log(value); });

In this case value is undefined. Your library looks great and I'd like to use it, please advise.

Error: Socket.end() called already; cannot write

Hi, Im using your library with socket.io authentication to verify users sessions.
I encountered the following problem:

Event issue: 172.21.3.185:701 {"server":"172.21.3.185:701","tokens":["701","172.21.3.185"],"messages":[{"stack":"Error: Socket.end() called already; cannot write.\n    at Socket.write (net.js:334:13)\n    at allocateMemcachedConnection (/opt/fotka/node-0.4.12/lib/node/memcached/lib/memcached.js:198:9)\n    at Socket.streamConnect (/opt/fotka/node-0.4.12/lib/node/memcached/lib/memcached.js:120:44)\n    at Socket.emit (events.js:61:17)\n    at Socket._onConnect (net.js:582:12)\n    at IOWatcher.onWritable (net.js:186:12)","message":"Socket.end() called already; cannot write."}],"retries":2,"totalRetries":0}

What can this mean?
How do I deal with it?

Thanks

Binary data get() issue

I've got a pdf file with the size of 125884 bytes https://github.com/aslushnikov/node-memcached/blob/master/issues/48/1335827866.pdf. Once I stored it in the memcached, it almost always comes back corrupted: the data lacks 3 or 4 bytes, but sometimes it happens that it is returned full.

I guess the problem is that you check the end of the message from memcached with the \r\n sequence, but in memcached documentation it is strongly recommended not to do this way.

Hope it helps, and thank you for your work,
Andrey

cache miss when number of initial concurrent connections > poolSize

Playing with ab, I discovered the following problem:
with poolSzie set, for example, as 10, and no pool operating(initial start of application), 'ab -c 11' will yield cache miss on 11th request, with no error message returned. Just 'false' in result. If you start 20 concurrent connection, 10 will get the miss, and so on, basically any number over poolSize of connections will be in trouble. That also will happen if all pooled connections close during normal application run, and start over again.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.