예제 #1
0
 private void OnMemcacheError(MemcacheResponseHeader header, IMemcacheRequest request)
 {
     if (MemcacheError != null)
     {
         MemcacheError(header, request);
     }
 }
예제 #2
0
        /// <summary>
        /// Sends a request with the policy defined with the configuration object, to multiple nodes if the replicas setting
        /// is different from zero.
        /// </summary>
        /// <param name="request">A memcache request derived from RedundantRequest</param>
        /// <returns>
        /// True if the request was sent to at least one node. The caller will receive a callback (if not null).
        /// False if the request could not be sent to any node. In that case, the callback will not be called.
        /// </returns>
        protected bool SendRequest(IMemcacheRequest request)
        {
            int countTrySends   = 0;
            int countTrySendsOK = 0;

            foreach (var node in _cluster.Locator.Locate(request))
            {
                countTrySends++;
                if (node.TrySend(request, _configuration.QueueTimeout))
                {
                    countTrySendsOK++;
                }

                // Break after trying to send the request to replicas+1 nodes
                if (countTrySends > request.Replicas)
                {
                    break;
                }
            }

            // The callback will not be called
            if (countTrySendsOK == 0)
            {
                return(false);
            }

            // If the request was sent to less than Replicas+1 nodes, fail the remaining ones.
            for (; countTrySendsOK <= request.Replicas; countTrySendsOK++)
            {
                request.Fail();
            }

            return(true);
        }
예제 #3
0
        private bool SendRequest(IMemcacheRequest request, ManualResetEventSlim callAvailable = null)
        {
            try
            {
                var buffer = request.GetQueryBuffer();

                if (_clientConfig.QueueLength > 0 &&
                    _pendingRequests.Count >= _clientConfig.QueueLength)
                {
                    // The request queue is full, the transport will be put back in the pool after the queue is not full anymore
                    Interlocked.Exchange(ref _transportAvailableInReceive, 1);
                    if (!_pendingRequests.IsEmpty)
                    {
                        // the receive will reset the flag after the next dequeue
                        return(false);
                    }

                    if (0 == Interlocked.CompareExchange(ref _transportAvailableInReceive, 0, 1))
                    {
                        // the flag has already been reset (by the receive)
                        return(false);
                    }
                }

                _pendingRequests.Enqueue(request);
                SendAsynch(buffer, 0, buffer.Length, callAvailable);
            }
            catch (Exception e)
            {
                TransportFailureOnSend(e);
                return(false);
            }

            return(true);
        }
예제 #4
0
        public bool TrySend(IMemcacheRequest request, int timeout)
        {
            try
            {
                var tries = 0;
                IMemcacheTransport transport;
                while (!IsClosing() &&
                       !_tokenSource.IsCancellationRequested &&
                       ++tries <= _configuration.PoolSize &&
                       _transportPool.TryTake(out transport, timeout, _tokenSource.Token))
                {
                    if (transport.TrySend(request))
                    {
                        return(true);
                    }
                }
            }
            catch (OperationCanceledException)
            {
                // someone called for a cancel on the pool.TryTake and already raised the problem
                return(false);
            }

            return(false);
        }
예제 #5
0
 private void OnMemcacheResponse(MemcacheResponseHeader h, IMemcacheRequest e)
 {
     if (MemcacheResponse != null)
     {
         MemcacheResponse(h, e);
     }
 }
예제 #6
0
        /// <summary>
        /// Sends a request with the policy defined with the configuration object, to multiple nodes if the replicas setting
        /// is different from zero.
        /// </summary>
        /// <param name="request">A memcache request derived from RedundantRequest</param>
        /// <returns>
        /// True if the request was sent to at least one node. The caller will receive a callback (if not null).
        /// False if the request could not be sent to any node. In that case, the callback will not be called.
        /// </returns>
        protected bool SendRequest(IMemcacheRequest request)
        {
            int countTrySends   = 0;
            int countTrySendsOK = 0;

            foreach (var node in _locator.Locate(request.Key))
            {
                countTrySends++;
                if (node.TrySend(request, _configuration.QueueTimeout))
                {
                    countTrySendsOK++;
                }

                // Break after trying to send the request to replicas+1 nodes
                if (countTrySends > request.Replicas)
                {
                    break;
                }
            }

            if (countTrySendsOK == 0)
            {
                // The callback will not be called
                return(false);
            }
            else
            {
                // Call Fail() on the request as many times as node.TrySend returned false
                for (; countTrySendsOK < countTrySends; countTrySendsOK++)
                {
                    request.Fail();
                }
                return(true);
            }
        }
