public static void FinishCurrent(PooledSocket socket) { string response = socket.ReadResponse(); if (String.Compare(response, "END", StringComparison.Ordinal) != 0) throw new MemcachedClientException("No END was received."); }
public override void Dispose() { if (this.socket != null) { ((IDisposable)this.socket).Dispose(); this.socket = null; } base.Dispose(); }
public AsyncSocketHelper(PooledSocket socket) { this.socket = socket; this.asyncBuffer = new SlidingBuffer(ChunkSize); this.readEvent = new SocketAsyncEventArgs(); this.readEvent.Completed += new EventHandler<SocketAsyncEventArgs>(AsyncReadCompleted); this.readEvent.SetBuffer(new byte[ChunkSize], 0, ChunkSize); this.readInProgressEvent = new ManualResetEvent(false); }
public override void Dispose() { GC.SuppressFinalize(this); if (this.socket != null) { ((IDisposable)this.socket).Dispose(); this.socket = null; } base.Dispose(); }
public override void Dispose() { GC.SuppressFinalize(this); if (this.socket != null) { ((IDisposable)this.socket).Dispose(); this.socket = null; } base.Dispose(); }
protected override bool ExecuteAction() { PooledSocket socket = this.Socket; if (socket == null) { return(false); } socket.SendCommand("delete " + this.HashedKey); return(String.Compare(socket.ReadResponse(), "DELETED", StringComparison.Ordinal) == 0); }
protected internal virtual PooledSocket CreateSocket() { try { var ps = new PooledSocket(this.endPoint, this.config.ConnectionTimeout, this.config.ReceiveTimeout, _logger); ps.Connect(); return(ps); } catch (Exception ex) { _logger.LogError(ex, $"Create {nameof(PooledSocket)}"); throw; } }
/// <summary> /// Sends the command to the server. The trailing \r\n is automatically appended. /// </summary> /// <param name="value">The command to be sent to the server.</param> public void SendCommand(string value) { this.CheckDisposed(); //this.CheckThread(); if (log.IsDebugEnabled) { log.Debug("SendCommand: " + value); } // send the whole command with only one Write // since Nagle is disabled on the socket this is more efficient than // Write(command), Write("\r\n") this.Write(PooledSocket.GetCommandBuffer(value)); }
protected internal virtual async Task <PooledSocket> CreateSocketAsync() { try { var ps = new PooledSocket(this.endPoint, this.config.ConnectionTimeout, this.config.ReceiveTimeout, _logger); await ps.ConnectAsync(); return(ps); } catch (Exception ex) { _logger.LogError(new EventId(this.GetHashCode(), nameof(MemcachedNode)), ex, $"Create {nameof(PooledSocket)}"); throw; } }
protected override bool ExecuteAction() { foreach (MemcachedNode server in this.ServerPool.WorkingServers) { using (PooledSocket ps = server.Acquire()) { if (ps != null) { ps.SendCommand("flush_all"); } } } return(true); }
/// <summary> /// Releases an item back into the pool /// </summary> /// <param name="socket"></param> private void ReleaseSocket(PooledSocket socket) { if (log.IsDebugEnabled) { log.Debug("Releasing socket " + socket.InstanceId); log.Debug("Are we alive? " + this.isAlive); } if (this.isAlive) { // is it still working (i.e. the server is still connected) if (socket.IsAlive) { // mark the item as free this.freeItems.Push(socket); } else { // kill this item //socket.Destroy(); socket.Dispose(); // mark ourselves as not working for a while this.MarkAsDead(); } } else { // one of our previous sockets has died, so probably all of them // are dead. so, kill the socket (this will eventually clear the pool as well) //socket.Destroy(); socket.Dispose(); } // In any event, we want to let any waiters know that we can create a new // socket: if (semaphore != null) { try { semaphore.Release(); } catch (ObjectDisposedException e) { log.Error(e); } } }
protected internal virtual async Task <PooledSocket> CreateSocketAsync() { try { var ps = new PooledSocket(_endPoint, _config.ConnectionTimeout, _config.ReceiveTimeout, _logger); await ps.ConnectAsync(); return(ps); } catch (Exception ex) { var endPointStr = _endPoint.ToString().Replace("Unspecified/", string.Empty); _logger.LogError(ex, $"Failed to {nameof(CreateSocketAsync)} to {endPointStr}"); throw; } }
public static GetResponse ReadItem(PooledSocket socket) { string description = socket.ReadResponse(); if (String.Compare(description, "END", StringComparison.Ordinal) == 0) return null; if (description.Length < 6 || String.Compare(description, 0, "VALUE ", 0, 6, StringComparison.Ordinal) != 0) throw new MemcachedClientException("No VALUE response received.\r\n" + description); ulong cas = 0; string[] parts = description.Split(' '); // response is: // VALUE <key> <flags> <bytes> [<cas unique>] // 0 1 2 3 4 // // cas only exists in 1.2.4+ // if (parts.Length == 5) { if (!UInt64.TryParse(parts[4], out cas)) throw new MemcachedClientException("Invalid CAS VALUE received."); } else if (parts.Length < 4) { throw new MemcachedClientException("Invalid VALUE response received: " + description); } ushort flags = UInt16.Parse(parts[2], CultureInfo.InvariantCulture); int length = Int32.Parse(parts[3], CultureInfo.InvariantCulture); byte[] allData = new byte[length]; byte[] eod = new byte[2]; socket.Read(allData, 0, length); socket.Read(eod, 0, 2); // data is terminated by \r\n GetResponse retval = new GetResponse(parts[1], flags, cas, allData); if (log.IsDebugEnabled) log.DebugFormat("Received value. Data type: {0}, size: {1}.", retval.Item.Flag, retval.Item.Data.Count); return retval; }
protected override bool ExecuteAction() { PooledSocket socket = this.Socket; if (socket == null) { return(false); } socket.SendCommand(String.Concat("incr ", this.HashedKey, " ", this.amount.ToString(CultureInfo.InvariantCulture))); string response = socket.ReadResponse(); //maybe we should throw an exception when the item is not found? if (String.Compare(response, "NOT_FOUND", StringComparison.Ordinal) == 0) { return(false); } return(UInt32.TryParse(response, out this.result)); }
protected override bool ExecuteAction() { PooledSocket socket = this.Socket; if (socket == null) { return(false); } socket.SendCommand("get " + this.HashedKey); GetResponse r = GetHelper.ReadItem(this.Socket); if (r != null) { this.result = this.ServerPool.Transcoder.Deserialize(r.Item); GetHelper.FinishCurrent(this.Socket); } return(true); }
/// <summary> /// Releases an item back into the pool /// </summary> /// <param name="socket"></param> private void ReleaseSocket(PooledSocket socket) { if (Log.IsDebugEnabled) { Log.Debug("Releasing socket " + socket.InstanceId); Log.Debug("Are we alive? " + isAlive); } if (isAlive) { // is it still working (i.e. the server is still connected) if (socket.IsAlive) { // mark the item as free freeItems.Enqueue(socket); // there can be a race condition (see the count check in acquire) // not sure what to do about it Interlocked.Decrement(ref workingCount); // signal the event so if someone is waiting for it can reuse this item itemReleasedEvent.Set(); } else { // kill this item socket.Destroy(); // mark ourselves as not working for a while MarkAsDead(); } } else { // one of our previous sockets has died, so probably all of them are dead // kill the socket thus clearing the pool, and after we become alive // we'll fill the pool with working sockets socket.Destroy(); } }
/// <summary> /// Releases an item back into the pool /// </summary> /// <param name="socket"></param> private void ReleaseSocket(PooledSocket socket) { if (log.IsDebugEnabled) { log.Debug("Releasing socket " + socket.InstanceId); log.Debug("Are we alive? " + this.isAlive); } if (this.isAlive) { // is it still working (i.e. the server is still connected) if (socket.IsAlive) { // mark the item as free this.freeItems.Push(socket); // signal the event so if someone is waiting for it can reuse this item this.semaphore.Release(); } else { // kill this item socket.Destroy(); // mark ourselves as not working for a while this.MarkAsDead(); // make sure to signal the Acquire so it can create a new conenction // if the failure policy keeps the pool alive this.semaphore.Release(); } } else { // one of our previous sockets has died, so probably all of them // are dead. so, kill the socket (this will eventually clear the pool as well) socket.Destroy(); } }
protected override IOperationResult ReadResponse(PooledSocket socket) { var response = new ObserveResponse(); var result = new ObserveOperationResult(); var retval = false; if (response.Read(socket)) { retval = true; result.Cas = response.Cas; result.StatusCode = StatusCode; result.Key = response.Key; result.KeyState = response.KeyState; result.PersistenceStats = response.PersistenceStats; result.ReplicationStats = response.ReplicationStats; } this.StatusCode = response.StatusCode.ToStatusCode(); result.PassOrFail(retval, ResultHelper.ProcessResponseData(response.Data, "Failed: ")); return result; }
/// <summary> /// Releases an item back into the pool /// </summary> /// <param name="socket"></param> void ReleaseSocket(PooledSocket socket) { if (this._logger.IsEnabled(LogLevel.Trace)) { this._logger.LogDebug($"Releasing socket ({socket.InstanceID}) - Alive: {this.IsAlive}"); } if (this.IsAlive) { // is it still working (i.e. the server is still connected) if (socket.IsAlive) { // mark the item as free this._freeItems.Push(socket); // signal the event so if someone is waiting for it can reuse this item this._semaphore.Release(); } else { // kill this item socket.Destroy(); // mark ourselves as not working for a while this.MarkAsDead(); // make sure to signal the Acquire so it can create a new conenction // if the failure policy keeps the pool alive this._semaphore.Release(); } } else { // one of our previous sockets has died, so probably all of them // are dead. so, kill the socket (this will eventually clear the pool as well) socket.Destroy(); } }
/// <summary> /// Acquires a new item from the sockIOPool /// </summary> /// <returns>An <see cref="T:PooledSocket"/> instance which is connected to the memcached server, or <value>null</value> if the sockIOPool is dead.</returns> public PooledSocket Acquire() { bool hasDebug = log.IsDebugEnabled; if (hasDebug) { log.Debug("Acquiring stream from pool. " + this.endPoint); } if (!this.isAlive || this.isDisposed) { if (hasDebug) { log.Debug("Pool is dead or disposed, returning null. " + this.endPoint); } return(null); } PooledSocket retval = null; if (!this.semaphore.WaitOne(this.config.QueueTimeout)) { if (hasDebug) { log.Debug("Pool is full, timeouting. " + this.endPoint); } // everyone is so busy throw new TimeoutException(); } // maybe we died while waiting if (!this.isAlive) { if (hasDebug) { log.Debug("Pool is dead, returning null. " + this.endPoint); } return(null); } // do we have free items? if (this.freeItems.Dequeue(out retval)) { #region [ get it from the sockIOPool ] try { retval.Reset(); if (hasDebug) { log.Debug("Socket was reset. " + retval.InstanceId); } return(retval); } catch (Exception e) { log.Error("Failed to reset an acquired socket.", e); this.MarkAsDead(); return(null); } #endregion } // free item sockIOPool is empty if (hasDebug) { log.Debug("Could not get a socket from the pool, Creating a new item. " + this.endPoint); } try { // okay, create the new item retval = this.CreateSocket(); } catch (Exception e) { log.Error("Failed to create socket. " + this.endPoint, e); this.MarkAsDead(); return(null); } if (hasDebug) { log.Debug("Done."); } return(retval); }
protected override bool ReadResponseAsync(PooledSocket socket, Action<bool> next) { var response = new BinaryResponse(); bool ioPending; var retval = response.ReadAsync(socket, (readSuccess) => { if (readSuccess) this.DecodeResult(response.Data); next(readSuccess); }, out ioPending); if (!ioPending && retval) this.Result = this.DecodeResult(response.Data); return retval; }
protected internal virtual PooledSocket CreateSocket() { PooledSocket retval = new PooledSocket(this.endPoint, this.config.ConnectionTimeout, this.config.ReceiveTimeout); return(retval); }
protected override bool ReadResponseAsync(PooledSocket socket, Action<bool> next) { throw new NotImplementedException(); }
protected override IOperationResult ReadResponse(PooledSocket socket) { var response = new BinaryResponse(); var result = new BinaryOperationResult(); if (response.Read(socket)) { this.Result = DecodeResult(response.Data); result.Pass(); return result; } result.Fail("Processing of response failed"); return result; }
protected override bool ReadResponse(PooledSocket socket) { var response = new BinaryResponse(); if (response.Read(socket)) { this.Result = DecodeResult(response.Data); return true; } return false; }
protected override bool ExecuteAction() { Dictionary <IPEndPoint, Dictionary <string, string> > retval = new Dictionary <IPEndPoint, Dictionary <string, string> >(); foreach (MemcachedNode server in this.ServerPool.WorkingServers) { using (PooledSocket ps = server.Acquire()) { if (ps == null) { continue; } ps.SendCommand("stats"); Dictionary <string, string> serverData = new Dictionary <string, string>(StringComparer.Ordinal); while (true) { string line = ps.ReadResponse(); // stat values are terminated by END if (String.Compare(line, "END", StringComparison.Ordinal) == 0) { break; } // expected response is STAT item_name item_value if (line.Length < 6 || String.Compare(line, 0, "STAT ", 0, 5, StringComparison.Ordinal) != 0) { if (log.IsWarnEnabled) { log.Warn("Unknow response: " + line); } continue; } // get the key&value string[] parts = line.Remove(0, 5).Split(' '); if (parts.Length != 2) { if (log.IsWarnEnabled) { log.Warn("Unknow response: " + line); } continue; } // store the stat item serverData[parts[0]] = parts[1]; } retval[server.EndPoint] = serverData; } } this.results = new ServerStats(retval); return(true); }
/// <summary> /// Acquires a new item from the pool /// </summary> /// <returns>An <see cref="T:PooledSocket"/> instance which is connected to the memcached server, or <value>null</value> if the pool is dead.</returns> public PooledSocket Acquire() { bool hasDebug = log.IsDebugEnabled; if (hasDebug) { log.Debug("Acquiring stream from pool. " + this.endPoint); } if (!this.isAlive || this.isDisposed) { if (hasDebug) { log.Debug("Pool is dead or disposed, returning null. " + this.endPoint); } return(null); } PooledSocket retval = null; if (!this.semaphore.WaitOne(this.queueTimeout)) { if (hasDebug) { log.Debug("Pool is full, timeouting. " + this.endPoint); } // everyone is so busy throw new TimeoutException(); } // maybe we died while waiting if (!this.isAlive) { if (hasDebug) { log.Debug("Pool is dead, returning null. " + this.endPoint); } return(null); } // do we have free items? if (this.freeItems.TryPop(out retval)) { #region [ get it from the pool ] try { retval.Reset(); if (hasDebug) { log.Debug("Socket was reset. " + retval.InstanceId); } return(retval); } catch (Exception e) { log.Error("Failed to reset an acquired socket.", e); this.MarkAsDead(); return(null); } #endregion } // free item pool is empty if (hasDebug) { log.Debug("Could not get a socket from the pool, Creating a new item. " + this.endPoint); } try { // okay, create the new item retval = this.CreateSocket(); } catch (Exception e) { log.Error("Failed to create socket. " + this.endPoint, e); // eventhough this item failed the failure policy may keep the pool alive // so we need to make sure to release the semaphore, so new connections can be // acquired or created (otherwise dead conenctions would "fill up" the pool // while the FP pretends that the pool is healthy) semaphore.Release(); this.MarkAsDead(); return(null); } if (hasDebug) { log.Debug("Done."); } return(retval); }
/// <summary> /// Acquires a new item from the pool /// </summary> /// <returns>An <see cref="T:PooledSocket"/> instance which is connected to the memcached server, or <value>null</value> if the pool is dead.</returns> public IPooledSocketResult Acquire() { var result = new PooledSocketResult(); var message = string.Empty; if (_isDebugEnabled) { _logger.LogDebug("Acquiring stream from pool. " + this.endPoint); } if (!this.isAlive || this.isDisposed) { message = "Pool is dead or disposed, returning null. " + this.endPoint; result.Fail(message); if (_isDebugEnabled) { _logger.LogDebug(message); } return(result); } PooledSocket retval = null; if (!this.semaphore.WaitOne(this.queueTimeout)) { message = "Pool is full, timeouting. " + this.endPoint; if (_isDebugEnabled) { _logger.LogDebug(message); } result.Fail(message, new TimeoutException()); // everyone is so busy return(result); } // maybe we died while waiting if (!this.isAlive) { message = "Pool is dead, returning null. " + this.endPoint; if (_isDebugEnabled) { _logger.LogDebug(message); } result.Fail(message); return(result); } // do we have free items? if (this.freeItems.TryPop(out retval)) { #region [ get it from the pool ] try { retval.Reset(); message = "Socket was reset. " + retval.InstanceId; if (_isDebugEnabled) { _logger.LogDebug(message); } result.Pass(message); result.Value = retval; return(result); } catch (Exception e) { message = "Failed to reset an acquired socket."; _logger.LogError(message, e); this.MarkAsDead(); result.Fail(message, e); return(result); } #endregion } // free item pool is empty message = "Could not get a socket from the pool, Creating a new item. " + this.endPoint; if (_isDebugEnabled) { _logger.LogDebug(message); } try { // okay, create the new item var startTime = DateTime.Now; retval = this.CreateSocket(); _logger.LogInformation("MemcachedAcquire-CreateSocket: {0}ms", (DateTime.Now - startTime).TotalMilliseconds); result.Value = retval; result.Pass(); } catch (Exception e) { message = "Failed to create socket. " + this.endPoint; _logger.LogError(message, e); // eventhough this item failed the failure policy may keep the pool alive // so we need to make sure to release the semaphore, so new connections can be // acquired or created (otherwise dead conenctions would "fill up" the pool // while the FP pretends that the pool is healthy) semaphore.Release(); this.MarkAsDead(); result.Fail(message); return(result); } if (_isDebugEnabled) { _logger.LogDebug("Done."); } return(result); }
/// <summary> /// Acquires a new item from the pool /// </summary> /// <returns>An <see cref="T:PooledSocket"/> instance which is connected to the memcached server, or <value>null</value> if the pool is dead.</returns> public PooledSocket Acquire() { if (log.IsDebugEnabled) { log.Debug("Acquiring stream from pool."); } if (!this.IsAlive) { if (log.IsDebugEnabled) { log.Debug("Pool is dead, returning null."); } return(null); } // every release signals the event, so even if the pool becomes full in the meantime // the WaitOne will succeed, and more items will be in the pool than allowed, // so reset the event when an item is inserted this.itemReleasedEvent.Reset(); PooledSocket retval = null; // do we have free items? if (this.freeItems.Dequeue(out retval)) { try { retval.Reset(); if (log.IsDebugEnabled) { log.Debug("Socket was reset. " + retval.InstanceId); } Interlocked.Increment(ref this.workingCount); return(retval); } catch (Exception e) { log.Error("Failed to reset an acquired socket.", e); this.MarkAsDead(); return(null); } } else { // free item pool is empty if (log.IsDebugEnabled) { log.Debug("Could not get a socket from the pool."); } // we are not allowed to create more, so wait for an item to be released back into the pool if (this.workingCount >= this.maxItems) { if (log.IsDebugEnabled) { log.Debug("Pool is full, wait for a release."); } // wait on the event if (!itemReleasedEvent.WaitOne(this.config.ConnectionTimeout, false)) { if (log.IsDebugEnabled) { log.Debug("Pool is still full, timeouting."); } // everyone is working throw new TimeoutException(); } } if (log.IsDebugEnabled) { log.Debug("Creating a new item."); } try { // okay, create the new item retval = this.CreateSocket(); Interlocked.Increment(ref this.workingCount); } catch (Exception e) { log.Error("Failed to create socket.", e); this.MarkAsDead(); return(null); } } if (log.IsDebugEnabled) { log.Debug("Done."); } return(retval); }
public unsafe bool Read(PooledSocket socket) { this.StatusCode = -1; if (!socket.IsAlive) return false; var header = new byte[HeaderLength]; socket.Read(header, 0, header.Length); int dataLength, extraLength; DeserializeHeader(header, out dataLength, out extraLength); var keyHeader = new byte[4]; socket.Read(keyHeader, 0, 4); var vbucket = BinaryConverter.DecodeUInt16(keyHeader, 0); var keylen = BinaryConverter.DecodeUInt16(keyHeader, 2); var keyData = new byte[keylen]; socket.Read(keyData, 0, keylen); Key = BinaryConverter.DecodeKey(keyData); var keyStateData = new byte[1]; socket.Read(keyStateData, 0, keyStateData.Length); KeyState = (ObserveKeyState)keyStateData[0]; var casData = new byte[8]; socket.Read(casData, 0, casData.Length); Cas = BinaryConverter.DecodeUInt64(casData, 0); return this.StatusCode == 0; }
protected override bool ExecuteAction() { // {hashed key -> normal key}: will be used when mapping the returned items back to the original keys Dictionary <string, string> hashedToReal = new Dictionary <string, string>(StringComparer.Ordinal); // {normal key -> hashed key}: we have to hash all keys anyway, so we better cache them to improve performance instead of doing the hashing later again Dictionary <string, string> realToHashed = new Dictionary <string, string>(StringComparer.Ordinal); IMemcachedKeyTransformer transformer = this.ServerPool.KeyTransformer; // and store them with the originals so we can map the returned items // to the original keys foreach (string s in this.keys) { string hashed = transformer.Transform(s); hashedToReal[hashed] = s; realToHashed[s] = hashed; } // map each key to the appropriate server in the pool IDictionary <MemcachedNode, IList <string> > splitKeys = this.ServerPool.SplitKeys(this.keys); // we'll open 1 socket for each server List <PooledSocket> sockets = new List <PooledSocket>(); try { string[] command; // send a 'gets' to each server foreach (KeyValuePair <MemcachedNode, IList <string> > kp in splitKeys) { // gets <keys> // // keys: key key key key command = new string[kp.Value.Count + 1]; command[0] = "gets"; kp.Value.CopyTo(command, 1); for (int i = 1; i < command.Length; i++) { command[i] = realToHashed[command[i]]; } PooledSocket socket = kp.Key.Acquire(); if (socket == null) { continue; } sockets.Add(socket); socket.SendCommand(String.Join(" ", command)); } Dictionary <string, object> retval = new Dictionary <string, object>(StringComparer.Ordinal); Dictionary <string, ulong> cas = new Dictionary <string, ulong>(StringComparer.Ordinal); // process each response and build a dictionary from the results foreach (PooledSocket socket in sockets) { try { GetResponse r; while ((r = GetHelper.ReadItem(socket)) != null) { string originalKey = hashedToReal[r.Key]; retval[originalKey] = this.ServerPool.Transcoder.Deserialize(r.Item); cas[originalKey] = r.CasValue; } } catch (NotSupportedException) { throw; } catch (Exception e) { log.Error(e); } } this.result = retval; this.casValues = cas; } finally { if (sockets != null) { foreach (PooledSocket socket in sockets) { ((IDisposable)socket).Dispose(); } } } return(true); }
bool IMemcachedNode.Execute(PooledSocket socket, IOperation op) { return true; }