예제 #1
0
    def __init__(self, conf_dict):
        """
        Init
        :param conf_dict: dict
        :type conf_dict: dict
        """

        Meters.aii("k.db_pool.mysql.call.__init")

        # Base
        super(MysqlConnectionPool, self).__init__(conf_dict)

        # Init us
        self.host_status = dict()

        # Check
        if "hosts" not in self.conf_dict and "host" not in self.conf_dict and "unix" not in self.conf_dict:
            raise Exception(
                "No server specified (hosts, host, unix not found in conf_dict"
            )

        # Init, "hosts" first
        if "hosts" in self.conf_dict:
            for host in self.conf_dict["hosts"]:
                self.host_status[host] = 0.0
        elif "host" in self.conf_dict:
            logger.warning(
                "Using deprecated entry, prefer using 'hosts', got host=%s",
                self.conf_dict["host"])
            for host in self.conf_dict["host"].split(","):
                self.host_status[host] = 0.0
        elif "unix" in self.conf_dict:
            for host in self.conf_dict["unix"].split(","):
                self.host_status[host] = 0.0
예제 #2
0
    def _protocol_client_hello_server_reply(self, item):
        """
        Received a hello reply
        :param item: Received server reply ("C.HI.REPLY PID=...")

        """

        with self._protocol_lock:
            # Parse it
            self._server_pid = item.replace("C.HI.REPLY PID=", "")

            # Unschedule timeout
            self._unschedule_client_helloservertimeout()

            # Stats
            Meters.aii("ping.client.client_hello_server_reply")

            # Delay
            ms = SolBase.datediff(self.dt_hello_send)

            # Stats
            Meters.dtci("ping.client.delay_client_hello_toserver_reply", ms)

            # Initiate the ping loop, with random start
            self._schedule_clientping(True)
예제 #3
0
    def _protocol_client_ping_send(self):
        """
        Must send a client ping

        """
        with self._protocol_lock:
            # Reset (we are called by it)
            self._ping_greenlet = None

            # Schedule a timeout
            self._schedule_client_pingservertimeout()

            # Timestamp
            self.dt_last_ping_send = SolBase.datecurrent()

            # Send a ping
            b = self.send_unicode_to_socket("C.PING")
            if not b:
                # Stat
                logger.error("send failed, fatal, disconnecting")
                Meters.aii("ping.client.client_send_error")
                # Disconnect
                self.disconnect()
            else:
                # Stats
                Meters.aii("ping.client.client_ping_sent")
예제 #4
0
    def send_binary_to_socket_with_signal(self, signaled_buffer):
        """
        Send to socket, asynch.
        Upon completion, signaled_buffer.send_event is set.
        Caution : Caller MUST check the boolean returned. If False, the event will NOT be set.
        :param signaled_buffer: A signaled_buffer instance.
        :type signaled_buffer: pysoltcp.tcpbase.SignaledBuffer.SignaledBuffer
        :return: True is send has been scheduled, false otherwise.
        :rtype bool
        """

        # Check
        if not isinstance(signaled_buffer, SignaledBuffer):
            logger.error("signaled_buffer not a SignaledBuffer, class=%s, self=%s", SolBase.get_classname(signaled_buffer), self)
            return False

            # Check
        if not isinstance(signaled_buffer.binary_buffer, binary_type):
            logger.error("binary_buffer not a binary, class=%s, self=%s", SolBase.get_classname(signaled_buffer.binary_buffer), self)
            return False

        # Check
        if not self.__is_running():
            logger.debug(
                "not connected, returning false, self=%s",
                self)
            return False

        # Enqueue
        self.__send_queue.put(signaled_buffer)

        # Stats
        Meters.aii("tcp.server.server_bytes_send_pending", len(signaled_buffer.binary_buffer))

        return True