예제 #7
0
        public IEnumerable <IMemcacheNode> Locate(IMemcacheRequest req)
        {
            var key = req.Key;

            if (key == null)
            {
                throw new ArgumentNullException("key");
            }

            var ld = _lookupData;

            switch (ld.Nodes.Length)
            {
            case 0:
                yield break;

            case 1:
                var firstNode = ld.Nodes[0];
                if (!firstNode.IsDead)
                {
                    yield return(firstNode);
                }
                yield break;
            }

            // Return alive JsonNodes only.
            foreach (var retNode in LocateNode(ld, GetKeyHash(key)))
            {
                if (retNode != null && !retNode.IsDead)
                {
                    yield return(retNode);
                }
            }
        }
예제 #8
0
        public IEnumerable <IMemcacheNode> Locate(IMemcacheRequest req)
        {
            // Compute the vBucket's index using a modified CRC32
            var vBucketIndex = Hash.Compute(req.Key) & HashMask;

            req.VBucket = (ushort)vBucketIndex;

            return(YieldingLocate(req, vBucketIndex));
        }
 public SaslPlainTextToken(string zone, string user, string password)
 {
     _authenticationStatus = new TaskCompletionSource<Status>();
     _request = new SaslPlainRequest
     {
         Zone = zone,
         User = user,
         Password = password,
         Callback = _authenticationStatus.SetResult,
     };
 }
예제 #10
0
 public SaslPlainTextToken(string zone, string user, string password)
 {
     _authenticationStatus = new TaskCompletionSource <Status>();
     _request = new SaslPlainRequest
     {
         Zone     = zone,
         User     = user,
         Password = password,
         Callback = _authenticationStatus.SetResult,
     };
 }
예제 #11
0
 public bool TrySend(IMemcacheRequest req)
 {
     if (!IsAlive)
     {
         return(false);
     }
     else
     {
         req.HandleResponse(Response, null, Extra, Message);
         return(true);
     }
 }
예제 #12
0
 public bool TrySend(IMemcacheRequest req)
 {
     if (!IsAlive)
     {
         return false;
     }
     else
     {
         req.HandleResponse(Response, null, Extra, Message);
         return true;
     }
 }
예제 #13
0
            public bool TrySend(IMemcacheRequest req)
            {
                if (!_broken)
                {
                    return(true);
                }

                if (TransportDead != null)
                {
                    TransportDead(this);
                }
                return(false);
            }
        private IEnumerable<IMemcacheNode> YieldingLocate(IMemcacheRequest req, uint vBucketIndex)
        {
            // Check for non-configured, badly configured, or dead cluster
            if (Nodes == null || Nodes.Count == 0 || VBucketMap == null || VBucketMap.Length != 1024)
                yield break;

            // Yield replica in the same order (the first one being the master)
            foreach (var node in VBucketMap[vBucketIndex])
                if (0 <= node && node < Nodes.Count)
                    yield return Nodes[node];
                else
                    continue;
        }
        public IEnumerable<IMemcacheNode> Locate(IMemcacheRequest req)
        {
            // Compute the vBucket's index using a modified CRC32
            var vBucketIndex = Hash.Compute(req.Key) & HashMask;
            var couchbaseReq = req as ICouchbaseRequest;
            if (couchbaseReq != null)
                couchbaseReq.VBucket = (ushort)vBucketIndex;

            // the call to the yield is done in another method in order to
            // have the VBucket changed before we start iterating over the
            // located nodes
            return YieldingLocate(req, vBucketIndex);
        }
