diff options
author | Andy McCurdy <andy@andymccurdy.com> | 2020-02-25 13:25:25 -0800 |
---|---|---|
committer | Andy McCurdy <andy@andymccurdy.com> | 2020-02-25 13:25:25 -0800 |
commit | e57daf554d6a4a66373de6605d13fb7a185852e9 (patch) | |
tree | ae39d655d6da1f55493ba81fbcd5bb3fdd1c0999 | |
parent | 3310fe415a4c3a6ec9a9fcaf9a9fa24808219429 (diff) | |
download | redis-py-e57daf554d6a4a66373de6605d13fb7a185852e9.tar.gz |
add support for the MEMORY STATS command
Fixes #1268
-rwxr-xr-x | redis/client.py | 34 | ||||
-rw-r--r-- | tests/test_commands.py | 11 |
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) |