summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy McCurdy <andy@andymccurdy.com>2020-02-25 13:25:25 -0800
committerAndy McCurdy <andy@andymccurdy.com>2020-02-25 13:25:25 -0800
commite57daf554d6a4a66373de6605d13fb7a185852e9 (patch)
treeae39d655d6da1f55493ba81fbcd5bb3fdd1c0999
parent3310fe415a4c3a6ec9a9fcaf9a9fa24808219429 (diff)
downloadredis-py-e57daf554d6a4a66373de6605d13fb7a185852e9.tar.gz
add support for the MEMORY STATS command
Fixes #1268
-rwxr-xr-xredis/client.py34
-rw-r--r--tests/test_commands.py11
2 files changed, 42 insertions, 3 deletions
diff --git a/redis/client.py b/redis/client.py
index 9cb60f5..10ba979 100755
--- a/redis/client.py
+++ b/redis/client.py
@@ -158,6 +158,19 @@ def parse_info(response):
return info
+def parse_memory_stats(response, **kwargs):
+ "Parse the results of MEMORY STATS"
+ stats = pairs_to_dict(response,
+ decode_keys=True,
+ decode_string_values=True)
+ for key, value in iteritems(stats):
+ if key.startswith('db.'):
+ stats[key] = pairs_to_dict(value,
+ decode_keys=True,
+ decode_string_values=True)
+ return stats
+
+
SENTINEL_STATE_TYPES = {
'can-failover-its-master': int,
'config-epoch': int,
@@ -217,14 +230,24 @@ def parse_sentinel_get_master(response):
return response and (response[0], int(response[1])) or None
-def pairs_to_dict(response, decode_keys=False):
+def nativestr_if_bytes(value):
+ return nativestr(value) if isinstance(value, bytes) else value
+
+
+def pairs_to_dict(response, decode_keys=False, decode_string_values=False):
"Create a dict given a list of key/value pairs"
if response is None:
return {}
- if decode_keys:
+ if decode_keys or decode_string_values:
# the iter form is faster, but I don't know how to make that work
# with a nativestr() map
- return dict(izip(imap(nativestr, response[::2]), response[1::2]))
+ keys = response[::2]
+ if decode_keys:
+ keys = imap(nativestr, keys)
+ values = response[1::2]
+ if decode_string_values:
+ values = imap(nativestr_if_bytes, values)
+ return dict(izip(keys, values))
else:
it = iter(response)
return dict(izip(it, it))
@@ -598,6 +621,7 @@ class Redis(object):
'INFO': parse_info,
'LASTSAVE': timestamp_to_datetime,
'MEMORY PURGE': bool_ok,
+ 'MEMORY STATS': parse_memory_stats,
'MEMORY USAGE': int_or_none,
'OBJECT': parse_object,
'PING': lambda r: nativestr(r) == 'PONG',
@@ -1328,6 +1352,10 @@ class Redis(object):
"Return the encoding, idletime, or refcount about the key"
return self.execute_command('OBJECT', infotype, key, infotype=infotype)
+ def memory_stats(self):
+ "Return a dictionary of memory stats"
+ return self.execute_command('MEMORY STATS')
+
def memory_usage(self, key, samples=None):
"""
Return the total memory usage for key, its value and associated
diff --git a/tests/test_commands.py b/tests/test_commands.py
index 7f1e33e..fc85b5f 100644
--- a/tests/test_commands.py
+++ b/tests/test_commands.py
@@ -2600,6 +2600,17 @@ class TestRedisCommands(object):
assert resp == [0, None, 255]
@skip_if_server_version_lt('4.0.0')
+ def test_memory_stats(self, r):
+ # put a key into the current db to make sure that "db.<current-db>"
+ # has data
+ r.set('foo', 'bar')
+ stats = r.memory_stats()
+ assert isinstance(stats, dict)
+ for key, value in iteritems(stats):
+ if key.startswith('db.'):
+ assert isinstance(value, dict)
+
+ @skip_if_server_version_lt('4.0.0')
def test_memory_usage(self, r):
r.set('foo', 'bar')
assert isinstance(r.memory_usage('foo'), int)