diff options
Diffstat (limited to 'pymemcache/client')
-rw-r--r-- | pymemcache/client/base.py | 64 | ||||
-rw-r--r-- | pymemcache/client/hash.py | 26 |
2 files changed, 83 insertions, 7 deletions
diff --git a/pymemcache/client/base.py b/pymemcache/client/base.py index 04ae052..252e860 100644 --- a/pymemcache/client/base.py +++ b/pymemcache/client/base.py @@ -688,6 +688,23 @@ class Client: key, default ) + def gat(self, key: Key, expire: int = 0, default: Optional[Any] = None) -> Any: + """ + The memcached "gat" command, but only for one key, as a convenience. + + Args: + key: str, see class docs for details. + expire: optional int, number of seconds until the item is expired + from the cache, or zero for no expiry (the default). + default: value that will be returned if the key was not found. + + Returns: + The value for the key, or default if the key wasn't found. + """ + return self._fetch_cmd( + b"gat", [key], False, key_prefix=self.key_prefix, expire=expire + ).get(key, default) + def get_many(self, keys: Iterable[Key]) -> Dict[Key, Any]: """ The memcached "get" command. @@ -727,6 +744,28 @@ class Client: key, defaults ) + def gats( + self, key: Key, expire: int = 0, default: Any = None, cas_default: Any = None + ) -> Tuple[Any, Any]: + """ + The memcached "gats" command, but only for one key, as a convenience. + + Args: + key: str, see class docs for details. + expire: optional int, number of seconds until the item is expired + from the cache, or zero for no expiry (the default). + default: value that will be returned if the key was not found. + cas_default: same behaviour as default argument. + + Returns: + A tuple of (value, cas) + or (default, cas_defaults) if the key was not found. + """ + defaults = (default, cas_default) + return self._fetch_cmd( + b"gats", [key], True, key_prefix=self.key_prefix, expire=expire + ).get(key, defaults) + def gets_many(self, keys: Iterable[Key]) -> Dict[Key, Tuple[Any, Any]]: """ The memcached "gets" command. @@ -1118,12 +1157,17 @@ class Client: keys: Iterable[Key], expect_cas: bool, key_prefix: bytes = b"", + expire: Optional[int] = None, ) -> Dict[Key, Any]: prefixed_keys = [self.check_key(k, key_prefix=key_prefix) for k in keys] remapped_keys = dict(zip(prefixed_keys, keys)) # It is important for all keys to be listed in their original order. cmd = name + if expire is not None: + expire_bytes = self._check_integer(expire, "expire") + cmd += b" " + expire_bytes + if prefixed_keys: cmd += b" " + b" ".join(prefixed_keys) cmd += b"\r\n" @@ -1498,6 +1542,26 @@ class PooledClient: else: raise + def gat(self, key: Key, expire: int = 0, default: Optional[Any] = None) -> Any: + with self.client_pool.get_and_release(destroy_on_fail=True) as client: + try: + return client.gat(key, expire, default) + except Exception: + if self.ignore_exc: + return default + else: + raise + + def gats(self, key: Key, expire: int = 0, default: Optional[Any] = None) -> Any: + with self.client_pool.get_and_release(destroy_on_fail=True) as client: + try: + return client.gats(key, expire, default) + except Exception: + if self.ignore_exc: + return default + else: + raise + def get_many(self, keys: Iterable[Key]) -> Dict[Key, Any]: with self.client_pool.get_and_release(destroy_on_fail=True) as client: try: diff --git a/pymemcache/client/hash.py b/pymemcache/client/hash.py index e56517f..aec4090 100644 --- a/pymemcache/client/hash.py +++ b/pymemcache/client/hash.py @@ -170,18 +170,24 @@ class HashClient: self._last_dead_check_time = current_time def _get_client(self, key): - check_key_helper(key, self.allow_unicode_keys, self.key_prefix) + # If key is tuple use first item as server key + if isinstance(key, tuple) and len(key) == 2: + server_key, key = key + else: + server_key = key + + check_key_helper(server_key, self.allow_unicode_keys, self.key_prefix) if self._dead_clients: self._retry_dead() - server = self.hasher.get_node(key) + server = self.hasher.get_node(server_key) # We've ran out of servers to try if server is None: if self.ignore_exc is True: - return + return None, key raise MemcacheError("All servers seem to be down right now") - return self.clients[server] + return self.clients[server], key def _safely_run_func(self, client, func, default_val, *args, **kwargs): try: @@ -311,7 +317,7 @@ class HashClient: self._failed_clients[server] = failed_metadata def _run_cmd(self, cmd, key, default_val, *args, **kwargs): - client = self._get_client(key) + client, key = self._get_client(key) if client is None: return default_val @@ -346,6 +352,12 @@ class HashClient: def get(self, key, default=None, **kwargs): return self._run_cmd("get", key, default, default=default, **kwargs) + def gat(self, key, default=None, **kwargs): + return self._run_cmd("gat", key, default, default=default, **kwargs) + + def gats(self, key, default=None, **kwargs): + return self._run_cmd("gats", key, default, default=default, **kwargs) + def incr(self, key, *args, **kwargs): return self._run_cmd("incr", key, False, *args, **kwargs) @@ -357,7 +369,7 @@ class HashClient: failed = [] for key, value in values.items(): - client = self._get_client(key) + client, key = self._get_client(key) if client is None: failed.append(key) @@ -378,7 +390,7 @@ class HashClient: end = {} for key in keys: - client = self._get_client(key) + client, key = self._get_client(key) if client is None: continue |