예제 #5
0
    def connect(self):
        """
        Connect to server.
        :return Return true upon success.
        """

        # Stats
        Meters.aii("ping.client.client_connect_count")

        # Call base
        dt_start = SolBase.datecurrent()
        b = TcpSimpleClient.connect(self)
        if not b:
            # Stat
            logger.error("PingSimpleClient : connect failed, fatal, exiting")
            Meters.aii("ping.client.client_connect_error")

            # Exit
            return False

        # Stat
        Meters.dtci("ping.client.delay_client_connect",
                    SolBase.datediff(dt_start))

        # SSL stats
        ms = self._get_ssl_handshake_ms()
        if ms:
            Meters.dtci("ping.client.delay_client_sslhandshake", ms)

        # Send hello
        self._protocol_client_hello_send()
        return True
예제 #6
0
    def __on_ssl_timeout(self):
        """
        Called when SSL timeout.
        """

        # Reset first (in LOCK)
        with self.__ssl_locker:
            self.__ssl_timeout_greenlet = None

        # Process (outside of LOCK, high level may call _unschedule_ssl_handshake_timeout in lock)
        logger.debug("__on_ssl_timeout, self=%s", self)

        # Check
        if not self.__ssl_handshake_pending:
            # Done, exit
            return
        elif not self.__is_running():
            # Not connected, exit
            return

        # Not done, FATAL
        logger.warning("handshake timeout, fatal, ms=%s, self=%s", self.__ssl_handshake_timeout_ms, self)

        # Stat
        Meters.aii("tcp.server.ssl_handshake_timeout_count")

        # Timeout, Fatal, exit now
        self._disconnect_helper("__on_ssl_timeout")
예제 #7
0
    def _connection_ping(self, conn):
        """
        Ping connection

        This send a ping, write/read toward mysql.

        :param conn: pymysql.connections.Connection
        :type conn: pymysql.connections.Connection
        :return bool
        :rtype bool
        """

        Meters.aii("k.db_pool.mysql.call._connection_ping")

        # noinspection PyBroadException
        try:
            # TODO : PING MODE MUST BE CONFIGURABLE
            conn.ping(reconnect=False)
        except Exception as e:
            Meters.aii("k.db_pool.mysql.ex_ping")
            logger.debug("Ping failed, obj=%s, ex=%s", conn,
                         SolBase.extostr(e))
            return False
        else:
            return True
예제 #8
0
    def handle(self, data, address):
        """
        Handle one udp message
        :param data: data
        :type data: str
        :param address: address
        :type address: str
        """

        ms_start = SolBase.mscurrent()
        try:
            # Handle data
            pass

            # Stats
            Meters.aii("resolvusclient_udp_recv")
        except Exception as e:
            # Log
            logger.warning(
                "Handle failed, data_len=%s, address=%s, data=%s, ex=%s",
                len(data), repr(address), repr(data), SolBase.extostr(e))

            # Stat
            Meters.aii("resolvusclient_udp_recv_ex")
        finally:
            Meters.dtci("resolvusclient_udp_recv_dtc",
                        SolBase.msdiff(ms_start))
예제 #9
0
    def start(self):
        """
        Connect to server.
        :return Return true upon success.
        """

        # Timestamp
        self.dtClientConnect = SolBase.datecurrent()

        # Call base
        b = TcpServerQueuedClientContext.start(self)
        if not b:
            # Stat
            logger.error("start failed, fatal, exiting")
            Meters.aii("ping.server.serverStartError")

            # Exit
            return False

        # Stat
        Meters.aii("ping.server.serverStartCount")

        # Schedule an hello timeout
        self._schedule_client_hello_timeout()
        return True
