Skip to content

Commit

Permalink
Merge pull request #59 from sontek/add_hashing_client
Browse files Browse the repository at this point in the history
Add hashing client
  • Loading branch information
cgordon committed Jul 17, 2015
2 parents 3444e0e + ed85bcf commit 63a2d96
Show file tree
Hide file tree
Showing 20 changed files with 937 additions and 100 deletions.
8 changes: 8 additions & 0 deletions ChangeLog.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
Change Log
==========
Unreleased
----------
* Python 3 Support
* Introduced HashClient that uses consistent hasing for allocating keys
across many memcached nodes. It also can detect servers going down
and rebalance keys across the available nodes.
* Retry sock.recv() when it raises EINTR

New in version 1.2.9
--------------------

Expand Down
36 changes: 20 additions & 16 deletions README.md → README.rst
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
pymemcache
==========

[![Build
Status](https://travis-ci.org/pinterest/pymemcache.png)](https://travis-ci.org/pinterest/pymemcache)
.. image:: https://travis-ci.org/pinterest/pymemcache.png
:target: https://travis-ci.org/pinterest/pymemcache

A comprehensive, fast, pure-Python memcached client.

Expand All @@ -19,13 +19,17 @@ Installing pymemcache

You can install pymemcache manually, with Nose tests, by doing the following:

.. code-block:: bash
git clone https://github.com/pinterest/pymemcache.git
cd pymemcache
python setup.py nosetests
sudo python setup.py install
You can also use pip:

.. code-block:: bash
sudo pip install https://github.com/pinterest/pymemcache.git
Usage
Expand Down Expand Up @@ -83,17 +87,17 @@ Mixpanel's pure Python memcached client:
Credits
=======

* [Charles Gordon](http://github.com/cgordon)
* [Dave Dash](http://github.com/davedash)
* [Dan Crosta](http://github.com/dcrosta)
* [Julian Berman](http://github.com/Julian)
* [Mark Shirley](http://github.com/maspwr)
* [Tim Bart](http://github.com/pims)
* [Thomas Orozco](http://github.com/krallin)
* [Marc Abramowitz](http://github.com/msabramo)
* [Marc-Andre Courtois](http://github.com/mcourtois)
* [Julien Danjou](http://github.com/jd)
* [INADA Naoki](http://github.com/methane)
* [James Socol](http://github.com/jsocol)
* [Joshua Harlow](http://github.com/harlowja)
* [John Anderson](http://github.com/sontek)
* `Charles Gordon <http://github.com/cgordon>`_
* `Dave Dash <http://github.com/davedash>`_
* `Dan Crosta <http://github.com/dcrosta>`_
* `Julian Berman <http://github.com/Julian>`_
* `Mark Shirley <http://github.com/maspwr>`_
* `Tim Bart <http://github.com/pims>`_
* `Thomas Orozco <http://github.com/krallin>`_
* `Marc Abramowitz <http://github.com/msabramo>`_
* `Marc-Andre Courtois <http://github.com/mcourtois>`_
* `Julien Danjou <http://github.com/jd>`_
* `INADA Naoki <http://github.com/methane>`_
* `James Socol <http://github.com/jsocol>`_
* `Joshua Harlow <http://github.com/harlowja>`_
* `John Anderson <http://github.com/sontek>`_
46 changes: 46 additions & 0 deletions docs/apidoc/pymemcache.client.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
pymemcache.client package
=========================

Submodules
----------

pymemcache.client.base module
-----------------------------

.. automodule:: pymemcache.client.base
:members:
:undoc-members:
:show-inheritance:

pymemcache.client.hash module
-----------------------------

.. automodule:: pymemcache.client.hash
:members:
:undoc-members:
:show-inheritance:

pymemcache.client.murmur3 module
--------------------------------

.. automodule:: pymemcache.client.murmur3
:members:
:undoc-members:
:show-inheritance:

pymemcache.client.rendezvous module
-----------------------------------

.. automodule:: pymemcache.client.rendezvous
:members:
:undoc-members:
:show-inheritance:


Module contents
---------------

.. automodule:: pymemcache.client
:members:
:undoc-members:
:show-inheritance:
7 changes: 4 additions & 3 deletions docs/apidoc/pymemcache.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,16 @@ Subpackages

.. toctree::

pymemcache.client
pymemcache.test

Submodules
----------

pymemcache.client module
------------------------
pymemcache.exceptions module
----------------------------

.. automodule:: pymemcache.client
.. automodule:: pymemcache.exceptions
:members:
:undoc-members:
:show-inheritance:
Expand Down
16 changes: 16 additions & 0 deletions docs/apidoc/pymemcache.test.rst
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,14 @@ pymemcache.test.test_client module
:undoc-members:
:show-inheritance:

pymemcache.test.test_client_hash module
---------------------------------------

.. automodule:: pymemcache.test.test_client_hash
:members:
:undoc-members:
:show-inheritance:

pymemcache.test.test_integration module
---------------------------------------

Expand All @@ -36,6 +44,14 @@ pymemcache.test.test_integration module
:undoc-members:
:show-inheritance:

pymemcache.test.test_rendezvous module
--------------------------------------

.. automodule:: pymemcache.test.test_rendezvous
:members:
:undoc-members:
:show-inheritance:

pymemcache.test.test_utils module
---------------------------------

Expand Down
21 changes: 19 additions & 2 deletions docs/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,37 @@ Basic Usage

.. code-block:: python
from pymemcache.client import Client
from pymemcache.client.base import Client
client = Client(('localhost', 11211))
client.set('some_key', 'some_value')
result = client.get('some_key')
Using a memcached cluster
-------------------------
This will use a consistent hashing algorithm to choose which server to
set/get the values from. It will also automatically rebalance depending
on if a server goes down.

.. code-block:: python
from pymemcache.client.hash import HashClient
client = HashClient([
('127.0.0.1', 11211),
('127.0.0.1', 11212)
])
client.set('some_key', 'some value')
result = client.get('some_key')
Serialization
--------------

.. code-block:: python
import json
from pymemcache.client import Client
from pymemcache.client.base import Client
def json_serializer(key, value):
if type(value) == str:
Expand Down
3 changes: 3 additions & 0 deletions pymemcache/client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# API Backwards compatibility
from pymemcache.client.base import Client # noqa
from pymemcache.client.base import PooledClient # noqa
65 changes: 14 additions & 51 deletions pymemcache/client.py → pymemcache/client/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,15 @@

from pymemcache import pool

from pymemcache.exceptions import (
MemcacheClientError,
MemcacheUnknownCommandError,
MemcacheIllegalInputError,
MemcacheServerError,
MemcacheUnknownError,
MemcacheUnexpectedCloseError
)


RECV_SIZE = 4096
VALID_STORE_RESULTS = {
Expand Down Expand Up @@ -56,51 +65,9 @@
b'slab_automove': lambda value: int(value) != 0,
}


class MemcacheError(Exception):
"Base exception class"
pass


class MemcacheClientError(MemcacheError):
"""Raised when memcached fails to parse the arguments to a request, likely
due to a malformed key and/or value, a bug in this library, or a version
mismatch with memcached."""
pass


class MemcacheUnknownCommandError(MemcacheClientError):
"""Raised when memcached fails to parse a request, likely due to a bug in
this library or a version mismatch with memcached."""
pass


class MemcacheIllegalInputError(MemcacheClientError):
"""Raised when a key or value is not legal for Memcache (see the class docs
for Client for more details)."""
pass


class MemcacheServerError(MemcacheError):
"""Raised when memcached reports a failure while processing a request,
likely due to a bug or transient issue in memcached."""
pass


class MemcacheUnknownError(MemcacheError):
"""Raised when this library receives a response from memcached that it
cannot parse, likely due to a bug in this library or a version mismatch
with memcached."""
pass


class MemcacheUnexpectedCloseError(MemcacheServerError):
"Raised when the connection with memcached closes unexpectedly."
pass


# Common helper functions.


def _check_key(key, key_prefix=b''):
"""Checks key and add key_prefix."""
if isinstance(key, six.text_type):
Expand All @@ -120,8 +87,7 @@ class Client(object):
"""
A client for a single memcached server.
Keys and Values
----------------
*Keys and Values*
Keys must have a __str__() method which should return a str with no more
than 250 ASCII characters and no whitespace or control characters. Unicode
Expand All @@ -131,16 +97,15 @@ class Client(object):
Values must have a __str__() method to convert themselves to a byte
string. Unicode objects can be a problem since str() on a Unicode object
will attempt to encode it as ASCII (which will fail if the value contains
code points larger than U+127). You can fix this will a serializer or by
code points larger than U+127). You can fix this with a serializer or by
just calling encode on the string (using UTF-8, for instance).
If you intend to use anything but str as a value, it is a good idea to use
a serializer and deserializer. The pymemcache.serde library has some
already implemented serializers, including one that is compatible with
the python-memcache library.
Serialization and Deserialization
----------------------------------
*Serialization and Deserialization*
The constructor takes two optional functions, one for "serialization" of
values, and one for "deserialization". The serialization function takes
Expand All @@ -167,8 +132,7 @@ def deserialize_json(key, value, flags):
raise Exception("Unknown flags for value: {1}".format(flags))
Error Handling
---------------
*Error Handling*
All of the methods in this class that talk to memcached can throw one of
the following exceptions:
Expand Down Expand Up @@ -656,7 +620,6 @@ def _fetch_cmd(self, name, keys, expect_cas):
while True:
buf, line = _readline(self.sock, buf)
self._raise_errors(line, name)

if line == b'END':
return result
elif line.startswith(b'VALUE'):
Expand Down

0 comments on commit 63a2d96

Please sign in to comment.