Ejemplo n.º 1
0
class HazelcastClient(object):
    """
    Hazelcast Client.
    """
    CLIENT_ID = AtomicInteger()
    _config = None
    logger = logging.getLogger("HazelcastClient")

    def __init__(self, config=None):
        self.config = config or ClientConfig()
        self.properties = ClientProperties(self.config.get_properties())
        self.id = HazelcastClient.CLIENT_ID.get_and_increment()
        self.name = self._create_client_name()
        self._init_logger()
        self._logger_extras = {
            "client_name": self.name,
            "group_name": self.config.group_config.name
        }
        self._log_group_password_info()
        self.lifecycle = LifecycleService(self.config, self._logger_extras)
        if 'gevent' in sys.modules:
            from hazelcast.gevent_reactor import GeventReactor
            self.reactor = GeventReactor()
        else:
            from hazelcast.reactor import AsyncoreReactor
            self.reactor = AsyncoreReactor(self._logger_extras)
        self._address_providers = self._create_address_providers()
        self._address_translator = self._create_address_translator()
        self.connection_manager = ConnectionManager(
            self, self.reactor.new_connection, self._address_translator)
        self.heartbeat = Heartbeat(self)
        self.invoker = InvocationService(self)
        self.listener = ListenerService(self)
        self.cluster = ClusterService(self.config, self,
                                      self._address_providers)
        self.partition_service = PartitionService(self)
        self.proxy = ProxyManager(self)
        self.load_balancer = RandomLoadBalancer(self.cluster)
        self.serialization_service = SerializationServiceV1(
            serialization_config=self.config.serialization_config,
            properties=self.properties)
        self.transaction_manager = TransactionManager(self)
        self.lock_reference_id_generator = AtomicInteger(1)
        self.near_cache_manager = NearCacheManager(self)
        self.statistics = Statistics(self)
        self._start()

    def _start(self):
        self.reactor.start()
        try:
            self.invoker.start()
            self.cluster.start()
            self.heartbeat.start()
            self.listener.start()
            self.partition_service.start()
            self.statistics.start()
        except:
            self.reactor.shutdown()
            raise
        self.logger.info("Client started.", extra=self._logger_extras)

    def get_atomic_long(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.atomic_long.AtomicLong`.

        :param name: (str), name of the AtomicLong proxy.
        :return: (:class:`~hazelcast.proxy.atomic_long.AtomicLong`), AtomicLong proxy for the given name.
        """
        return self.proxy.get_or_create(ATOMIC_LONG_SERVICE, name)

    def get_atomic_reference(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.atomic_reference.AtomicReference`.

        :param name: (str), name of the AtomicReference proxy.
        :return: (:class:`~hazelcast.proxy.atomic_reference.AtomicReference`), AtomicReference proxy for the given name.
        """
        return self.proxy.get_or_create(ATOMIC_REFERENCE_SERVICE, name)

    def get_count_down_latch(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.count_down_latch.CountDownLatch`.

        :param name: (str), name of the CountDownLatch proxy.
        :return: (:class:`~hazelcast.proxy.count_down_latch.CountDownLatch`), CountDownLatch proxy for the given name.
        """
        return self.proxy.get_or_create(COUNT_DOWN_LATCH_SERVICE, name)

    def get_executor(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.executor.Executor`.

        :param name: (str), name of the Executor proxy.
        :return: (:class:`~hazelcast.proxy.executor.Executor`), Executor proxy for the given name.
        """
        return self.proxy.get_or_create(EXECUTOR_SERVICE, name)

    def get_flake_id_generator(self, name):
        """
        Creates or returns a cluster-wide :class:`~hazelcast.proxy.flake_id_generator.FlakeIdGenerator`.

        :param name: (str), name of the FlakeIdGenerator proxy.
        :return: (:class:`~hazelcast.proxy.flake_id_generator.FlakeIdGenerator`), FlakeIdGenerator proxy for the given name
        """
        return self.proxy.get_or_create(FLAKE_ID_GENERATOR_SERVICE, name)

    def get_id_generator(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.id_generator.IdGenerator`.

        :param name: (str), name of the IdGenerator proxy.
        :return: (:class:`~hazelcast.proxy.id_generator.IdGenerator`), IdGenerator proxy for the given name.
        """
        atomic_long = self.get_atomic_long(ID_GENERATOR_ATOMIC_LONG_PREFIX +
                                           name)
        return self.proxy.get_or_create(ID_GENERATOR_SERVICE,
                                        name,
                                        atomic_long=atomic_long)

    def get_queue(self, name):
        """
        Returns the distributed queue instance with the specified name.

        :param name: (str), name of the distributed queue.
        :return: (:class:`~hazelcast.proxy.queue.Queue`), distributed queue instance with the specified name.
        """
        return self.proxy.get_or_create(QUEUE_SERVICE, name)

    def get_list(self, name):
        """
        Returns the distributed list instance with the specified name.

        :param name: (str), name of the distributed list.
        :return: (:class:`~hazelcast.proxy.list.List`), distributed list instance with the specified name.
        """
        return self.proxy.get_or_create(LIST_SERVICE, name)

    def get_lock(self, name):
        """
        Returns the distributed lock instance with the specified name.

        :param name: (str), name of the distributed lock.
        :return: (:class:`~hazelcast.proxy.lock.Lock`), distributed lock instance with the specified name.
        """
        return self.proxy.get_or_create(LOCK_SERVICE, name)

    def get_map(self, name):
        """
        Returns the distributed map instance with the specified name.

        :param name: (str), name of the distributed map.
        :return: (:class:`~hazelcast.proxy.map.Map`), distributed map instance with the specified name.
        """
        return self.proxy.get_or_create(MAP_SERVICE, name)

    def get_multi_map(self, name):
        """
        Returns the distributed MultiMap instance with the specified name.

        :param name: (str), name of the distributed MultiMap.
        :return: (:class:`~hazelcast.proxy.multi_map.MultiMap`), distributed MultiMap instance with the specified name.
        """
        return self.proxy.get_or_create(MULTI_MAP_SERVICE, name)

    def get_pn_counter(self, name):
        """
        Returns the PN Counter instance with the specified name.

        :param name: (str), name of the PN Counter.
        :return: (:class:`~hazelcast.proxy.pn_counter.PNCounter`), the PN Counter.
        """
        return self.proxy.get_or_create(PN_COUNTER_SERVICE, name)

    def get_reliable_topic(self, name):
        """
        Returns the :class:`~hazelcast.proxy.reliable_topic.ReliableTopic` instance with the specified name.

        :param name: (str), name of the ReliableTopic.
        :return: (:class:`~hazelcast.proxy.reliable_topic.ReliableTopic`), the ReliableTopic.
        """
        return self.proxy.get_or_create(RELIABLE_TOPIC_SERVICE, name)

    def get_replicated_map(self, name):
        """
        Returns the distributed ReplicatedMap instance with the specified name.

        :param name: (str), name of the distributed ReplicatedMap.
        :return: (:class:`~hazelcast.proxy.replicated_map.ReplicatedMap`), distributed ReplicatedMap instance with the specified name.
        """
        return self.proxy.get_or_create(REPLICATED_MAP_SERVICE, name)

    def get_ringbuffer(self, name):
        """
        Returns the distributed RingBuffer instance with the specified name.

        :param name: (str), name of the distributed RingBuffer.
        :return: (:class:`~hazelcast.proxy.ringbuffer.RingBuffer`), distributed RingBuffer instance with the specified name.
        """

        return self.proxy.get_or_create(RINGBUFFER_SERVICE, name)

    def get_semaphore(self, name):
        """
        Returns the distributed Semaphore instance with the specified name.

        :param name: (str), name of the distributed Semaphore.
        :return: (:class:`~hazelcast.proxy.semaphore.Semaphore`), distributed Semaphore instance with the specified name.
        """
        return self.proxy.get_or_create(SEMAPHORE_SERVICE, name)

    def get_set(self, name):
        """
        Returns the distributed Set instance with the specified name.

        :param name: (str), name of the distributed Set.
        :return: (:class:`~hazelcast.proxy.set.Set`), distributed Set instance with the specified name.
        """
        return self.proxy.get_or_create(SET_SERVICE, name)

    def get_topic(self, name):
        """
        Returns the :class:`~hazelcast.proxy.topic.Topic` instance with the specified name.

        :param name: (str), name of the Topic.
        :return: (:class:`~hazelcast.proxy.topic.Topic`), the Topic.
        """
        return self.proxy.get_or_create(TOPIC_SERVICE, name)

    def new_transaction(self, timeout=120, durability=1, type=TWO_PHASE):
        """
        Creates a new :class:`~hazelcast.transaction.Transaction` associated with the current thread using default or given options.

        :param timeout: (long), the timeout in seconds determines the maximum lifespan of a transaction. So if a
            transaction is configured with a timeout of 2 minutes, then it will automatically rollback if it hasn't
            committed yet.
        :param durability: (int), the durability is the number of machines that can take over if a member fails during a
        transaction commit or rollback
        :param type: (Transaction Type), the transaction type which can be :const:`~hazelcast.transaction.TWO_PHASE` or :const:`~hazelcast.transaction.ONE_PHASE`
        :return: (:class:`~hazelcast.transaction.Transaction`), new Transaction associated with the current thread.
        """
        return self.transaction_manager.new_transaction(
            timeout, durability, type)

    def add_distributed_object_listener(self, listener_func):
        """
        Adds a listener which will be notified when a
        new distributed object is created or destroyed.
        :param listener_func: Function to be called when a distributed object is created or destroyed.
        :return: (str), a registration id which is used as a key to remove the listener.
        """
        return self.proxy.add_distributed_object_listener(listener_func)

    def remove_distributed_object_listener(self, registration_id):
        """
        Removes the specified distributed object listener. Returns silently if there is no such listener added before.
        :param registration_id: (str), id of registered listener.
        :return: (bool), ``true`` if registration is removed, ``false`` otherwise.
        """
        return self.proxy.remove_distributed_object_listener(registration_id)

    def get_distributed_objects(self):
        """
        Returns all distributed objects such as; queue, map, set, list, topic, lock, multimap.
        Also, as a side effect, it clears the local instances of the destroyed proxies.
        :return:(Sequence), List of instances created by Hazelcast.
        """
        request = client_get_distributed_objects_codec.encode_request()
        to_object = self.serialization_service.to_object
        future = self.invoker.invoke_on_random_target(request)
        response = client_get_distributed_objects_codec.decode_response(
            future.result(), to_object)["response"]

        distributed_objects = self.proxy.get_distributed_objects()
        local_distributed_object_infos = set()
        for dist_obj in distributed_objects:
            local_distributed_object_infos.add(
                DistributedObjectInfo(dist_obj.name, dist_obj.service_name))

        for dist_obj_info in response:
            local_distributed_object_infos.discard(dist_obj_info)
            self.proxy.get_or_create(dist_obj_info.service_name,
                                     dist_obj_info.name,
                                     create_on_remote=False)

        for dist_obj_info in local_distributed_object_infos:
            self.proxy.destroy_proxy(dist_obj_info.service_name,
                                     dist_obj_info.name,
                                     destroy_on_remote=False)

        return self.proxy.get_distributed_objects()

    def shutdown(self):
        """
        Shuts down this HazelcastClient.
        """
        if self.lifecycle.is_live:
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTTING_DOWN)
            self.near_cache_manager.destroy_all_near_caches()
            self.statistics.shutdown()
            self.partition_service.shutdown()
            self.heartbeat.shutdown()
            self.cluster.shutdown()
            self.reactor.shutdown()
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTDOWN)
            self.logger.info("Client shutdown.", extra=self._logger_extras)

    def _create_address_providers(self):
        network_config = self.config.network_config
        address_providers = []

        cloud_config = network_config.cloud_config
        cloud_address_provider = self._init_cloud_address_provider(
            cloud_config)
        if cloud_address_provider:
            address_providers.append(cloud_address_provider)

        address_providers.append(DefaultAddressProvider(network_config))
        return address_providers

    def _init_cloud_address_provider(self, cloud_config):
        if cloud_config.enabled:
            discovery_token = cloud_config.discovery_token
            host, url = HazelcastCloudDiscovery.get_host_and_url(
                self.config.get_properties(), discovery_token)
            return HazelcastCloudAddressProvider(
                host, url, self._get_connection_timeout(), self._logger_extras)

        cloud_token = self.properties.get(
            self.properties.HAZELCAST_CLOUD_DISCOVERY_TOKEN)
        if cloud_token != "":
            host, url = HazelcastCloudDiscovery.get_host_and_url(
                self.config.get_properties(), cloud_token)
            return HazelcastCloudAddressProvider(
                host, url, self._get_connection_timeout(), self._logger_extras)

        return None

    def _create_address_translator(self):
        network_config = self.config.network_config
        cloud_config = network_config.cloud_config
        cloud_discovery_token = self.properties.get(
            self.properties.HAZELCAST_CLOUD_DISCOVERY_TOKEN)

        address_list_provided = len(network_config.addresses) != 0
        if cloud_discovery_token != "" and cloud_config.enabled:
            raise HazelcastIllegalStateError(
                "Ambiguous Hazelcast.cloud configuration. "
                "Both property based and client configuration based settings are provided "
                "for Hazelcast cloud discovery together. Use only one.")

        hazelcast_cloud_enabled = cloud_discovery_token != "" or cloud_config.enabled
        self._is_discovery_configuration_consistent(address_list_provided,
                                                    hazelcast_cloud_enabled)

        if hazelcast_cloud_enabled:
            if cloud_config.enabled:
                discovery_token = cloud_config.discovery_token
            else:
                discovery_token = cloud_discovery_token
            host, url = HazelcastCloudDiscovery.get_host_and_url(
                self.config.get_properties(), discovery_token)
            return HazelcastCloudAddressTranslator(
                host, url, self._get_connection_timeout(), self._logger_extras)

        return DefaultAddressTranslator()

    def _get_connection_timeout(self):
        network_config = self.config.network_config
        conn_timeout = network_config.connection_timeout
        return sys.maxsize if conn_timeout == 0 else conn_timeout

    def _is_discovery_configuration_consistent(self, address_list_provided,
                                               hazelcast_cloud_enabled):
        count = 0
        if address_list_provided:
            count += 1
        if hazelcast_cloud_enabled:
            count += 1

        if count > 1:
            raise HazelcastIllegalStateError(
                "Only one discovery method can be enabled at a time. "
                "Cluster members given explicitly: {}"
                ", Hazelcast.cloud enabled: {}".format(
                    address_list_provided, hazelcast_cloud_enabled))

    def _create_client_name(self):
        if self.config.client_name:
            return self.config.client_name
        return "hz.client_" + str(self.id)

    def _init_logger(self):
        logger_config = self.config.logger_config
        if logger_config.config_file is not None:
            with open(logger_config.config_file, "r") as f:
                json_config = json.loads(f.read())
                logging.config.dictConfig(json_config)
        else:
            logging.config.dictConfig(DEFAULT_LOGGING)
            self.logger.setLevel(logger_config.level)

    def _log_group_password_info(self):
        if self.config.group_config.password:
            self.logger.info(
                "A non-empty group password is configured for the Hazelcast client. "
                "Starting with Hazelcast IMDG version 3.11, clients with the same group name, "
                "but with different group passwords (that do not use authentication) will be "
                "accepted to a cluster. The group password configuration will be removed "
                "completely in a future release.",
                extra=self._logger_extras)
Ejemplo n.º 2
0
class HazelcastClient(object):
    """
    Hazelcast Client.
    """
    logger = logging.getLogger("HazelcastClient")
    _config = None

    def __init__(self, config=None):
        self.config = config or ClientConfig()
        self.lifecycle = LifecycleService(self.config)
        #self.reactor = AsyncoreReactor()
        self.reactor = GeventReactor()
        self.connection_manager = ConnectionManager(
            self, self.reactor.new_connection)
        self.heartbeat = Heartbeat(self)
        self.invoker = InvocationService(self)
        self.listener = ListenerService(self)
        self.cluster = ClusterService(self.config, self)
        self.partition_service = PartitionService(self)
        self.proxy = ProxyManager(self)
        self.load_balancer = RandomLoadBalancer(self.cluster)
        self.serialization_service = SerializationServiceV1(
            serialization_config=self.config.serialization_config)
        self.transaction_manager = TransactionManager(self)
        self._start()

    def _start(self):
        self.reactor.start()
        try:
            self.cluster.start()
            self.heartbeat.start()
            self.partition_service.start()
        except:
            self.reactor.shutdown()
            raise
        self.logger.info("Client started.")

    def get_atomic_long(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.atomic_long.AtomicLong`.

        :param name: (str), name of the AtomicLong proxy.
        :return: (:class:`~hazelcast.proxy.atomic_long.AtomicLong`), AtomicLong proxy for the given name.
        """
        return self.proxy.get_or_create(ATOMIC_LONG_SERVICE, name)

    def get_atomic_reference(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.atomic_reference.AtomicReference`.

        :param name: (str), name of the AtomicReference proxy.
        :return: (:class:`~hazelcast.proxy.atomic_reference.AtomicReference`), AtomicReference proxy for the given name.
        """
        return self.proxy.get_or_create(ATOMIC_REFERENCE_SERVICE, name)

    def get_count_down_latch(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.count_down_latch.CountDownLatch`.

        :param name: (str), name of the CountDownLatch proxy.
        :return: (:class:`~hazelcast.proxy.count_down_latch.CountDownLatch`), CountDownLatch proxy for the given name.
        """
        return self.proxy.get_or_create(COUNT_DOWN_LATCH_SERVICE, name)

    def get_executor(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.executor.Executor`.

        :param name: (str), name of the Executor proxy.
        :return: (:class:`~hazelcast.proxy.executor.Executor`), Executor proxy for the given name.
        """
        return self.proxy.get_or_create(EXECUTOR_SERVICE, name)

    def get_id_generator(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.id_generator.IdGenerator`.

        :param name: (str), name of the IdGenerator proxy.
        :return: (:class:`~hazelcast.proxy.id_generator.IdGenerator`), IdGenerator proxy for the given name.
        """
        atomic_long = self.get_atomic_long(ID_GENERATOR_ATOMIC_LONG_PREFIX +
                                           name)
        return self.proxy.get_or_create(ID_GENERATOR_SERVICE,
                                        name,
                                        atomic_long=atomic_long)

    def get_queue(self, name):
        """
        Returns the distributed queue instance with the specified name.

        :param name: (str), name of the distributed queue.
        :return: (:class:`~hazelcast.proxy.queue.Queue`), distributed queue instance with the specified name.
        """
        return self.proxy.get_or_create(QUEUE_SERVICE, name)

    def get_list(self, name):
        """
        Returns the distributed list instance with the specified name.

        :param name: (str), name of the distributed list.
        :return: (:class:`~hazelcast.proxy.list.List`), distributed list instance with the specified name.
        """
        return self.proxy.get_or_create(LIST_SERVICE, name)

    def get_lock(self, name):
        """
        Returns the distributed lock instance with the specified name.

        :param name: (str), name of the distributed lock.
        :return: (:class:`~hazelcast.proxy.lock.Lock`), distributed lock instance with the specified name.
        """
        return self.proxy.get_or_create(LOCK_SERVICE, name)

    def get_map(self, name):
        """
        Returns the distributed map instance with the specified name.

        :param name: (str), name of the distributed map.
        :return: (:class:`~hazelcast.proxy.map.Map`), distributed map instance with the specified name.
        """
        return self.proxy.get_or_create(MAP_SERVICE, name)

    def get_multi_map(self, name):
        """
        Returns the distributed MultiMap instance with the specified name.

        :param name: (str), name of the distributed MultiMap.
        :return: (:class:`~hazelcast.proxy.multi_map.MultiMap`), distributed MultiMap instance with the specified name.
        """
        return self.proxy.get_or_create(MULTI_MAP_SERVICE, name)

    def get_reliable_topic(self, name):
        """
        Returns the :class:`~hazelcast.proxy.reliable_topic.ReliableTopic` instance with the specified name.

        :param name: (str), name of the ReliableTopic.
        :return: (:class:`~hazelcast.proxy.reliable_topic.ReliableTopic`), the ReliableTopic.
        """
        return self.proxy.get_or_create(RELIABLE_TOPIC_SERVICE, name)

    def get_replicated_map(self, name):
        """
        Returns the distributed ReplicatedMap instance with the specified name.

        :param name: (str), name of the distributed ReplicatedMap.
        :return: (:class:`~hazelcast.proxy.replicated_map.ReplicatedMap`), distributed ReplicatedMap instance with the specified name.
        """
        return self.proxy.get_or_create(REPLICATED_MAP_SERVICE, name)

    def get_ringbuffer(self, name):
        """
        Returns the distributed RingBuffer instance with the specified name.

        :param name: (str), name of the distributed RingBuffer.
        :return: (:class:`~hazelcast.proxy.ringbuffer.RingBuffer`), distributed RingBuffer instance with the specified name.
        """

        return self.proxy.get_or_create(RINGBUFFER_SERIVCE, name)

    def get_semaphore(self, name):
        """
        Returns the distributed Semaphore instance with the specified name.

        :param name: (str), name of the distributed Semaphore.
        :return: (:class:`~hazelcast.proxy.semaphore.Semaphore`), distributed Semaphore instance with the specified name.
        """
        return self.proxy.get_or_create(SEMAPHORE_SERVICE, name)

    def get_set(self, name):
        """
        Returns the distributed Set instance with the specified name.

        :param name: (str), name of the distributed Set.
        :return: (:class:`~hazelcast.proxy.set.Set`), distributed Set instance with the specified name.
        """
        return self.proxy.get_or_create(SET_SERVICE, name)

    def get_topic(self, name):
        """
        Returns the :class:`~hazelcast.proxy.topic.Topic` instance with the specified name.

        :param name: (str), name of the Topic.
        :return: (:class:`~hazelcast.proxy.topic.Topic`), the Topic.
        """
        return self.proxy.get_or_create(TOPIC_SERVICE, name)

    def new_transaction(self, timeout=120, durability=1, type=TWO_PHASE):
        """
        Creates a new :class:`~hazelcast.transaction.Transaction` associated with the current thread using default or given options.

        :param timeout: (long), the timeout in seconds determines the maximum lifespan of a transaction. So if a
            transaction is configured with a timeout of 2 minutes, then it will automatically rollback if it hasn't
            committed yet.
        :param durability: (int), the durability is the number of machines that can take over if a member fails during a
        transaction commit or rollback
        :param type: (Transaction Type), the transaction type which can be :const:`~hazelcast.transaction.TWO_PHASE` or :const:`~hazelcast.transaction.ONE_PHASE`
        :return: (:class:`~hazelcast.transaction.Transaction`), new Transaction associated with the current thread.
        """
        return self.transaction_manager.new_transaction(
            timeout, durability, type)

    def shutdown(self):
        """
        Shuts down this HazelcastClient.
        """
        if self.lifecycle.is_live:
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTTING_DOWN)
            self.partition_service.shutdown()
            self.heartbeat.shutdown()
            self.cluster.shutdown()
            self.reactor.shutdown()
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTDOWN)
            self.logger.info("Client shutdown.")
Ejemplo n.º 3
0
class HazelcastClient(object):
    logger = logging.getLogger("HazelcastClient")
    _config = None

    def __init__(self, config=None):
        self.config = config or ClientConfig()
        self.lifecycle = LifecycleService(self.config)
        self.reactor = AsyncoreReactor()
        self.connection_manager = ConnectionManager(self, self.reactor.new_connection)
        self.heartbeat = Heartbeat(self)
        self.invoker = InvocationService(self)
        self.listener = ListenerService(self)
        self.cluster = ClusterService(self.config, self)
        self.partition_service = PartitionService(self)
        self.proxy = ProxyManager(self)
        self.load_balancer = RandomLoadBalancer(self.cluster)
        self.serializer = SerializationServiceV1(serialization_config=self.config.serialization_config)
        self.transaction_manager = TransactionManager(self)
        self._start()

    def _start(self):
        self.reactor.start()
        try:
            self.cluster.start()
            self.heartbeat.start()
            self.partition_service.start()
        except:
            self.reactor.shutdown()
            raise
        self.logger.info("Client started.")

    def get_atomic_long(self, name):
        return self.proxy.get_or_create(ATOMIC_LONG_SERVICE, name)

    def get_atomic_reference(self, name):
        return self.proxy.get_or_create(ATOMIC_REFERENCE_SERVICE, name)

    def get_count_down_latch(self, name):
        return self.proxy.get_or_create(COUNT_DOWN_LATCH_SERVICE, name)

    def get_executor(self, name):
        return self.proxy.get_or_create(EXECUTOR_SERVICE, name)

    def get_id_generator(self, name):
        atomic_long = self.get_atomic_long(ID_GENERATOR_ATOMIC_LONG_PREFIX + name)
        return self.proxy.get_or_create(ID_GENERATOR_SERVICE, name, atomic_long=atomic_long)

    def get_queue(self, name):
        return self.proxy.get_or_create(QUEUE_SERVICE, name)

    def get_list(self, name):
        return self.proxy.get_or_create(LIST_SERVICE, name)

    def get_lock(self, name):
        return self.proxy.get_or_create(LOCK_SERVICE, name)

    def get_map(self, name):
        return self.proxy.get_or_create(MAP_SERVICE, name)

    def get_multi_map(self, name):
        return self.proxy.get_or_create(MULTI_MAP_SERVICE, name)

    def get_reliable_topic(self, name):
        return self.proxy.get_or_create(RELIABLE_TOPIC_SERVICE, name)

    def get_replicated_map(self, name):
        return self.proxy.get_or_create(REPLICATED_MAP_SERVICE, name)

    def get_ringbuffer(self, name):
        return self.proxy.get_or_create(RINGBUFFER_SERIVCE, name)

    def get_semaphore(self, name):
        return self.proxy.get_or_create(SEMAPHORE_SERVICE, name)

    def get_set(self, name):
        return self.proxy.get_or_create(SET_SERVICE, name)

    def get_topic(self, name):
        return self.proxy.get_or_create(TOPIC_SERVICE, name)

    def new_transaction(self, timeout=120, durability=1, type=TWO_PHASE):
        return self.transaction_manager.new_transaction(timeout, durability, type)

    def shutdown(self):
        if self.lifecycle.is_live:
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTTING_DOWN)
            self.partition_service.shutdown()
            self.heartbeat.shutdown()
            self.cluster.shutdown()
            self.reactor.shutdown()
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTDOWN)
            self.logger.info("Client shutdown.")
class HazelcastClient(object):
    logger = logging.getLogger("HazelcastClient")
    _config = None

    def __init__(self, config=None):
        self.config = config or ClientConfig()
        self.lifecycle = LifecycleService(self.config)
        self.reactor = AsyncoreReactor()
        self.connection_manager = ConnectionManager(
            self, self.reactor.new_connection)
        self.heartbeat = Heartbeat(self)
        self.invoker = InvocationService(self)
        self.listener = ListenerService(self)
        self.cluster = ClusterService(self.config, self)
        self.partition_service = PartitionService(self)
        self.proxy = ProxyManager(self)
        self.load_balancer = RandomLoadBalancer(self.cluster)
        self.serializer = SerializationServiceV1(
            serialization_config=self.config.serialization_config)
        self.transaction_manager = TransactionManager(self)
        self._start()

    def _start(self):
        self.reactor.start()
        try:
            self.cluster.start()
            self.heartbeat.start()
            self.partition_service.start()
        except:
            self.reactor.shutdown()
            raise
        self.logger.info("Client started.")

    def get_atomic_long(self, name):
        return self.proxy.get_or_create(ATOMIC_LONG_SERVICE, name)

    def get_atomic_reference(self, name):
        return self.proxy.get_or_create(ATOMIC_REFERENCE_SERVICE, name)

    def get_count_down_latch(self, name):
        return self.proxy.get_or_create(COUNT_DOWN_LATCH_SERVICE, name)

    def get_executor(self, name):
        return self.proxy.get_or_create(EXECUTOR_SERVICE, name)

    def get_id_generator(self, name):
        atomic_long = self.get_atomic_long(ID_GENERATOR_ATOMIC_LONG_PREFIX +
                                           name)
        return self.proxy.get_or_create(ID_GENERATOR_SERVICE,
                                        name,
                                        atomic_long=atomic_long)

    def get_queue(self, name):
        return self.proxy.get_or_create(QUEUE_SERVICE, name)

    def get_list(self, name):
        return self.proxy.get_or_create(LIST_SERVICE, name)

    def get_lock(self, name):
        return self.proxy.get_or_create(LOCK_SERVICE, name)

    def get_map(self, name):
        return self.proxy.get_or_create(MAP_SERVICE, name)

    def get_multi_map(self, name):
        return self.proxy.get_or_create(MULTI_MAP_SERVICE, name)

    def get_reliable_topic(self, name):
        return self.proxy.get_or_create(RELIABLE_TOPIC_SERVICE, name)

    def get_replicated_map(self, name):
        return self.proxy.get_or_create(REPLICATED_MAP_SERVICE, name)

    def get_ringbuffer(self, name):
        return self.proxy.get_or_create(RINGBUFFER_SERIVCE, name)

    def get_semaphore(self, name):
        return self.proxy.get_or_create(SEMAPHORE_SERVICE, name)

    def get_set(self, name):
        return self.proxy.get_or_create(SET_SERVICE, name)

    def get_topic(self, name):
        return self.proxy.get_or_create(TOPIC_SERVICE, name)

    def new_transaction(self, timeout=120, durability=1, type=TWO_PHASE):
        return self.transaction_manager.new_transaction(
            timeout, durability, type)

    def shutdown(self):
        if self.lifecycle.is_live:
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTTING_DOWN)
            self.partition_service.shutdown()
            self.heartbeat.shutdown()
            self.cluster.shutdown()
            self.reactor.shutdown()
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTDOWN)
            self.logger.info("Client shutdown.")
Ejemplo n.º 5
0
class HazelcastClient(object):
    """
    Hazelcast Client.
    """
    logger = logging.getLogger("HazelcastClient")
    _config = None

    def __init__(self, config=None):
        self.config = config or ClientConfig()
        self.properties = ClientProperties(self.config.get_properties())
        self.lifecycle = LifecycleService(self.config)
        self.reactor = AsyncoreReactor()
        self._address_providers = self._create_address_providers()
        self._address_translator = self._create_address_translator()
        self.connection_manager = ConnectionManager(
            self, self.reactor.new_connection, self._address_translator)
        self.heartbeat = Heartbeat(self)
        self.invoker = InvocationService(self)
        self.listener = ListenerService(self)
        self.cluster = ClusterService(self.config, self,
                                      self._address_providers)
        self.partition_service = PartitionService(self)
        self.proxy = ProxyManager(self)
        self.load_balancer = RandomLoadBalancer(self.cluster)
        self.serialization_service = SerializationServiceV1(
            serialization_config=self.config.serialization_config)
        self.transaction_manager = TransactionManager(self)
        self.lock_reference_id_generator = LockReferenceIdGenerator()
        self._start()

    def _start(self):
        self.reactor.start()
        try:
            self.cluster.start()
            self.heartbeat.start()
            self.partition_service.start()
        except:
            self.reactor.shutdown()
            raise
        self.logger.info("Client started.")

    def get_atomic_long(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.atomic_long.AtomicLong`.

        :param name: (str), name of the AtomicLong proxy.
        :return: (:class:`~hazelcast.proxy.atomic_long.AtomicLong`), AtomicLong proxy for the given name.
        """
        return self.proxy.get_or_create(ATOMIC_LONG_SERVICE, name)

    def get_atomic_reference(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.atomic_reference.AtomicReference`.

        :param name: (str), name of the AtomicReference proxy.
        :return: (:class:`~hazelcast.proxy.atomic_reference.AtomicReference`), AtomicReference proxy for the given name.
        """
        return self.proxy.get_or_create(ATOMIC_REFERENCE_SERVICE, name)

    def get_count_down_latch(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.count_down_latch.CountDownLatch`.

        :param name: (str), name of the CountDownLatch proxy.
        :return: (:class:`~hazelcast.proxy.count_down_latch.CountDownLatch`), CountDownLatch proxy for the given name.
        """
        return self.proxy.get_or_create(COUNT_DOWN_LATCH_SERVICE, name)

    def get_executor(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.executor.Executor`.

        :param name: (str), name of the Executor proxy.
        :return: (:class:`~hazelcast.proxy.executor.Executor`), Executor proxy for the given name.
        """
        return self.proxy.get_or_create(EXECUTOR_SERVICE, name)

    def get_id_generator(self, name):
        """
        Creates cluster-wide :class:`~hazelcast.proxy.id_generator.IdGenerator`.

        :param name: (str), name of the IdGenerator proxy.
        :return: (:class:`~hazelcast.proxy.id_generator.IdGenerator`), IdGenerator proxy for the given name.
        """
        atomic_long = self.get_atomic_long(ID_GENERATOR_ATOMIC_LONG_PREFIX +
                                           name)
        return self.proxy.get_or_create(ID_GENERATOR_SERVICE,
                                        name,
                                        atomic_long=atomic_long)

    def get_queue(self, name):
        """
        Returns the distributed queue instance with the specified name.

        :param name: (str), name of the distributed queue.
        :return: (:class:`~hazelcast.proxy.queue.Queue`), distributed queue instance with the specified name.
        """
        return self.proxy.get_or_create(QUEUE_SERVICE, name)

    def get_list(self, name):
        """
        Returns the distributed list instance with the specified name.

        :param name: (str), name of the distributed list.
        :return: (:class:`~hazelcast.proxy.list.List`), distributed list instance with the specified name.
        """
        return self.proxy.get_or_create(LIST_SERVICE, name)

    def get_lock(self, name):
        """
        Returns the distributed lock instance with the specified name.

        :param name: (str), name of the distributed lock.
        :return: (:class:`~hazelcast.proxy.lock.Lock`), distributed lock instance with the specified name.
        """
        return self.proxy.get_or_create(LOCK_SERVICE, name)

    def get_map(self, name):
        """
        Returns the distributed map instance with the specified name.

        :param name: (str), name of the distributed map.
        :return: (:class:`~hazelcast.proxy.map.Map`), distributed map instance with the specified name.
        """
        return self.proxy.get_or_create(MAP_SERVICE, name)

    def get_multi_map(self, name):
        """
        Returns the distributed MultiMap instance with the specified name.

        :param name: (str), name of the distributed MultiMap.
        :return: (:class:`~hazelcast.proxy.multi_map.MultiMap`), distributed MultiMap instance with the specified name.
        """
        return self.proxy.get_or_create(MULTI_MAP_SERVICE, name)

    def get_reliable_topic(self, name):
        """
        Returns the :class:`~hazelcast.proxy.reliable_topic.ReliableTopic` instance with the specified name.

        :param name: (str), name of the ReliableTopic.
        :return: (:class:`~hazelcast.proxy.reliable_topic.ReliableTopic`), the ReliableTopic.
        """
        return self.proxy.get_or_create(RELIABLE_TOPIC_SERVICE, name)

    def get_replicated_map(self, name):
        """
        Returns the distributed ReplicatedMap instance with the specified name.

        :param name: (str), name of the distributed ReplicatedMap.
        :return: (:class:`~hazelcast.proxy.replicated_map.ReplicatedMap`), distributed ReplicatedMap instance with the specified name.
        """
        return self.proxy.get_or_create(REPLICATED_MAP_SERVICE, name)

    def get_ringbuffer(self, name):
        """
        Returns the distributed RingBuffer instance with the specified name.

        :param name: (str), name of the distributed RingBuffer.
        :return: (:class:`~hazelcast.proxy.ringbuffer.RingBuffer`), distributed RingBuffer instance with the specified name.
        """

        return self.proxy.get_or_create(RINGBUFFER_SERIVCE, name)

    def get_semaphore(self, name):
        """
        Returns the distributed Semaphore instance with the specified name.

        :param name: (str), name of the distributed Semaphore.
        :return: (:class:`~hazelcast.proxy.semaphore.Semaphore`), distributed Semaphore instance with the specified name.
        """
        return self.proxy.get_or_create(SEMAPHORE_SERVICE, name)

    def get_set(self, name):
        """
        Returns the distributed Set instance with the specified name.

        :param name: (str), name of the distributed Set.
        :return: (:class:`~hazelcast.proxy.set.Set`), distributed Set instance with the specified name.
        """
        return self.proxy.get_or_create(SET_SERVICE, name)

    def get_topic(self, name):
        """
        Returns the :class:`~hazelcast.proxy.topic.Topic` instance with the specified name.

        :param name: (str), name of the Topic.
        :return: (:class:`~hazelcast.proxy.topic.Topic`), the Topic.
        """
        return self.proxy.get_or_create(TOPIC_SERVICE, name)

    def new_transaction(self, timeout=120, durability=1, type=TWO_PHASE):
        """
        Creates a new :class:`~hazelcast.transaction.Transaction` associated with the current thread using default or given options.

        :param timeout: (long), the timeout in seconds determines the maximum lifespan of a transaction. So if a
            transaction is configured with a timeout of 2 minutes, then it will automatically rollback if it hasn't
            committed yet.
        :param durability: (int), the durability is the number of machines that can take over if a member fails during a
        transaction commit or rollback
        :param type: (Transaction Type), the transaction type which can be :const:`~hazelcast.transaction.TWO_PHASE` or :const:`~hazelcast.transaction.ONE_PHASE`
        :return: (:class:`~hazelcast.transaction.Transaction`), new Transaction associated with the current thread.
        """
        return self.transaction_manager.new_transaction(
            timeout, durability, type)

    def shutdown(self):
        """
        Shuts down this HazelcastClient.
        """
        if self.lifecycle.is_live:
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTTING_DOWN)
            self.partition_service.shutdown()
            self.heartbeat.shutdown()
            self.cluster.shutdown()
            self.reactor.shutdown()
            self.lifecycle.fire_lifecycle_event(LIFECYCLE_STATE_SHUTDOWN)
            self.logger.info("Client shutdown.")

    def _create_address_providers(self):
        network_config = self.config.network_config
        address_providers = []

        cloud_config = network_config.cloud_config
        cloud_address_provider = self._init_cloud_address_provider(
            cloud_config)
        if cloud_address_provider:
            address_providers.append(cloud_address_provider)

        address_providers.append(DefaultAddressProvider(network_config))
        return address_providers

    def _init_cloud_address_provider(self, cloud_config):
        if cloud_config.enabled:
            discovery_token = cloud_config.discovery_token
            host, url = HazelcastCloudDiscovery.get_host_and_url(
                self.config.get_properties(), discovery_token)
            return HazelcastCloudAddressProvider(
                host, url, self._get_connection_timeout())

        cloud_token = self.properties.get(
            self.properties.HAZELCAST_CLOUD_DISCOVERY_TOKEN)
        if cloud_token != "":
            host, url = HazelcastCloudDiscovery.get_host_and_url(
                self.config.get_properties(), cloud_token)
            return HazelcastCloudAddressProvider(
                host, url, self._get_connection_timeout())

        return None

    def _create_address_translator(self):
        network_config = self.config.network_config
        cloud_config = network_config.cloud_config
        cloud_discovery_token = self.properties.get(
            self.properties.HAZELCAST_CLOUD_DISCOVERY_TOKEN)

        address_list_provided = len(network_config.addresses) != 0
        if cloud_discovery_token != "" and cloud_config.enabled:
            raise HazelcastIllegalStateError(
                "Ambiguous Hazelcast.cloud configuration. "
                "Both property based and client configuration based settings are provided "
                "for Hazelcast cloud discovery together. Use only one.")

        hazelcast_cloud_enabled = cloud_discovery_token != "" or cloud_config.enabled
        self._is_discovery_configuration_consistent(address_list_provided,
                                                    hazelcast_cloud_enabled)

        if hazelcast_cloud_enabled:
            if cloud_config.enabled:
                discovery_token = cloud_config.discovery_token
            else:
                discovery_token = cloud_discovery_token
            host, url = HazelcastCloudDiscovery.get_host_and_url(
                self.config.get_properties(), discovery_token)
            return HazelcastCloudAddressTranslator(
                host, url, self._get_connection_timeout())

        return DefaultAddressTranslator()

    def _get_connection_timeout(self):
        network_config = self.config.network_config
        conn_timeout = network_config.connection_timeout
        return sys.maxsize if conn_timeout == 0 else conn_timeout

    def _is_discovery_configuration_consistent(self, address_list_provided,
                                               hazelcast_cloud_enabled):
        count = 0
        if address_list_provided:
            count += 1
        if hazelcast_cloud_enabled:
            count += 1

        if count > 1:
            raise HazelcastIllegalStateError(
                "Only one discovery method can be enabled at a time. "
                "Cluster members given explicitly: {}"
                ", Hazelcast.cloud enabled: {}".format(
                    address_list_provided, hazelcast_cloud_enabled))