예제 #10
0
    def _protocol_server_ping_client_reply(self):
        """
        A client ping has been replied

        """

        with self._protocolLock:
            # Must have a timeout ongoing
            if self._pingTimeOutGreenlet is None:
                # Ping reply received without ongoing ping
                Meters.aii(
                    "ping.server.serverPingServerClientReplyNoPingOngoing")
            else:
                # Unschedule the timeout
                self._unschedule_server_ping_client_timeout()

                # Reschedule a ping
                self._schedule_server_ping()

                # Stats
                Meters.aii("ping.server.serverPingClientReply")

                # Delay
                Meters.dtci("ping.server.client_ping_server_reply",
                            SolBase.datediff(self.dtLastPingSend))
예제 #11
0
    def _protocol_server_ping_send(self):
        """
        Must send a client ping

        """
        with self._protocolLock:
            # Reset (we are called by it)
            self._pingGreenlet = None

            # Schedule a timeout
            self._schedule_server_ping_client_timeout()

            # Timestamp
            self.dtLastPingSend = SolBase.datecurrent()

            # Send a ping
            b = self.send_unicode_to_socket("S.PING")
            if not b:
                # Stat
                logger.error("send failed, fatal, disconnecting")
                Meters.aii("ping.server.serverSendError")
                # Disconnect
                self.stop_asynch()
            else:
                # Stats
                Meters.aii("ping.server.serverPingSent")
예제 #12
0
    def send_binary_to_socket(self, buffer_to_send):
        """
        Send to socket, asynch.
        :param buffer_to_send: The localBuffer to send (bytes)
        :type buffer_to_send: bytes
        :return: True is send has been scheduled, false otherwise.
        :rtype bool
        """

        # Check
        if not isinstance(buffer_to_send, binary_type):
            logger.error("buffer_to_send not a binary, class=%s, self=%s", SolBase.get_classname(buffer_to_send), self)
            return False

        # Check
        if not self.__is_running():
            logger.debug("not connected, returning false, self=%s", self)
            return False

        # Enqueue
        self.__send_queue.put(buffer_to_send)

        # Stats
        Meters.aii("tcp.server.server_bytes_send_pending", len(buffer_to_send))

        return True
예제 #13
0
    def _protocol_client_ping_server_reply(self):
        """
        A client ping has been replied

        """

        with self._protocol_lock:
            # Must have a timeout ongoing
            if self._ping_timeout_greenlet is None:
                # Ping reply received without ongoing ping
                Meters.aii(
                    "ping.client.client_ping_server_reply_noping_ongoing")
            else:
                # Unschedule the timeout
                self._unschedule_client_pingservertimeout()

                # Reschedule a ping
                self._schedule_clientping()

                # Stats
                Meters.aii("ping.client.client_ping_server_reply")

                # Delay and stats
                Meters.dtci("ping.client.delay_client_ping_toserver_reply",
                            SolBase.datediff(self.dt_last_ping_send))
예제 #14
0
    def _schedule_clientping(self, randomize_delay=False):
        """
        Schedule a ping
        :param randomize_delay: Randomize delay if true.

        """
        with self._protocol_lock:
            # Check
            if self._ping_greenlet:
                logger.warning(
                    "PingSimpleClient : _schedule_clientping : _ping_greenlet is not None, killing"
                )
                Meters.aii("ping.client.schedule_client_ping_error")
                self._unschedule_client_ping()

            # Go
            if not randomize_delay:
                self._ping_greenlet = gevent.spawn_later(
                    self._ping_interval_ms * 0.001,
                    self._protocol_client_ping_send)
            else:
                # Randomize delay
                vmin = self._ping_interval_ms / 2
                vmax = self._ping_interval_ms
                ms = randint(vmin, vmax)
                self._ping_greenlet = gevent.spawn_later(
                    ms * 0.001, self._protocol_client_ping_send)
예제 #15
0
    def close_all(self):
        """
        Close all connections
        """
        n = 0
        while not self.pool.empty():
            conn = self.pool.get_nowait()
            self._connection_close(conn)
            n += 1

        Meters.aii("k.db_pool.base.cur_size", increment_value=-n)
        Meters.ai("k.db_pool.base.max_size").set(max(Meters.aig("k.db_pool.base.max_size"), Meters.aig("k.db_pool.base.cur_size")))
        self.size = 0