예제 #16
0
        /// <summary>
        /// Synchronously sends a request
        /// </summary>
        /// <param name="request" />
        public bool TrySend(IMemcacheRequest request)
        {
            if (request == null || _disposed)
            {
                return(false);
            }

            if (!_initialized && !Initialize())
            {
                return(false);
            }

            return(SendRequest(request));
        }
예제 #17
0
        public bool TrySend(IMemcacheRequest request, int timeout)
        {
            LastRequest = request;
            trySendCounter++;

            if (timeout == 0)
            {
                LastRequest.HandleResponse(new MemcacheResponseHeader {
                    Status = DefaultResponse, ExtraLength = 4
                }, request.Key, new byte[4], new byte[0]);
            }

            return(true);
        }
예제 #19
0
        public IEnumerable<IMemcacheNode> Locate(IMemcacheRequest req)
        {
            int position = Interlocked.Increment(ref _lastPosition) % _nodes.Count;
            position = position >= 0 ? position : position + _nodes.Count;

            for(int i = 0; i < _nodes.Count; ++i)
            {
                var selectedNode = _nodes[position];
                if (!selectedNode.IsDead)
                    yield return selectedNode;

                position++;
                if (position >= _nodes.Count)
                    position = 0;
            }
        }
예제 #20
0
        public IEnumerable <IMemcacheNode> Locate(IMemcacheRequest req)
        {
            // Compute the vBucket's index using a modified CRC32
            var vBucketIndex = Hash.Compute(req.Key) & HashMask;
            var couchbaseReq = req as ICouchbaseRequest;

            if (couchbaseReq != null)
            {
                couchbaseReq.VBucket = (ushort)vBucketIndex;
            }

            // the call to the yield is done in another method in order to
            // have the VBucket changed before we start iterating over the
            // located nodes
            return(YieldingLocate(req, vBucketIndex));
        }
예제 #21
0
            public Status StepAuthenticate(TimeSpan authTimeout, out IMemcacheRequest stepRequest)
            {
                if (_started)
                {
                    stepRequest = null;
                    if (!_authenticationStatus.Task.Wait(authTimeout))
                    {
                        throw new AuthenticationException("Authentication has timed out");
                    }

                    return(_authenticationStatus.Task.Result);
                }

                _started    = true;
                stepRequest = _request;
                return(Status.StepRequired);
            }
예제 #22
0
        private bool Authenticate()
        {
            bool             authDone   = false;
            IMemcacheRequest request    = null;
            Status           authStatus = Status.NoError;

            if (_clientConfig.Authenticator != null)
            {
                var mre = new ManualResetEventSlim();
                var authenticationToken = _clientConfig.Authenticator.CreateToken();
                while (authenticationToken != null && !authDone)
                {
                    authStatus = authenticationToken.StepAuthenticate(out request);

                    switch (authStatus)
                    {
                    // auth OK, clear the token
                    case Status.NoError:
                        authenticationToken = null;
                        authDone            = true;
                        break;

                    case Status.StepRequired:
                        if (request == null)
                        {
                            throw new AuthenticationException("Unable to authenticate : step required but no request from token");
                        }
                        if (!SendRequest(request, mre))
                        {
                            throw new AuthenticationException("Unable to authenticate : unable to send authentication request");
                        }
                        break;

                    default:
                        throw new AuthenticationException("Unable to authenticate : status " + authStatus.ToString());
                    }
                }
                mre.Wait();
            }

            return(true);
        }
예제 #23
0

        
        private IEnumerable <IMemcacheNode> YieldingLocate(IMemcacheRequest req, uint vBucketIndex)
        {
            // Check for non-configured, badly configured, or dead cluster
            if (Nodes == null || Nodes.Count == 0 || VBucketMap == null || VBucketMap.Length != 1024)
            {
                yield break;
            }

            // Yield replica in the same order (the first one being the master)
            foreach (var node in VBucketMap[vBucketIndex])
            {
                if (0 <= node && node < Nodes.Count)
                {
                    yield return(Nodes[node]);
                }
                else
                {
                    continue;
                }
            }
        }
