From 77cdc417279c1cff406a781ea20fd1ae7ec11d30 Mon Sep 17 00:00:00 2001 From: Yunus Emre Inci Date: Mon, 31 Aug 2020 22:51:36 +0300 Subject: [PATCH 1/2] Implement map.set_ttl --- hazelcast/protocol/codec/map_message_type.py | 1 + hazelcast/protocol/codec/map_set_ttl_codec.py | 40 +++++++++++++++++++ hazelcast/proxy/map.py | 23 +++++++++-- tests/proxy/map_test.py | 9 +++++ 4 files changed, 69 insertions(+), 4 deletions(-) create mode 100644 hazelcast/protocol/codec/map_set_ttl_codec.py diff --git a/hazelcast/protocol/codec/map_message_type.py b/hazelcast/protocol/codec/map_message_type.py index 09e76a5e36..4bfef44322 100644 --- a/hazelcast/protocol/codec/map_message_type.py +++ b/hazelcast/protocol/codec/map_message_type.py @@ -55,3 +55,4 @@ MAP_VALUESWITHPAGINGPREDICATE = 0x0139 MAP_ENTRIESWITHPAGINGPREDICATE = 0x013a MAP_CLEARNEARCACHE = 0x013b +MAP_SETTTL = 0x0149 diff --git a/hazelcast/protocol/codec/map_set_ttl_codec.py b/hazelcast/protocol/codec/map_set_ttl_codec.py new file mode 100644 index 0000000000..e3691c7616 --- /dev/null +++ b/hazelcast/protocol/codec/map_set_ttl_codec.py @@ -0,0 +1,40 @@ +from hazelcast.serialization.bits import * +from hazelcast.protocol.client_message import ClientMessage +from hazelcast.protocol.custom_codec import * +from hazelcast.util import ImmutableLazyDataList +from hazelcast.protocol.codec.map_message_type import * + +REQUEST_TYPE = MAP_SETTTL +RESPONSE_TYPE = 101 +RETRYABLE = False + + +def calculate_size(name, key, ttl): + """ Calculates the request payload size""" + data_size = 0 + data_size += calculate_size_str(name) + data_size += calculate_size_data(key) + data_size += LONG_SIZE_IN_BYTES + return data_size + + +def encode_request(name, key, ttl): + """ Encode request into client_message""" + client_message = ClientMessage(payload_size=calculate_size(name, key, ttl)) + client_message.set_message_type(REQUEST_TYPE) + client_message.set_retryable(RETRYABLE) + client_message.append_str(name) + client_message.append_data(key) + client_message.append_long(ttl) + client_message.update_frame_length() + return client_message + + +def decode_response(client_message, to_object=None): + """ Decode response from client message""" + parameters = dict(response=None) + parameters['response'] = client_message.read_bool() + return parameters + + + diff --git a/hazelcast/proxy/map.py b/hazelcast/proxy/map.py index 057bb61cfc..deabfeb369 100644 --- a/hazelcast/proxy/map.py +++ b/hazelcast/proxy/map.py @@ -10,10 +10,10 @@ map_is_locked_codec, map_key_set_codec, map_key_set_with_predicate_codec, map_load_all_codec, \ map_load_given_keys_codec, map_lock_codec, map_put_codec, map_put_all_codec, map_put_if_absent_codec, \ map_put_transient_codec, map_size_codec, map_remove_codec, map_remove_if_same_codec, \ - map_remove_entry_listener_codec, map_replace_codec, map_replace_if_same_codec, map_set_codec, map_try_lock_codec, \ - map_try_put_codec, map_try_remove_codec, map_unlock_codec, map_values_codec, map_values_with_predicate_codec, \ - map_add_interceptor_codec, map_execute_on_all_keys_codec, map_execute_on_key_codec, map_execute_on_keys_codec, \ - map_execute_with_predicate_codec, map_add_near_cache_entry_listener_codec + map_remove_entry_listener_codec, map_replace_codec, map_replace_if_same_codec, map_set_codec, map_set_ttl_codec, \ + map_try_lock_codec, map_try_put_codec, map_try_remove_codec, map_unlock_codec, map_values_codec, \ + map_values_with_predicate_codec, map_add_interceptor_codec, map_execute_on_all_keys_codec, map_execute_on_key_codec, \ + map_execute_on_keys_codec, map_execute_with_predicate_codec, map_add_near_cache_entry_listener_codec from hazelcast.proxy.base import Proxy, EntryEvent, EntryEventType, get_entry_listener_flags, MAX_SIZE from hazelcast.util import check_not_none, thread_id, to_millis from hazelcast import six @@ -725,6 +725,21 @@ def set(self, key, value, ttl=-1): value_data = self._to_data(value) return self._set_internal(key_data, value_data, ttl) + def set_ttl(self, key, ttl): + """ + Updates the TTL (time to live) value of the entry specified by the given key with a new TTL value. New TTL + value is valid starting from the time this operation is invoked, not since the time the entry was created. + If the entry does not exist or is already expired, this call has no effect. + + :param key: (object), the key of the map entry. + :param ttl: (int), maximum time for this entry to stay in the map (0 means infinite, + negative means map config default) + """ + check_not_none(key, "key can't be None") + check_not_none(ttl, "ttl can't be None") + key_data = self._to_data(key) + return self._encode_invoke_on_key(map_set_ttl_codec, key_data, key=key_data, ttl=to_millis(ttl)) + def size(self): """ Returns the number of entries in this map. diff --git a/tests/proxy/map_test.py b/tests/proxy/map_test.py index c05272454f..778112aa23 100644 --- a/tests/proxy/map_test.py +++ b/tests/proxy/map_test.py @@ -437,6 +437,15 @@ def test_set(self): self.map.set("key", "value") self.assertEqual(self.map.get("key"), "value") + + def test_set_ttl(self): + self.map.put("key", "value") + self.map.set_ttl("key", 0.1) + + def evicted(): + self.assertFalse(self.map.contains_key("key")) + + self.assertTrueEventually(evicted, 1) def test_size(self): self._fill_map() From c6da1a0e1e097e8a008f8aa6fd4293c5eb240722 Mon Sep 17 00:00:00 2001 From: Yunus Emre Inci Date: Tue, 1 Sep 2020 10:41:02 +0300 Subject: [PATCH 2/2] invalidate nearcache on set_ttl --- hazelcast/proxy/map.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hazelcast/proxy/map.py b/hazelcast/proxy/map.py index deabfeb369..14ddd457dc 100644 --- a/hazelcast/proxy/map.py +++ b/hazelcast/proxy/map.py @@ -738,7 +738,7 @@ def set_ttl(self, key, ttl): check_not_none(key, "key can't be None") check_not_none(ttl, "ttl can't be None") key_data = self._to_data(key) - return self._encode_invoke_on_key(map_set_ttl_codec, key_data, key=key_data, ttl=to_millis(ttl)) + return self._set_ttl_internal(key_data, ttl) def size(self): """ @@ -876,6 +876,9 @@ def _set_internal(self, key_data, value_data, ttl): return self._encode_invoke_on_key(map_set_codec, key_data, key=key_data, value=value_data, thread_id=thread_id(), ttl=to_millis(ttl)) + def _set_ttl_internal(self, key_data, ttl): + return self._encode_invoke_on_key(map_set_ttl_codec, key_data, key=key_data, ttl=to_millis(ttl)) + def _try_remove_internal(self, key_data, timeout): return self._encode_invoke_on_key(map_try_remove_codec, key_data, key=key_data, thread_id=thread_id(), timeout=to_millis(timeout)) @@ -1022,6 +1025,10 @@ def _set_internal(self, key_data, value_data, ttl): self._invalidate_cache(key_data) return super(MapFeatNearCache, self)._set_internal(key_data, value_data, ttl) + def _set_ttl_internal(self, key_data, ttl): + self._invalidate_cache(key_data) + return super(MapFeatNearCache, self)._set_ttl_internal(key_data, ttl) + def _replace_internal(self, key_data, value_data): self._invalidate_cache(key_data) return super(MapFeatNearCache, self)._replace_internal(key_data, value_data)