Пример #1
0
        /// <summary>
        /// Returns an instance of transport suitable for a call. The implementation may return existing transport or allocate a new instance.
        /// The call is thread-safe
        /// </summary>
        protected virtual ClientTransport AcquireClientTransportForCall(ClientEndPoint client, RequestMsg request)
        {
            var transport = TryGetExistingAcquiredTransportPerRemoteNode(client.Node);

            if (transport != null)
            {
                return(transport);
            }

            //otherwise we need to create a new transport
            if (m_ClientTransportMaxCount > 0)
            {
                var alock = m_ClientTransportAllocatorLocks[(client.Node.GetHashCode() & CoreConsts.ABS_HASH_MASK) % m_ClientTransportAllocatorLocks.Length];
                lock (alock)
                {
                    transport = TryGetExistingAcquiredTransportPerRemoteNode(client.Node);
                    if (transport != null)
                    {
                        return(transport);
                    }
                    return(makeAndLaunchClientTransportForCall(client, request));
                }
            }

            return(makeAndLaunchClientTransportForCall(client, request));
        }
Пример #2
0
        /// <summary>
        /// Dispatches a call allocating new or re-using existing transport if needed. The strategy depends on particular Binding implementation.
        /// This call is thread-safe
        /// </summary>
        public CallSlot DispatchCall(ClientEndPoint client, RequestMsg request)
        {
            CheckRunningState();

            //Binding level inspectors
            foreach (var insp in m_ClientMsgInspectors.OrderedValues)
            {
                request = insp.ClientDispatchCall(client, request);
            }

            //Glue level inspectors
            request = Glue.ClientDispatchingRequest(client, request);

            //==============================================================

            CallOptions options;

            options.DispatchTimeoutMs = client.DispatchTimeoutMs;
            options.TimeoutMs         = client.TimeoutMs;

            var reserve = client.ReserveTransport;

            var transport = client.m_ReservedTransport ?? AcquireClientTransportForCall(client, request);

            CallSlot slot = null;

            try
            {
                if (reserve)
                {
                    client.m_ReservedTransport = transport;
                }

                slot = transport.SendRequest(client, request, options);

                // If execution pauses here and server sends response BEFORE call
                //then Glue.Deliver response will retry to fimnd the missing call slot for some fixed interval
                if (slot != null)
                {
                    Glue.ClientDispatchedRequest(client, request, slot);
                }
            }
            finally
            {
                if (!reserve)
                {
                    ReleaseClientTransportAfterCall(transport);
                }
            }

            return(slot);
        }
Пример #3
0
        private ClientTransport makeAndLaunchClientTransportForCall(ClientEndPoint client, RequestMsg request)
        {
            var transport = MakeNewClientTransport(client);

            try
            {
                ConfigureAndStartNewClientTransport(transport);
            }
            catch
            {
                transport.Dispose();
                throw;
            }
            return(transport);
        }
Пример #4
0
        /// <summary>
        /// INTERNAL METHOD. Developers do not call!
        /// This constructor is used by an Async binding that delivers response after call slot was created
        /// </summary>
        public CallSlot(ClientEndPoint client, ClientTransport clientTransport, RequestMsg request, CallStatus status, int timeoutMs = 0)
        {
            m_Client          = client;
            m_ClientTransport = clientTransport;
            m_RequestID       = request.RequestID;
            m_CallStatus      = status;
            m_OneWay          = request.OneWay;
            m_StartTime       = DateTime.UtcNow;
            m_TimeoutMs       = timeoutMs > 0 ? timeoutMs : DEFAULT_TIMEOUT_MS;

            if (!m_OneWay && client.Binding.MeasureStatTimes)
            {
                m_StatStartTimeTicks   = client.Binding.StatTimeTicks;
                m_StatRoundtripTimeKey = client.Binding.GetClientCallStatTimeKey(client, request);
            }
        }
Пример #5
0
        /// <summary>
        /// INTERNAL METHOD. Developers do not call!
        /// This constructor is used by a synchronous binding that delivers response right after sending it.
        /// ONLY for OneWayCall = false
        /// </summary>
        public CallSlot(ClientEndPoint client,
                        ClientTransport clientTransport,
                        long actualStartTimeTicks,
                        DateTime actualStartTimeUtc,
                        RequestMsg request,
                        ResponseMsg response,
                        int timeoutMs)
        {
            m_Client          = client;
            m_ClientTransport = clientTransport;
            m_RequestID       = request.RequestID;
            m_OneWay          = false;
            m_StartTime       = actualStartTimeUtc;
            m_TimeoutMs       = timeoutMs > 0 ? timeoutMs : DEFAULT_TIMEOUT_MS;

            if (client.Binding.MeasureStatTimes)
            {
                m_StatStartTimeTicks   = actualStartTimeTicks;
                m_StatRoundtripTimeKey = client.Binding.GetClientCallStatTimeKey(client, request);
            }

            m_ResponseMsg = response;
            m_CallStatus  = m_ResponseMsg.OK ? CallStatus.ResponseOK : CallStatus.ResponseError;
            var remoteInstance = response.RemoteInstance;

            if (remoteInstance.HasValue)
            {
                m_Client.__setRemoteInstance(remoteInstance.Value);
            }

            if (m_StatRoundtripTimeKey != null && m_Client.Binding.MeasureStatTimes)
            {
                m_StatRoundtripEndTimeTicks = m_Client.Binding.StatTimeTicks;
                m_ClientTransport.stat_Time(m_StatRoundtripTimeKey, m_StatRoundtripEndTimeTicks - m_StatStartTimeTicks);
            }
        }
Пример #6
0
 /// <summary>
 /// Factory method - Override to make an instance of a new client transport suitable for particular binding type
 /// </summary>
 protected abstract ClientTransport MakeNewClientTransport(ClientEndPoint client);
Пример #7
0
 /// <summary>
 /// Extracts necessary information from client:request pair that characterizes the particular call
 ///  for the purpose of call timing
 /// </summary>
 public virtual string GetClientCallStatTimeKey(ClientEndPoint client, RequestMsg request)
 {
     //todo In future may add property StatCallTimesLevel {Transport, Contract, Method}
     return(client.Node.ToString() + " -> " + request.Contract.FullName + '.' + request.MethodName + "()");
 }
Пример #8
0
 public void ClientDispatchedRequest(ClientEndPoint client, RequestMsg request, CallSlot callSlot)
 {
 }
Пример #9
0
 public RequestMsg ClientDispatchingRequest(ClientEndPoint client, RequestMsg request)
 {
     return(request);
 }
Пример #10
0
 /// <summary>
 /// Override to send a client request into remote endpoint.
 /// This is a blocking call for bindings that are OperationFlow.Synchronous and
 /// result arrives immediately into CallSlot.
 /// </summary>
 protected abstract CallSlot DoSendRequest(ClientEndPoint endpoint, RequestMsg request, CallOptions options);
Пример #11
0
 /// <summary>
 /// Sends a client request into remote endpoint.
 /// This is a blocking call for bindings that are OperationFlow.Synchronous and
 /// result arrives immediately into CallSlot.
 /// </summary>
 public CallSlot SendRequest(ClientEndPoint endpoint, RequestMsg request, CallOptions options)
 {
     CheckRunningState();
     return(DoSendRequest(endpoint, request, options));
 }