예제 #25
0
        private IMemcacheRequest DequeueToMatch(MemcacheResponseHeader header)
        {
            IMemcacheRequest result = null;

            if (header.Opcode.IsQuiet())
            {
                throw new MemcacheException("No way we can match a quiet request !");
            }
            else
            {
                // hacky case on partial response for stat command
                if (header.Opcode == Opcode.Stat && header.TotalBodyLength != 0 && header.Status == Status.NoError)
                {
                    if (!_pendingRequests.TryPeek(out result))
                    {
                        throw new MemcacheException("Received a response when no request is pending");
                    }
                }
                else
                {
                    if (!_pendingRequests.TryDequeue(out result))
                    {
                        throw new MemcacheException("Received a response when no request is pending");
                    }
                }

                if (result.RequestId != header.Opaque)
                {
                    result.Fail();
                    throw new MemcacheException("Received a response that doesn't match with the sent request queue : sent " + result.ToString() + " received " + header.ToString());
                }
            }

            AvailableInReceive();
            return(result);
        }
예제 #26
0
 private void OnMemcacheResponse(MemcacheResponseHeader h, IMemcacheRequest e)
 {
     if (MemcacheResponse != null)
         MemcacheResponse(h, e);
 }
예제 #27
0
        public bool TrySend(IMemcacheRequest request, int timeout)
        {
            try
            {
                var tries = 0;
                IMemcacheTransport transport;
                while (!IsClosing()
                    && !_tokenSource.IsCancellationRequested
                    && ++tries <= _configuration.PoolSize
                    && _transportPool.TryTake(out transport, timeout, _tokenSource.Token))
                {
                    if (transport.TrySend(request))
                        return true;
                }
            }
            catch (OperationCanceledException)
            {
                // someone called for a cancel on the pool.TryTake and already raised the problem
                return false;
            }

            return false;
        }
예제 #28
0
        public void AuthenticationFailed()
        {
            var sentMutex = new ManualResetEventSlim(false);

            using (var serverStub = new ServerMock())
            {
                IMemcacheRequest authenticationRequest = null;
                // a token that fails
                var authenticatorTokenFailing = new Moq.Mock <IAuthenticationToken>();
                authenticatorTokenFailing
                .Setup(t => t.StepAuthenticate(Moq.It.IsAny <TimeSpan>(), out authenticationRequest))
                .Returns(Status.TemporaryFailure);
                // a token that works
                var authenticatorTokenOk = new Moq.Mock <IAuthenticationToken>();
                authenticatorTokenOk
                .Setup(t => t.StepAuthenticate(Moq.It.IsAny <TimeSpan>(), out authenticationRequest))
                .Returns(Status.NoError);
                // an authenticator that returns one failing token followed by working tokens
                bool alreadyFailed = false;
                var  authenticator = new Moq.Mock <IMemcacheAuthenticator>();
                authenticator
                .Setup(auth => auth.CreateToken())
                .Returns(() =>
                {
                    if (alreadyFailed)
                    {
                        return(authenticatorTokenOk.Object);
                    }
                    alreadyFailed = true;
                    return(authenticatorTokenFailing.Object);
                });

                // setup the request to send
                bool requestFailed   = false;
                bool requestAchieved = false;
                var  request         = new Moq.Mock <IMemcacheRequest>();
                request
                .Setup(r => r.Fail())
                .Callback(() =>
                {
                    requestFailed = true;
                    sentMutex.Set();
                });
                request
                .Setup(r => r.HandleResponse(
                           Moq.It.Is <Headers.MemcacheResponseHeader>(h => h.Status == Status.NoError),
                           Moq.It.IsAny <byte[]>(),
                           Moq.It.IsAny <byte[]>(),
                           Moq.It.IsAny <byte[]>()))
                .Callback(() =>
                {
                    requestAchieved = true;
                    sentMutex.Set();
                });
                var queryBuffer = new byte[MemcacheRequestHeader.Size];
                new MemcacheRequestHeader().ToData(queryBuffer);
                request
                .Setup(r => r.GetQueryBuffer())
                .Returns(queryBuffer);

                IMemcacheTransport transportToWork = null;
                var transportToFail = new MemcacheTransport(
                    serverStub.ListenEndPoint,
                    new MemcacheClientConfiguration
                {
                    SocketTimeout = TimeSpan.Zero,
                    Authenticator = authenticator.Object,
                },
                    _ => { },
                    t =>
                {
                    Interlocked.Exchange(ref transportToWork, t);
                },
                    false,
                    () => false);
                new MemcacheResponseHeader
                {
                    Status = Status.NoError,
                    Opcode = Opcode.Get,
                }.ToData(serverStub.ResponseHeader);

                Exception raised = null;
                transportToFail.TransportError += e =>
                                                  // when the transport fails collect the exception
                                                  Interlocked.Exchange(ref raised, e);
                var sent = transportToFail.TrySend(request.Object);

                Assert.IsFalse(sent, "The request send should fail");
                Assert.IsNotNull(raised, "The authentication should have failed");

                // wait for reconnection to happen (should be done in a instant timer)
                Assert.That(ref transportToWork, (!Is.Null).After(1000, 10), "The working transport should have been set");

                sent = transportToWork.TrySend(request.Object);
                Assert.IsTrue(sent, "The request should have been sent");
                var received = sentMutex.Wait(TimeSpan.FromMinutes(5));
                Assert.IsTrue(received, "The response should have been received");
                Assert.IsFalse(requestFailed, "The request should not have failed");
                Assert.IsTrue(requestAchieved, "The request should have achieved");
            }
        }
            public Status StepAuthenticate(TimeSpan authTimeout, out IMemcacheRequest stepRequest)
            {
                if (_started)
                {
                    stepRequest = null;
                    if (!_authenticationStatus.Task.Wait(authTimeout))
                        throw new AuthenticationException("Authentication has timed out");

                    return _authenticationStatus.Task.Result;
                }

                _started = true;
                stepRequest = _request;
                return Status.StepRequired;
            }