예제 #16
0
    def _protocol_client_hello_received(self):
        """
        Must send a hello

        """
        with self._protocolLock:
            # Un-schedule hello timeout
            self._unschedule_client_hello_timeout()

            # Stats
            Meters.aii("ping.server.clientHelloReceived")

            # Delay
            Meters.aii("ping.server.delayClientConnectToClientHello",
                       SolBase.datediff(self.dtClientConnect))

            # Send a reply
            b = self.send_unicode_to_socket("C.HI.REPLY PID={0}".format(
                os.getpid()))
            if not b:
                # Stat
                logger.error("send failed, fatal, disconnecting")
                Meters.aii("ping.server.serverSendError")

                # Disconnect
                self.stop_asynch()
            else:
                # Now connected, schedule a ping
                self._schedule_server_ping()

                # Stats
                Meters.aii("ping.server.client_hello_server_reply")
예제 #17
0
    def _schedule_client_hello_timeout(self):
        """
        Schedule a ping timeout

        """

        with self._protocolLock:
            # Check
            if self._helloTimeOutGreenlet:
                logger.warning("_helloTimeOutGreenlet is not None, killing")
                Meters.aii("ping.server.scheduleClientHelloTimeOutError")
                self._unschedule_client_hello_timeout()
                # Go
            self._helloTimeOutGreenlet = gevent.spawn_later(
                self._helloTimeOutMs * 0.001,
                self._protocol_context_client_hello_timeout)
예제 #18
0
    def _schedule_client_pingservertimeout(self):
        """
        Schedule a ping timeout

        """

        with self._protocol_lock:
            # Check
            if self._ping_timeout_greenlet:
                logger.warning("_ping_timeout_greenlet is not None, killing")
                Meters.aii("ping.client.schedule_client_pingtimeouterror")
                self._unschedule_client_pingservertimeout()
                # Go
            self._ping_timeout_greenlet = gevent.spawn_later(
                self._ping_timeout_ms * 0.001,
                self._protocol_client_pingserver_timeout)
예제 #19
0
    def disconnect(self):
        """
        Disconnect from server.
        :return Return true upon success.
        """

        # Stat
        Meters.aii("ping.client.client_disconnect_count")

        # Clean
        self._unschedule_client_helloservertimeout()
        self._unschedule_client_ping()
        self._unschedule_client_pingservertimeout()

        # Base
        return TcpSimpleClient.disconnect(self)
예제 #20
0
    def _schedule_server_ping_client_timeout(self):
        """
        Schedule a ping timeout

        """

        with self._protocolLock:
            # Check
            if self._pingTimeOutGreenlet:
                logger.warning("_ping_timeout_greenlet is not None, killing")
                Meters.aii("ping.server.scheduleServerPingTimeOutError")
                self._unschedule_server_ping_client_timeout()
                # Go
            self._pingTimeOutGreenlet = gevent.spawn_later(
                self._pingTimeOutMs * 0.001,
                self._protocol_server_ping_client_timeout)
