|
65 | 65 | map_set_with_max_idle_codec, |
66 | 66 | map_remove_interceptor_codec, |
67 | 67 | map_remove_all_codec, |
| 68 | + map_add_near_cache_invalidation_listener_codec, |
68 | 69 | ) |
69 | 70 | from hazelcast.internal.asyncio_proxy.base import ( |
70 | 71 | Proxy, |
@@ -971,8 +972,177 @@ def handler(message): |
971 | 972 | return self._invoke_on_key(request, key_data, handler) |
972 | 973 |
|
973 | 974 |
|
974 | | -def create_map_proxy(service_name, name, context): |
| 975 | +class MapFeatNearCache(Map[KeyType, ValueType]): |
| 976 | + """Map proxy implementation featuring Near Cache""" |
| 977 | + |
| 978 | + def __init__(self, service_name, name, context): |
| 979 | + super(MapFeatNearCache, self).__init__(service_name, name, context) |
| 980 | + self._invalidation_listener_id = None |
| 981 | + self._near_cache = context.near_cache_manager.get_or_create_near_cache(name) |
| 982 | + |
| 983 | + async def clear(self): |
| 984 | + self._near_cache._clear() |
| 985 | + return await super(MapFeatNearCache, self).clear() |
| 986 | + |
| 987 | + async def evict_all(self): |
| 988 | + self._near_cache.clear() |
| 989 | + return await super(MapFeatNearCache, self).evict_all() |
| 990 | + |
| 991 | + async def load_all(self, keys=None, replace_existing_values=True): |
| 992 | + if keys is None and replace_existing_values: |
| 993 | + self._near_cache.clear() |
| 994 | + return await super(MapFeatNearCache, self).load_all(keys, replace_existing_values) |
| 995 | + |
| 996 | + async def _on_destroy(self): |
| 997 | + await self._remove_near_cache_invalidation_listener() |
| 998 | + self._near_cache.clear() |
| 999 | + await super(MapFeatNearCache, self)._on_destroy() |
| 1000 | + |
| 1001 | + async def _add_near_cache_invalidation_listener(self): |
| 1002 | + codec = map_add_near_cache_invalidation_listener_codec |
| 1003 | + request = codec.encode_request(self.name, EntryEventType.INVALIDATION, self._is_smart) |
| 1004 | + self._invalidation_listener_id = await self._register_listener( |
| 1005 | + request, |
| 1006 | + lambda r: codec.decode_response(r), |
| 1007 | + lambda reg_id: map_remove_entry_listener_codec.encode_request(self.name, reg_id), |
| 1008 | + lambda m: codec.handle(m, self._handle_invalidation, self._handle_batch_invalidation), |
| 1009 | + ) |
| 1010 | + |
| 1011 | + async def _remove_near_cache_invalidation_listener(self): |
| 1012 | + if self._invalidation_listener_id: |
| 1013 | + await self.remove_entry_listener(self._invalidation_listener_id) |
| 1014 | + |
| 1015 | + def _handle_invalidation(self, key, source_uuid, partition_uuid, sequence): |
| 1016 | + # key is always ``Data`` |
| 1017 | + # null key means near cache has to remove all entries in it. |
| 1018 | + # see MapAddNearCacheEntryListenerMessageTask. |
| 1019 | + if key is None: |
| 1020 | + self._near_cache._clear() |
| 1021 | + else: |
| 1022 | + self._invalidate_cache(key) |
| 1023 | + |
| 1024 | + def _handle_batch_invalidation(self, keys, source_uuids, partition_uuids, sequences): |
| 1025 | + # key_list is always list of ``Data`` |
| 1026 | + for key_data in keys: |
| 1027 | + self._invalidate_cache(key_data) |
| 1028 | + |
| 1029 | + def _invalidate_cache(self, key_data): |
| 1030 | + self._near_cache._invalidate(key_data) |
| 1031 | + |
| 1032 | + def _invalidate_cache_batch(self, key_data_list): |
| 1033 | + for key_data in key_data_list: |
| 1034 | + self._near_cache._invalidate(key_data) |
| 1035 | + |
| 1036 | + # internals |
| 1037 | + async def _contains_key_internal(self, key_data): |
| 1038 | + try: |
| 1039 | + return self._near_cache[key_data] |
| 1040 | + except KeyError: |
| 1041 | + return await super(MapFeatNearCache, self)._contains_key_internal(key_data) |
| 1042 | + |
| 1043 | + async def _get_internal(self, key_data): |
| 1044 | + try: |
| 1045 | + return self._near_cache[key_data] |
| 1046 | + except KeyError: |
| 1047 | + value = await super(MapFeatNearCache, self)._get_internal(key_data) |
| 1048 | + self._near_cache.__setitem__(key_data, value) |
| 1049 | + return value |
| 1050 | + |
| 1051 | + async def _get_all_internal(self, partition_to_keys, tasks=None): |
| 1052 | + tasks = tasks or [] |
| 1053 | + for key_dic in partition_to_keys.values(): |
| 1054 | + for key in list(key_dic.keys()): |
| 1055 | + try: |
| 1056 | + key_data = key_dic[key] |
| 1057 | + value = self._near_cache[key_data] |
| 1058 | + future = asyncio.Future() |
| 1059 | + future.set_result((key, value)) |
| 1060 | + tasks.append(future) |
| 1061 | + del key_dic[key] |
| 1062 | + except KeyError: |
| 1063 | + pass |
| 1064 | + return await super(MapFeatNearCache, self)._get_all_internal(partition_to_keys, tasks) |
| 1065 | + |
| 1066 | + def _try_remove_internal(self, key_data, timeout): |
| 1067 | + self._invalidate_cache(key_data) |
| 1068 | + return super(MapFeatNearCache, self)._try_remove_internal(key_data, timeout) |
| 1069 | + |
| 1070 | + def _try_put_internal(self, key_data, value_data, timeout): |
| 1071 | + self._invalidate_cache(key_data) |
| 1072 | + return super(MapFeatNearCache, self)._try_put_internal(key_data, value_data, timeout) |
| 1073 | + |
| 1074 | + def _set_internal(self, key_data, value_data, ttl, max_idle): |
| 1075 | + self._invalidate_cache(key_data) |
| 1076 | + return super(MapFeatNearCache, self)._set_internal(key_data, value_data, ttl, max_idle) |
| 1077 | + |
| 1078 | + def _set_ttl_internal(self, key_data, ttl): |
| 1079 | + self._invalidate_cache(key_data) |
| 1080 | + return super(MapFeatNearCache, self)._set_ttl_internal(key_data, ttl) |
| 1081 | + |
| 1082 | + def _replace_internal(self, key_data, value_data): |
| 1083 | + self._invalidate_cache(key_data) |
| 1084 | + return super(MapFeatNearCache, self)._replace_internal(key_data, value_data) |
| 1085 | + |
| 1086 | + def _replace_if_same_internal(self, key_data, old_value_data, new_value_data): |
| 1087 | + self._invalidate_cache(key_data) |
| 1088 | + return super(MapFeatNearCache, self)._replace_if_same_internal( |
| 1089 | + key_data, old_value_data, new_value_data |
| 1090 | + ) |
| 1091 | + |
| 1092 | + def _remove_internal(self, key_data): |
| 1093 | + self._invalidate_cache(key_data) |
| 1094 | + return super(MapFeatNearCache, self)._remove_internal(key_data) |
| 1095 | + |
| 1096 | + def _remove_all_internal(self, predicate_data): |
| 1097 | + self._near_cache.clear() |
| 1098 | + return super(MapFeatNearCache, self)._remove_all_internal(predicate_data) |
| 1099 | + |
| 1100 | + def _remove_if_same_internal_(self, key_data, value_data): |
| 1101 | + self._invalidate_cache(key_data) |
| 1102 | + return super(MapFeatNearCache, self)._remove_if_same_internal_(key_data, value_data) |
| 1103 | + |
| 1104 | + def _put_transient_internal(self, key_data, value_data, ttl, max_idle): |
| 1105 | + self._invalidate_cache(key_data) |
| 1106 | + return super(MapFeatNearCache, self)._put_transient_internal( |
| 1107 | + key_data, value_data, ttl, max_idle |
| 1108 | + ) |
| 1109 | + |
| 1110 | + def _put_internal(self, key_data, value_data, ttl, max_idle): |
| 1111 | + self._invalidate_cache(key_data) |
| 1112 | + return super(MapFeatNearCache, self)._put_internal(key_data, value_data, ttl, max_idle) |
| 1113 | + |
| 1114 | + def _put_if_absent_internal(self, key_data, value_data, ttl, max_idle): |
| 1115 | + self._invalidate_cache(key_data) |
| 1116 | + return super(MapFeatNearCache, self)._put_if_absent_internal( |
| 1117 | + key_data, value_data, ttl, max_idle |
| 1118 | + ) |
| 1119 | + |
| 1120 | + def _load_all_internal(self, key_data_list, replace_existing_values): |
| 1121 | + self._invalidate_cache_batch(key_data_list) |
| 1122 | + return super(MapFeatNearCache, self)._load_all_internal( |
| 1123 | + key_data_list, replace_existing_values |
| 1124 | + ) |
| 1125 | + |
| 1126 | + def _execute_on_key_internal(self, key_data, entry_processor_data): |
| 1127 | + self._invalidate_cache(key_data) |
| 1128 | + return super(MapFeatNearCache, self)._execute_on_key_internal( |
| 1129 | + key_data, entry_processor_data |
| 1130 | + ) |
| 1131 | + |
| 1132 | + def _evict_internal(self, key_data): |
| 1133 | + self._invalidate_cache(key_data) |
| 1134 | + return super(MapFeatNearCache, self)._evict_internal(key_data) |
| 1135 | + |
| 1136 | + def _delete_internal(self, key_data): |
| 1137 | + self._invalidate_cache(key_data) |
| 1138 | + return super(MapFeatNearCache, self)._delete_internal(key_data) |
| 1139 | + |
| 1140 | + |
| 1141 | +async def create_map_proxy(service_name, name, context): |
975 | 1142 | near_cache_config = context.config.near_caches.get(name, None) |
976 | 1143 | if near_cache_config is None: |
977 | 1144 | return Map(service_name, name, context) |
978 | | - raise InvalidConfigurationError("near cache is not supported") |
| 1145 | + nc = MapFeatNearCache(service_name, name, context) |
| 1146 | + if nc._near_cache.invalidate_on_change: |
| 1147 | + await nc._add_near_cache_invalidation_listener() |
| 1148 | + return nc |
0 commit comments