예제 #30
0
 public bool TrySend(IMemcacheRequest request, int timeout)
 {
     return _queue.TryAdd(request, timeout);
 }
예제 #31
0
            public bool TrySend(IMemcacheRequest req)
            {
                if (!_broken)
                    return true;

                if (TransportDead != null)
                    TransportDead(this);
                return false;
            }
예제 #32
0
        /// <summary>
        /// Synchronously sends a request
        /// </summary>
        /// <param name="request" />
        public bool TrySend(IMemcacheRequest request)
        {
            if (request == null || _disposed || _ongoingShutdown == 1)
                return false;

            if (!_initialized && !Initialize())
                return false;

            return SendRequest(request);
        }
예제 #33
0
 public bool TryTake(out IMemcacheRequest request, int timeout)
 {
     return(_queue.TryTake(out request, timeout));
 }
예제 #34
0
 public void Add(IMemcacheRequest request)
 {
     _queue.Add(request);
 }
예제 #35
0
        private bool SendRequest(IMemcacheRequest request, ManualResetEventSlim callAvailable = null)
        {
            try
            {
                var buffer = request.GetQueryBuffer();

                if (_clientConfig.QueueLength > 0 &&
                    _pendingRequests.Count >= _clientConfig.QueueLength)
                {
                    // The request queue is full, the transport will be put back in the pool after the queue is not full anymore
                    Interlocked.Exchange(ref _transportAvailableInReceive, 1);
                    if (!_pendingRequests.IsEmpty)
                        // the receive will reset the flag after the next dequeue
                        return false;

                    if (0 == Interlocked.CompareExchange(ref _transportAvailableInReceive, 0, 1))
                        // the flag has already been reset (by the receive)
                        return false;
                }

                _pendingRequests.Enqueue(request);
                SendAsynch(buffer, 0, buffer.Length, callAvailable);
            }
            catch (Exception e)
            {
                TransportFailureOnSend(e);
                return false;
            }

            return true;
        }
예제 #36
0
 public void Add(IMemcacheRequest request)
 {
     _queue.Add(request);
 }
예제 #37
0
 public bool TryTake(out IMemcacheRequest request, int timeout)
 {
     return _queue.TryTake(out request, timeout);
 }
예제 #38
0
 public bool TrySend(IMemcacheRequest request, int timeout)
 {
     return(_queue.TryAdd(request, timeout));
 }