예제 #21
0
    def _read_from_socket(self):
        """
        Read from the socket. Return a local_buf or None.
        """

        # Check
        if not self.__is_running():
            logger.debug("not connected, doing nothing, self=%s", self)
            return None

        try:
            # TODO : Socket local_buf size
            # TODO : Socket, upon server closure, will BLOCK on recv. Upon time, auto disconnect the client.

            # Try to read
            local_buf = self.current_socket.recv(1024)

            # If local_buf is empty string, socket is disconnected.
            if local_buf and len(local_buf) == 0:
                # Disconnect
                logger.debug("empty string received, disconnecting ourselves, self=%s", self)
                self._disconnect_helper("_read_from_socket : Empty string")
                return None

            # Stats
            Meters.aii("tcp.server.server_bytes_received", len(local_buf))

            # Ok
            return local_buf
        except error as e:
            # [Errno 11] Resource temporarily unavailable
            # Means that nothing is available to read.
            # If not this, we raise.
            if e.args[0] != EWOULDBLOCK:
                # Raise :)
                logger.debug("_tryReadWrite : _read_from_socket : error, ex=%s, self=%s", SolBase.extostr(e), self)
                self._disconnect_helper("_read_from_socket : error / No EWOULDBLOCK")
                return None
            else:
                # Normal
                logger.debug("_tryReadWrite : _read_from_socket : normal exception/EWOULDBLOCK, ex=%s, self=%s", e,
                             self)
                return None
        except Exception as e:
            logger.debug("_tryReadWrite : _read_from_socket : Exception, ex=%s, self=%s", SolBase.extostr(e), self)
            self._disconnect_helper("_read_from_socket : Exception / No EWOULDBLOCK")
            return None
예제 #22
0
    def _protocol_context_client_hello_timeout(self):
        """
        Hello timeout

        """

        with self._protocolLock:
            logger.error("timeout, fatal, disconnecting")

            # Reset (we are called by it)
            self._helloTimeOutGreenlet = None

            # Stats
            Meters.aii("ping.server.clientHelloTimeOut")

            # Disconnect ourselves (this is fatal)
            self.stop_asynch()
예제 #23
0
    def _protocol_server_ping_client_timeout(self):
        """
        Called when a ping has time-out (ie no reply from server)

        """

        with self._protocolLock:
            logger.warning("ping timeout, rescheduling ping")

            # Reset (we are called by it)
            self._pingTimeOutGreenlet = None

            # Reschedule a ping
            self._schedule_server_ping()

            # Stat
            Meters.aii("ping.server.serverPingClientTimeOut")
예제 #24
0
    def _protocol_client_hello_server_timeout(self):
        """
        Hello timeout

        """

        with self._protocol_lock:
            logger.error("timeout, fatal, disconnecting")

            # Reset (we are called by it)
            self._hello_timeout_greenlet = None

            # Stats
            Meters.aii("ping.client.client_hello_server_timeout")

            # Disconnect ourselves (this is fatal)
            self.disconnect()
예제 #25
0
    def test_meters(self):
        """
        Test
        """

        ai1a = Meters.ai("ai1")
        self.assertIsInstance(ai1a, AtomicIntSafe)
        ai1b = Meters.ai("ai1")
        self.assertEqual(id(ai1a), id(ai1b))

        ai1a = Meters.aii("ai1")
        self.assertEqual(ai1a.get(), 1)
        ai1a = Meters.aii("ai1", 2)
        self.assertEqual(ai1a.get(), 3)
        self.assertEqual(ai1a.get(), Meters.aig("ai1"))

        af1a = Meters.af("af1")
        self.assertIsInstance(af1a, AtomicFloatSafe)
        af1b = Meters.af("af1")
        self.assertEqual(id(af1a), id(af1b))

        af1a = Meters.afi("af1")
        self.assertEqual(af1a.get(), 1.0)
        af1a = Meters.afi("af1", 2.0)
        self.assertEqual(af1a.get(), 3.0)
        self.assertEqual(af1a.get(), Meters.afg("af1"))

        dtc1a = Meters.dtc("dtc1")
        self.assertIsInstance(dtc1a, DelayToCountSafe)
        dtc1b = Meters.dtc("dtc1")
        self.assertEqual(id(dtc1a), id(dtc1b))

        Meters.dtci("dtc1", 0)
        Meters.dtci("dtc1", 50)
        Meters.dtci("dtc1", 100)
        self.assertEquals(Meters._hash_meter["dtc"]["dtc1#"]._sorted_dict[0].get(), 1)
        self.assertEquals(Meters._hash_meter["dtc"]["dtc1#"]._sorted_dict[50].get(), 1)
        self.assertEquals(Meters._hash_meter["dtc"]["dtc1#"]._sorted_dict[100].get(), 1)
        self.assertEquals(Meters._hash_meter["dtc"]["dtc1#"]._sorted_dict[500].get(), 0)

        Meters.dtc("dtc1").to_dict()

        # Write
        Meters.write_to_logger()
