public void CopyOnWriteList_Should_AddRange_And_Count() { var list = new CopyOnWriteList<string>(); list.Add("one"); list.Add("two"); Assert.AreEqual(2, list.Count); list.AddRange(new[] { "three", "four" }); Assert.AreEqual(4, list.Count); CollectionAssert.AreEqual(new[] { "one", "two", "three", "four" }, list); }
/// <summary> /// Create the min amount of connections, if the pool is empty /// </summary> /// <exception cref="System.Net.Sockets.SocketException" /> internal Task <Connection[]> MaybeCreateCorePool() { var coreConnections = _config.GetPoolingOptions(ProtocolVersion).GetCoreConnectionsPerHost(_distance); if (!_connections.Any(c => c.IsClosed) && _connections.Count >= coreConnections) { //Pool has the appropriate size return(TaskHelper.ToTask(_connections.ToArray())); } if (!_poolModificationSemaphore.Wait(0)) { //Couldn't enter semaphore, check if there is a connection available to yield var opened = _connections.Where(c => !c.IsClosed).ToArray(); if (opened.Length > 0) { return(TaskHelper.ToTask(opened)); } var alreadyOpening = _openingConnections; if (alreadyOpening != null && alreadyOpening.Length > 0) { return(Task.Factory.ContinueWhenAny(alreadyOpening, t => { if (t.Status == TaskStatus.RanToCompletion) { return new[] { t.Result }; } if (t.Exception != null) { throw t.Exception.InnerException; } throw new TaskCanceledException("Could not get an opened connection because the Task was cancelled"); }, TaskContinuationOptions.ExecuteSynchronously)); } //There isn't a connection available yet, enter semaphore _poolModificationSemaphore.Wait(); } //Semaphore entered //Remove closed connections from the pool var toRemove = _connections.Where(c => c.IsClosed).ToArray(); foreach (var c in toRemove) { _connections.Remove(c); } var opening = new List <Task <Connection> >(); if (_openingConnections != null) { opening.AddRange(_openingConnections); } while (_connections.Count + opening.Count < coreConnections) { opening.Add(CreateConnection()); } if (opening.Count == 0) { if (_connections.Count == 0) { return(TaskHelper.FromException <Connection[]>(new DriverInternalError("Could not create a connection and no connections found in pool"))); } _poolModificationSemaphore.Release(); return(TaskHelper.ToTask(_connections.ToArray())); } var openingArray = opening.ToArray(); _openingConnections = openingArray; //Clean up when all open task finished var allCompleted = Task.Factory.ContinueWhenAll(openingArray, tasks => { _connections.AddRange(tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Select(t => t.Result).ToArray()); if (_connections.Count == coreConnections) { Logger.Info("{0} connection(s) to host {1} {2} created successfully", coreConnections, _host.Address, _connections.Count < 2 ? "was" : "were"); _host.BringUpIfDown(); } _openingConnections = null; var connectionsArray = _connections.ToArray(); _poolModificationSemaphore.Release(); if (connectionsArray.Length == 0 && tasks.All(t => t.Status != TaskStatus.RanToCompletion)) { //Pool could not be created Logger.Info("Connection pool to host {0} could not be created", _host.Address); //There are multiple problems, but we only care about one // ReSharper disable once PossibleNullReferenceException throw tasks.First().Exception.InnerException; } return(connectionsArray); }, TaskContinuationOptions.ExecuteSynchronously); //yield the first connection available return(Task.Factory.ContinueWhenAny(openingArray, t => { if (t.Status == TaskStatus.RanToCompletion) { return new[] { t.Result }; } if (t.Exception != null) { throw t.Exception.InnerException; } throw new TaskCanceledException("Could not get an opened connection because the Task was cancelled"); }, TaskContinuationOptions.ExecuteSynchronously) .ContinueWith(t => { if (t.Status != TaskStatus.RanToCompletion) { //The first connection failed //Wait for all to complete return allCompleted; } return TaskHelper.ToTask(t.Result); }, TaskContinuationOptions.ExecuteSynchronously).Unwrap()); }