public MemcachedNode( EndPoint endpoint, ISocketPoolConfiguration socketPoolConfig, ILogger logger) { this.endPoint = endpoint; this.config = socketPoolConfig; if (socketPoolConfig.ConnectionTimeout.TotalMilliseconds >= Int32.MaxValue) { throw new InvalidOperationException("ConnectionTimeout must be < Int32.MaxValue"); } if (socketPoolConfig.InitPoolTimeout.TotalSeconds < 1) { _initPoolTimeout = new TimeSpan(0, 1, 0); } else { _initPoolTimeout = socketPoolConfig.InitPoolTimeout; } _logger = logger; this.internalPoolImpl = new InternalPoolImpl(this, socketPoolConfig, _logger); }
/// <summary> /// Gets a value indicating whether the server is working or not. /// If the server is back online, we'll ercreate the internal socket pool and mark the server as alive so operations can target it. /// </summary> /// <returns>true if the server is alive; false otherwise.</returns> public bool Ping() { // is the server working? if (this.IsAlive) { return(true); } // this codepath is (should be) called very rarely // if you get here hundreds of times then you have bigger issues // and try to make the memcached instaces more stable and/or increase the deadTimeout try { // we could connect to the server, let's recreate the socket pool lock (MemcachedNode.Locker) { if (this._isDisposed) { return(false); } // try to connect to the server using (var socket = this.CreateSocket()) { if (this._logger.IsEnabled(LogLevel.Debug)) { this._logger.LogDebug($"Try to connect to the memcached server: {this.EndPoint}"); } } if (this.IsAlive) { return(true); } // it's easier to create a new pool than reinitializing a dead one // rewrite-then-dispose to avoid a race condition with Acquire (which does no locking) var oldPool = this._internalPoolImpl; var newPool = new InternalPoolImpl(this, this._config); Interlocked.Exchange(ref this._internalPoolImpl, newPool); try { oldPool.Dispose(); } catch { } } return(true); } catch { return(false); // could not reconnect } }
public MemcachedNode(IPEndPoint endpoint, ISocketPoolConfiguration socketPoolConfig) { this.endPoint = endpoint; this.config = socketPoolConfig; if (socketPoolConfig.ConnectionTimeout.TotalMilliseconds >= Int32.MaxValue) { throw new InvalidOperationException("ConnectionTimeout must be < Int32.MaxValue"); } this.internalPoolImpl = new InternalPoolImpl(this, socketPoolConfig); }
internal MemcachedNode(IPEndPoint endpoint, ISocketPoolConfiguration config) { endPoint = endpoint; this.config = config; internalPoolImpl = new InternalPoolImpl(endpoint, config); deadTimeout = (int)config.DeadTimeout.TotalSeconds; if (deadTimeout < 0) { throw new InvalidOperationException("deadTimeout must be >= TimeSpan.Zero"); } }
public MemcachedNode(EndPoint endpoint, ISocketPoolConfiguration config) { if (config.ConnectionTimeout.TotalMilliseconds >= Int32.MaxValue) { throw new InvalidOperationException($"ConnectionTimeout must be < {Int32.MaxValue}"); } this._logger = Logger.CreateLogger <IMemcachedNode>(); this._endpoint = endpoint; this._config = config; this._internalPoolImpl = new InternalPoolImpl(this, this._config); }
/// <summary> /// Gets a value indicating whether the server is working or not. /// /// If the server is not working, and the "being dead" timeout has been expired it will reinitialize itself. /// </summary> /// <remarks>It's possible that the server is still not up & running so the next call to <see cref="M:Acquire"/> could mark the instance as dead again.</remarks> /// <returns></returns> internal bool Ping() { // is the server working? if (internalPoolImpl.IsAlive) { return(true); } // deadTimeout was set to 0 which means forever if (deadTimeout == 0) { return(false); } TimeSpan diff = DateTime.UtcNow - internalPoolImpl.MarkedAsDeadUtc; // only do the real check if the configured time interval has passed if (diff.TotalSeconds < deadTimeout) { return(false); } // it's (relatively) safe to lock on 'this' since // this codepath is (should be) called very rarely // if you get here hundreds of times then you have bigger issues // and try to make the memcached instaces more stable and/or increase the deadTimeout lock (this) { if (internalPoolImpl.IsAlive) { return(true); } // it's easier to create a new pool than reinitializing a dead one internalPoolImpl.Dispose(); if (endPoint != null) { internalPoolImpl = new InternalPoolImpl(endPoint, config); } } return(true); }
/// <summary> /// Releases all resources allocated by this instance /// </summary> public void Dispose() { GC.SuppressFinalize(this); // this is not a graceful shutdown // if someone uses a pooled item then 99% that an exception will be thrown // somewhere. But since the dispose is mostly used when everyone else is finished // this should not kill any kittens lock (this) { if (isDisposed) { return; } isDisposed = true; internalPoolImpl.Dispose(); internalPoolImpl = null; } }