Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Support weights for servers

In the previous implementation, although it supports ketama_weighted
distribution, there is no way to provide server weights when declaring
the server list.  The only way to get weighted servers is to use the
libmemcached memcache_servers_parse() function, which allows a format
string of "<addr>:<port>:<weight>".  However, pylibmc will not accept
that format.

Instead, given the simple and similar API exposed by libmemcached, it's
very easy to add an optional weight to the server list tuple, and the
default weight (0) is handled automatically by libmemcached.

Example::

    client = pylibmc.Client(servers=[(_pylibmc.server_type_tcp,
                                      '127.0.0.1', 11211, 4),
                                     (_pylibmc.server_type_tcp,
                                      '127.0.0.1', 11212),
                                     '127.0.0.1:11213:2'])

    # client.addresses now contains 3 servers (all localhost, ports
    # 11211-11213), with weights of 4, 1, and 2, respectively.

Change-Id: I2cd6b93aca9b9bec22d3cd2a2e95d7ee3bdb38b3
  • Loading branch information...
commit 6829b0c6f2a083f62a39a602ccf0a2b19d0ff531 1 parent a816e22
Joe jhansche authored
Showing with 47 additions and 23 deletions.
  1. +7 −5 _pylibmcmodule.c
  2. +23 −14 pylibmc/client.py
  3. +17 −4 tests/test_translate.py