예제 #26
0
    def stop_synch_internal(self):
        """
        Disconnect from server.
        :return Return true upon success.
        """

        # Stat
        Meters.aii("ping.server.serverStopSynchCount")

        # Clean
        self._unschedule_client_hello_timeout()
        self._unschedule_server_ping()
        self._unschedule_server_ping_client_timeout()

        # Called
        self.stop_synch_internalCalled = True

        # Base
        return TcpServerQueuedClientContext.stop_synch_internal(self)
예제 #27
0
    def get_raw(self, key):
        """
        Get from cache.
        Can evict if ttl expired and return None.
        :param key: Any key
        :type key: str
        :return tuple(ttl_ms, value as bytes or str)
        :rtype; tuple, None
        """

        try:
            # Get it
            # [0] : Expired ms
            # [1] : Object cached
            tu_obj = self._hash_key.get(key)
            if not tu_obj:
                # Stat
                Meters.aii(self.meters_prefix + "mcs.cache_get_miss")
                return None

            # Got it, check TTL
            if self._is_expired(tu_obj[0], SolBase.mscurrent()):
                # Expired => kick it & exit
                self._safe_unhash(key)
                # Notify
                self._notify_eviction(key, tu_obj[1])
                # Stat
                Meters.aii(self.meters_prefix + "mcs.cache_get_miss")
                Meters.aii(self.meters_prefix + "mcs.cache_evict_ttl_get")
                return None

            # Got a HIT : Must update it in the ordered dict : del & re-add
            del (self._hash_context[key])
            self._hash_context[key] = tu_obj

            # Return the data
            Meters.aii(self.meters_prefix + "mcs.cache_get_hit")

            return tu_obj
        except Exception as e:
            logger.warning("Exception, ex=%s", SolBase.extostr(e))
            Meters.aii(self.meters_prefix + "mcs.cache_ex")
            return None
예제 #28
0
    def _connection_close(self, conn):
        """
        Close a connection
        Must not raise anything.
        :param conn: pymysql.connections.Connection
        :type conn: pymysql.connections.Connection
        """

        Meters.aii("k.db_pool.mysql.call._connection_close")

        # noinspection PyBroadException
        try:
            if conn:
                conn.close()
        except Exception as e:
            # Dont care of exception in case of closing
            Meters.aii("k.db_pool.mysql.ex_close")
            logger.debug("Close exception (non fatal), ex=%s",
                         SolBase.extostr(e))
예제 #29
0
    def _safe_unhash(self, key):
        """
        Remove a key from cache (from both dict)
        :param key: Any key
        :type key: str
        """

        try:
            # Kick from both hashes
            try:
                del (self._hash_key[key])
            except KeyError:
                pass

            try:
                del (self._hash_context[key])
            except KeyError:
                pass
        except Exception as e:
            logger.warning("Exception, ex=%s", SolBase.extostr(e))
            Meters.aii(self.meters_prefix + "mcs.cache_ex")
예제 #30
0
    def remove(self, key):
        """
        Remove a key from cache.
        :param key: Any key
        :type key: str
        """

        ms_start = SolBase.mscurrent()
        try:
            if not isinstance(key, (bytes, str)):
                raise Exception("Key must be (bytes, str)")

            # Use write redis
            self._write_redis.delete(key)

        except Exception as e:
            logger.warning("Exception, ex=%s", SolBase.extostr(e))
            Meters.aii(self.meters_prefix + "rcs.cache_ex")
        finally:
            Meters.dtci(self.meters_prefix + "rcs.cache_dtc_write",
                        SolBase.msdiff(ms_start))