12 _pylibmcmodule.c
View
@@ -139,9 +139,11 @@ static int PylibMC_Client_init(PylibMC_Client *self, PyObject *args,
unsigned char stype;
char *hostname;
unsigned short int port;
+ unsigned short int weight;
got_server |= 1;
port = 0;
+ weight = 1;
if (PyString_Check(c_srv)) {
memcached_server_st *list;
@@ -153,12 +155,12 @@ static int PylibMC_Client_init(PylibMC_Client *self, PyObject *args,
}
rc = memcached_server_push(self->mc, list);
- free(list);
+ memcached_server_list_free(list);
if (rc != MEMCACHED_SUCCESS) {
PylibMC_ErrFromMemcached(self, "memcached_server_push", rc);
goto it_error;
}
- } else if (PyArg_ParseTuple(c_srv, "Bs|H", &stype, &hostname, &port)) {
+ } else if (PyArg_ParseTuple(c_srv, "Bs|HH", &stype, &hostname, &port, &weight)) {
if (set_stype && set_stype != stype) {
PyErr_SetString(PyExc_ValueError, "can't mix transport types");
goto it_error;
@@ -177,10 +179,10 @@ static int PylibMC_Client_init(PylibMC_Client *self, PyObject *args,
switch (stype) {
case PYLIBMC_SERVER_TCP:
- rc = memcached_server_add(self->mc, hostname, port);
+ rc = memcached_server_add_with_weight(self->mc, hostname, port, weight);
break;
case PYLIBMC_SERVER_UDP:
- rc = memcached_server_add_udp(self->mc, hostname, port);
+ rc = memcached_server_add_udp_with_weight(self->mc, hostname, port, weight);
break;
case PYLIBMC_SERVER_UNIX:
if (port) {
@@ -188,7 +190,7 @@ static int PylibMC_Client_init(PylibMC_Client *self, PyObject *args,
"can't set port on unix sockets");
goto it_error;
}
- rc = memcached_server_add_unix_socket(self->mc, hostname);
+ rc = memcached_server_add_unix_socket_with_weight(self->mc, hostname, weight);
break;
default:
PyErr_Format(PyExc_ValueError, "bad type: %u", stype);
37 pylibmc/client.py
View
@@ -20,7 +20,7 @@ def _split_spec_type(spec):
else:
return ("tcp", spec)
-def _splitport(spec, port=None):
+def _unpack_addr(spec, port=None, weight=1):
if spec.startswith("["):
if "]" not in spec:
raise ValueError(spec)
@@ -32,37 +32,46 @@ def _splitport(spec, port=None):
(addr, port) = spec.split(":", 1)
else:
addr = spec
- return (addr, port)
-def translate_server_spec(server, port=11211):
- """Translate/normalize specification *server* into three-tuple (tp, addr, port).
+ if isinstance(port, str) and ":" in port:
+ (port, weight) = port.split(":", 1)
+ return (addr, port, weight)
+
+def translate_server_spec(server, port=11211, weight=1):
+ """Translate/normalize specification *server* into 4-tuple (scheme, addr, port, weight).
This is format is used by the extension module.
>>> translate_server_spec("127.0.0.1")
- (1, '127.0.0.1', 11211)
+ (1, '127.0.0.1', 11211, 1)
>>> translate_server_spec("udp:127.0.0.1")
- (2, '127.0.0.1', 11211)
+ (2, '127.0.0.1', 11211, 1)
>>> translate_server_spec("/var/run/memcached.sock")
- (4, '/var/run/memcached.sock', 0)
+ (4, '/var/run/memcached.sock', 0, 1)
+ >>> translate_server_spec("/var/run/memcached.sock", weight=2)
+ (4, '/var/run/memcached.sock', 0, 2)
>>> translate_server_spec("127.0.0.1:22122")
- (1, '127.0.0.1', 22122)
- >>> translate_server_spec("127.0.0.1", port=1234)
- (1, '127.0.0.1', 1234)
+ (1, '127.0.0.1', 22122, 1)
+ >>> translate_server_spec("127.0.0.1:1234:2")
+ (1, '127.0.0.1', 1234, 2)
+ >>> translate_server_spec("127.0.0.1", port=1234, weight=2)
+ (1, '127.0.0.1', 1234, 2)
>>> translate_server_spec("[::1]:22122")
- (1, '::1', 22122)
+ (1, '::1', 22122, 1)
>>> translate_server_spec("[::1]")
- (1, '::1', 11211)
+ (1, '::1', 11211, 1)
+ >>> translate_server_spec("[::1]:22122:3")
+ (1, '::1', 22122, 3)
"""
(scheme, spec) = _split_spec_type(server)
stype = server_type_map[scheme]
if scheme == "unix":
(addr, port) = (spec, 0)
elif scheme in ("tcp", "udp"):
- (addr, port) = _splitport(spec, port=port)
- return (stype, str(addr), int(port))
+ (addr, port, weight) = _unpack_addr(spec, port=port, weight=weight)
+ return (stype, str(addr), int(port), int(weight))
def translate_server_specs(servers):
addr_tups = []
21 tests/test_translate.py
View
@@ -4,16 +4,29 @@
def test_translate():
eq_(translate_server_spec("111.122.133.144"),
- (_pylibmc.server_type_tcp, "111.122.133.144", 11211))
+ (_pylibmc.server_type_tcp, "111.122.133.144", 11211, 1))
def test_translate():
eq_(translate_server_spec("111.122.133.144:5555"),
- (_pylibmc.server_type_tcp, "111.122.133.144", 5555))
+ (_pylibmc.server_type_tcp, "111.122.133.144", 5555, 1))
def test_udp_translate():
eq_(translate_server_spec("udp:199.299.399.499:5555"),
- (_pylibmc.server_type_udp, "199.299.399.499", 5555))
+ (_pylibmc.server_type_udp, "199.299.399.499", 5555, 1))
def test_udp_translate_ipv6():
eq_(translate_server_spec("udp:[abcd:abcd::1]:5555"),
- (_pylibmc.server_type_udp, "abcd:abcd::1", 5555))
+ (_pylibmc.server_type_udp, "abcd:abcd::1", 5555, 1))
+
+def test_translate_with_weight_string():
+ eq_(translate_server_spec("111.122.133.144:5555:2"),
+ (_pylibmc.server_type_tcp, "111.122.133.144", 5555, 2))
+
+def test_translate_with_weight_kwd():
+ eq_(translate_server_spec("111.122.133.144", weight=2),
+ (_pylibmc.server_type_tcp, "111.122.133.144", 11211, 2))
+
+def test_udp_translate_ipv6_with_weight():
+ eq_(translate_server_spec("udp:[abcd:abcd::1]:5555:2"),
+ (_pylibmc.server_type_udp, "abcd:abcd::1", 5555, 2))
+
Please sign in to comment.
Something went wrong with that request. Please try again.