Example #1
0
        private async Task AcceptNewClientAsync(
            TcpClient client,
            ConnectionSetting connectionSettings,
            CancellationToken cancellationToken)
        {
            ILifetimeScope newScope = _scope.BeginLifetimeScope(
                ConnectionScopeTag,
                builder =>
            {
                builder.RegisterInstance(
                    new ConnectionInformation(
                        client.Client.LocalEndPoint.ToString(),
                        client.Client.RemoteEndPoint.ToString()));

                builder.RegisterInstance(new SecurableConnection(client.GetStream(), _keyProvider.GetKey(connectionSettings.Certificate)))
                .As <SecurableConnection>()
                .As <IConnectionSecurity>()
                .As <IVariableStreamReader>();

                builder.RegisterInstance(connectionSettings);

                builder.Register(c => c.ResolveKeyed <IAuthenticationTransport>(connectionSettings.Protocol))
                .As <IAuthenticationTransport>();
            }
                );

            var newSession = newScope.ResolveKeyed <IProtocolSession>(connectionSettings.Protocol);

            using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken))
            {
                _sessions.Add(new SessionHolder(newSession, newSession.RunAsync(cancellationToken), newScope));
            }
        }
Example #2
0
        public async Task <Solution> ProcessAsync(
            Document document,
            SyntaxNode syntaxRoot,
            CancellationToken cancellationToken)
        {
            if (m_unwrittenWritableFields == null)
            {
                using (await SemaphoreLock.GetAsync(m_processUsagesLock))
                {
                    // A global analysis must be run before we can do any actual processing, because a field might
                    // be written in a different file than it is declared (even private ones may be split between
                    // partial classes).

                    // It's also quite expensive, which is why it's being done inside the lock, so
                    // that the entire solution is not processed for each input file individually
                    if (m_unwrittenWritableFields == null)
                    {
                        List <Document> allDocuments =
                            document.Project.Solution.Projects.SelectMany(p => p.Documents).ToList();
                        HashSet <IFieldSymbol>[] fields = await Task.WhenAll(
                            allDocuments
                            .AsParallel()
                            .Select(
                                doc => WritableFieldScanner.Scan(doc, cancellationToken)));

                        var writableFields = new ConcurrentDictionary <IFieldSymbol, bool>(
                            fields.SelectMany(s => s).Select(f => new KeyValuePair <IFieldSymbol, bool>(f, true)));

                        await Task.WhenAll(
                            allDocuments.AsParallel()
                            .Select(
                                doc => WriteUsagesScanner.RemoveWrittenFields(
                                    doc,
                                    writableFields,
                                    cancellationToken)));

                        m_unwrittenWritableFields = writableFields;
                    }
                }
            }

            if (m_unwrittenWritableFields.Count == 0)
            {
                // If there are no unwritten writable fields, skip all the rewriting
                return(document.Project.Solution);
            }

            SyntaxNode root = await document.GetSyntaxRootAsync(cancellationToken);

            var application = new ReadonlyRewriter(
                m_unwrittenWritableFields,
                await document.GetSemanticModelAsync(cancellationToken));

            return(document.Project.Solution.WithDocumentSyntaxRoot(document.Id, application.Visit(root)));
        }
Example #3
0
        public async Task RunAsync(CancellationToken cancellationToken)
        {
            _log.Information($"Opening ports: {string.Join(",", _settings.Connections.Select(p => p.Port.ToString()))}");

            TcpListener[] listeners = _settings.Connections
                                      .Select(p => new TcpListener(IPAddress.Any, p.Port))
                                      .ToArray();

            foreach (TcpListener l in listeners)
            {
                l.Start();
            }

            Task <TcpClient>[] listenerTasks = listeners
                                               .Select(tcp => tcp.AcceptTcpClientAsync())
                                               .ToArray();

            while (!cancellationToken.IsCancellationRequested)
            {
                var tasks = new Task[listenerTasks.Length + _sessions.Count];
                Array.Copy(listenerTasks, 0, tasks, 0, listenerTasks.Length);
                _sessions.Select(s => s.Task).ToList().CopyTo(tasks, listenerTasks.Length);

                int  completedIndex = Task.WaitAny(tasks);
                Task task           = tasks[completedIndex];

                if (task is Task <TcpClient> tcpTask)
                {
                    // This is a new connection task
                    TcpClient         client             = tcpTask.Result;
                    ConnectionSetting connectionSettings = _settings.Connections[completedIndex];
                    await AcceptNewClientAsync(client, connectionSettings, cancellationToken);

                    // Wait for another connection
                    listenerTasks[completedIndex] = listeners[completedIndex].AcceptTcpClientAsync();
                }
                else
                {
                    // One of the existing connections is closing
                    using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken))
                    {
                        int           sessionIndex   = completedIndex - listenerTasks.Length;
                        SessionHolder closingSession = _sessions[sessionIndex];
                        _log.Information($"Closing session {closingSession.Session.Id}...");
                        _sessions.RemoveAt(sessionIndex);
                        closingSession.Scope.Dispose();
                    }
                }
            }

            foreach (TcpListener l in listeners)
            {
                l.Stop();
            }
        }
Example #4
0
 public async Task Close(CancellationToken cancellationToken)
 {
     using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken))
     {
         Task[] closing = _sessions.Select(session => session.CloseAsync(cancellationToken)).ToArray();
         Task.WaitAll(closing, cancellationToken);
         Task.WaitAll(_sessionLifetimes.ToArray(), cancellationToken);
         _sessions         = null;
         _sessionLifetimes = null;
     }
 }
Example #5
0
        /// <summary>
        /// EncodeLock is used to encode a SemaphoreLock into a KVPair that can be PUT
        /// </summary>
        /// <param name="l">The SemaphoreLock data</param>
        /// <param name="oldIndex">The index that the data was fetched from, for CAS</param>
        /// <returns>A K/V pair with the lock data encoded in the Value field</returns>
        private KVPair EncodeLock(SemaphoreLock l, ulong oldIndex)
        {
            var jsonValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(l));

            return(new KVPair(string.Join("/", Opts.Prefix, DefaultSemaphoreKey))
            {
                Value = jsonValue,
                Flags = SemaphoreFlagValue,
                ModifyIndex = oldIndex
            });
        }
        public void ShouldReleaseTheLockOnRelease()
        {
            using var semaphore = new SemaphoreSlim(0, 1);
            Assert.AreEqual(0, semaphore.CurrentCount);

            var target = new SemaphoreLock(semaphore);

            target.Release();

            Assert.AreEqual(1, semaphore.CurrentCount);
        }
Example #7
0
        /// <summary>
        /// EncodeLock is used to encode a SemaphoreLock into a KVPair that can be PUT
        /// </summary>
        /// <param name="l">The SemaphoreLock data</param>
        /// <param name="oldIndex">The index that the data was fetched from, for CAS</param>
        /// <returns>A K/V pair with the lock data encoded in the Value field</returns>
        private KVPair EncodeLock(SemaphoreLock l, ulong oldIndex)
        {
            var jsonValue = JsonSerializer.SerializeToUtf8Bytes(l);

            return(new KVPair(string.Join("/", Opts.Prefix, DefaultSemaphoreKey))
            {
                Value = jsonValue,
                Flags = SemaphoreFlagValue,
                ModifyIndex = oldIndex
            });
        }
Example #8
0
        public async Task Close(CancellationToken cancellationToken)
        {
            using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken))
            {
                foreach (SessionHolder session in _sessions)
                {
                    session.Scope.Dispose();
                }

                await Task.WhenAll(_sessions.Select(s => s.Task));

                _sessions = null;
            }
        }
Example #9
0
        public static async Task <IDisposable> LockAsync(this SemaphoreSlim semaphore, CancellationToken cancellationToken)
        {
            var res = new SemaphoreLock(semaphore);

            try {
                await semaphore.WaitAsync(cancellationToken);

                var res2 = res;
                res = null;
                return(res2);
            } finally {
                res?.Reset();
            }
        }
Example #10
0
        public void LockAndSleep()
        {
            ThreadedRepeat(100, (index, threadAsserter) =>
            {
                int id = Thread.CurrentThread.ManagedThreadId;

                using (SemaphoreLock.Lock(semaphore))
                {
                    Thread.Sleep(400);
                    Console.Out.WriteLine("Thread " + id + " IN critical section. " + Interlocked.Increment(ref countIn) + " Threads in critical section.");
                }
                Console.Out.WriteLine("Thread " + id + " OUT critical section. " + Interlocked.Decrement(ref countIn) + " Threads in critical section.");

                threadAsserter.Assert(() => Assert.Less(countIn, 5));
            });
        }
Example #11
0
        public static IDisposable Lock(this SemaphoreSlim semaphore)
        {
            var res = new SemaphoreLock(semaphore);

            try {
                try {
                    semaphore.Wait();
                    var res2 = res;
                    res = null;
                    return(res2);
                } finally {
                    res?.Reset();
                }
            } catch (ObjectDisposedException ex) {
                throw new OperationCanceledException("semaphore was disposed", ex);
            }
        }
Example #12
0
        public static async Task <IDisposable> LockAsync(this SemaphoreSlim semaphore, CancellationToken cancellationToken)
        {
            var res = new SemaphoreLock(semaphore);

            try {
                try {
                    await semaphore.WaitAsync(cancellationToken);

                    var res2 = res;
                    res = null;
                    return(res2);
                } finally {
                    res?.Reset();
                }
            } catch (ObjectDisposedException ex) {
                throw new OperationCanceledException("semaphore was disposed", ex);
            }
        }
Example #13
0
        public void BasicLockingLogic_SeemsToWork()
        {
            // Start one long-running operation and one short-running one.
            // Expected behavior is that short one will wait for long one to complete.

            using (var semaphore = new SemaphoreSlim(1))
            {
                int?longCompletedAt  = null;
                int?shortCompletedAt = null;

                var longTask = Task.Run(async() =>
                {
                    Debug.WriteLine("Long entered.");
                    using (await SemaphoreLock.TakeAsync(semaphore))
                    {
                        Debug.WriteLine("Long acquired lock.");
                        await Task.Delay(5000);
                        Debug.WriteLine("Long completed.");
                        longCompletedAt = Environment.TickCount;
                    }
                });

                var shortTask = Task.Run(async() =>
                {
                    Debug.WriteLine("Short entered.");
                    await Task.Delay(500);
                    Debug.WriteLine("Short starting work.");
                    using (await SemaphoreLock.TakeAsync(semaphore))
                    {
                        Debug.WriteLine("Short acquired lock.");
                        await Task.Delay(50);
                        Debug.WriteLine("Short completed.");
                        shortCompletedAt = Environment.TickCount;
                    }
                });

                Task.WaitAll(longTask, shortTask);

                Assert.IsTrue(shortCompletedAt.HasValue);
                Assert.IsTrue(longCompletedAt.HasValue);
                Assert.IsTrue(longCompletedAt.Value < shortCompletedAt.Value);
            }
        }
Example #14
0
        public void Exception_Unlocks()
        {
            using (var semaphore = new SemaphoreSlim(1))
            {
                try
                {
                    using (SemaphoreLock.Take(semaphore))
                    {
                        throw new InvalidProgramException();
                    }
                }
                catch (InvalidProgramException)
                {
                }

                // If this is false, the lock is still being held.
                Assert.IsTrue(semaphore.Wait(0));
            }
        }
Example #15
0
        public async Task Start(CancellationToken cancellationToken)
        {
            TcpListener[] listeners = _ports
                                      .Select(p => new TcpListener(IPAddress.Any, p))
                                      .ToArray();

            foreach (var l in listeners)
            {
                l.Start();
            }

            Task <TcpClient>[] tasks =
                listeners.Select(tcp => tcp.AcceptTcpClientAsync())
                .ToArray();

            while (!cancellationToken.IsCancellationRequested)
            {
                int taskCompleted = Task.WaitAny(tasks);

                TcpClient client = tasks[taskCompleted].Result;

                using (await SemaphoreLock.GetLockAsync(_sessionSemaphore, cancellationToken))
                {
                    var securableConnection = new SecurableConnection(client.GetStream());
                    securableConnection.Certificate = ServerCertificate;
                    var session = InitiateSession(
                        securableConnection,
                        client.Client.LocalEndPoint,
                        client.Client.RemoteEndPoint);
                    _sessions.Add(session);
                    _sessionLifetimes.Add(session.Start(cancellationToken));
                }

                // Wait for another connection
                tasks[taskCompleted] = listeners[taskCompleted].AcceptTcpClientAsync();
            }

            foreach (var l in listeners)
            {
                l.Stop();
            }
        }
Example #16
0
        public async Task Run()
        {
            var sem   = new SemaphoreLock();
            var mut   = new MutexLock();
            var tasks = new List <Task>();

            Console.WriteLine("Running blocking lock function...");
            for (var i = 0; i < 3; i++)
            {
                tasks.Add(Task.Run(() => RunLock(sem)));
                tasks.Add(Task.Run(() => RunLock(mut)));
            }
            await Task.WhenAll(tasks);

            tasks = new List <Task>();
            Console.WriteLine("Running non-blocking lock function...");
            for (var i = 0; i < 3; i++)
            {
                tasks.Add(RunLockAsync(sem));
                tasks.Add(RunLockAsync(mut));
            }
            await Task.WhenAll(tasks);
        }
Example #17
0
        public async Task SendMessageAsync(ImapMessage message, Encoding encoding, CancellationToken cancellationToken)
        {
            using (await SemaphoreLock.GetLockAsync(_sendSemaphore, cancellationToken))
            {
                var builder = new StringBuilder();
                builder.Append(message.Tag);
                foreach (IMessageData data in message.Data)
                {
                    if (data is LiteralMessageData literal)
                    {
                        builder.Append("}");
                        builder.Append(literal.Length);
                        builder.AppendLine("}");
                        await _connection.WriteAsync(builder.ToString(), encoding, cancellationToken);

                        builder.Clear();
                    }
                    else
                    {
                        if (builder.Length > 0)
                        {
                            builder.Append(" ");
                        }

                        builder.Append(data.ToMessageString());
                    }
                }

                if (builder.Length > 0)
                {
                    _logger.Verbose("IMAP -> " + builder);
                    builder.AppendLine();
                    await _connection.WriteAsync(builder.ToString(), encoding, cancellationToken);
                }
            }
        }
Example #18
0
        /// <summary>
        /// PruneDeadHolders is used to remove all the dead lock holders
        /// </summary>
        /// <param name="l">The SemaphoreLock to prune</param>
        /// <param name="pairs">The list of K/V that currently hold locks</param>
        private static void PruneDeadHolders(SemaphoreLock l, IEnumerable <KVPair> pairs)
        {
            var alive = new HashSet <string>();

            foreach (var pair in pairs)
            {
                if (!string.IsNullOrEmpty(pair.Session))
                {
                    alive.Add(pair.Session);
                }
            }

            var newHolders = new Dictionary <string, bool>(l.Holders);

            foreach (var holder in l.Holders)
            {
                if (!alive.Contains(holder.Key))
                {
                    newHolders.Remove(holder.Key);
                }
            }

            l.Holders = newHolders;
        }
Example #19
0
        /// <summary>
        /// EncodeLock is used to encode a SemaphoreLock into a KVPair that can be PUT
        /// </summary>
        /// <param name="l">The SemaphoreLock data</param>
        /// <param name="oldIndex">The index that the data was fetched from, for CAS</param>
        /// <returns>A K/V pair with the lock data encoded in the Value field</returns>
        private KVPair EncodeLock(SemaphoreLock l, ulong oldIndex)
        {
            var jsonValue = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(l));

            return new KVPair(string.Join("/", Opts.Prefix, DefaultSemaphoreKey))
            {
                Value = jsonValue,
                Flags = SemaphoreFlagValue,
                ModifyIndex = oldIndex
            };
        }
Example #20
0
        /// <summary>
        /// PruneDeadHolders is used to remove all the dead lock holders
        /// </summary>
        /// <param name="l">The SemaphoreLock to prune</param>
        /// <param name="pairs">The list of K/V that currently hold locks</param>
        private static void PruneDeadHolders(SemaphoreLock l, IEnumerable<KVPair> pairs)
        {
            var alive = new HashSet<string>();
            foreach (var pair in pairs)
            {
                if (!string.IsNullOrEmpty(pair.Session))
                {
                    alive.Add(pair.Session);
                }
            }

            var newHolders = new Dictionary<string, bool>(l.Holders);

            foreach (var holder in l.Holders)
            {
                if (!alive.Contains(holder.Key))
                {
                    newHolders.Remove(holder.Key);
                }
            }

            l.Holders = newHolders;
        }
Example #21
0
        /// <summary>
        /// Requests the tracker to update its data set.
        /// </summary>
        /// <remarks>
        /// May be called multiple times concurrently.
        ///
        /// The method returns to signal that the trackerss of all containers
        /// when the method was called have attempted an update to their data.
        /// It may be that some updates failed - all we can say is that we tried.
        ///
        /// Method does not throw exceptions on transient failures, merely logs and ignores them.
        /// </remarks>
        public async Task TryUpdateAsync()
        {
            using var cts = new CancellationTokenSource(Constants.MaxTotalUpdateDuration);

            // If we get this lock, we will actually perform the update.
            using var writeLock = await SemaphoreLock.TryTakeAsync(_updateLock, TimeSpan.Zero);

            if (writeLock == null)
            {
                // Otherwise, we just no-op once the earlier probe request has updated the data.
                await WaitForPredecessorUpdateAsync(cts.Token);

                return;
            }

            using var probeDurationTimer = DockerTrackerMetrics.ProbeDuration.NewTimer();

            IList <ContainerListResponse> allContainers;

            try
            {
                using var listDurationTimer = DockerTrackerMetrics.ListContainersDuration.NewTimer();

                allContainers = await _client.Containers.ListContainersAsync(new ContainersListParameters
                {
                    All = true
                }, cts.Token);
            }
            catch (Exception ex)
            {
                DockerTrackerMetrics.ListContainersErrorCount.Inc();
                _log.Error(Helpers.Debug.GetAllExceptionMessages(ex));
                _log.Debug(ex.ToString()); // Only to verbose output.

                // Errors are ignored - if we fail to get data, we just skip an update and log the failure.
                // The next update will hopefully get past the error.

                // We will not remove the trackers yet but we will unpublish so we don't keep stale data published.
                foreach (var tracker in _containerTrackers.Values)
                {
                    tracker.Unpublish();
                }

                return;
            }

            DockerTrackerMetrics.ContainerCount.Set(allContainers.Count);
            SynchronizeTrackerSet(allContainers);

            // Update each tracker. We do them in parallel to minimize the total time span spent on probing.
            var updateTasks = new List <Task>();

            foreach (var tracker in _containerTrackers.Values)
            {
                updateTasks.Add(tracker.TryUpdateAsync(_client, cts.Token));
            }

            // Only exceptions from the update calls should be terminal exceptions,
            // so it is fine not to catch anything that may be thrown here.
            await Task.WhenAll(updateTasks);

            DockerTrackerMetrics.SuccessfulProbeTime.SetToCurrentTimeUtc();
        }
Example #22
0
 private async Task WaitForPredecessorUpdateAsync(CancellationToken cancel)
 {
     _log.Debug("Will not trigger new probe as it overlaps with existing probe.");
     using var readLock = await SemaphoreLock.TakeAsync(_updateLock, cancel);
 }
Example #23
0
        public void LockingLogic_WithTimeout_SeemsToWork()
        {
            // Start one long-running operation and two short-running ones, where one of the shorts times out on the lock.

            using (var semaphore = new SemaphoreSlim(1))
            {
                int?longCompletedAt   = null;
                int?short1CompletedAt = null;
                int?short2CompletedAt = null;
                int?short1TimedOutAt  = null;

                var longTask = Task.Run(async() =>
                {
                    Debug.WriteLine("Long entered.");
                    using (await SemaphoreLock.TakeAsync(semaphore))
                    {
                        Debug.WriteLine("Long acquired lock.");
                        await Task.Delay(5000);
                        Debug.WriteLine("Long completed.");
                        longCompletedAt = Environment.TickCount;
                    }
                });

                var shortTask1 = Task.Run(async() =>
                {
                    Debug.WriteLine("Short1 entered.");
                    await Task.Delay(500);
                    Debug.WriteLine("Short1 starting work.");
                    var lockInstance = await SemaphoreLock.TryTakeAsync(semaphore, TimeSpan.FromSeconds(1));

                    if (lockInstance == null)
                    {
                        Debug.WriteLine("Short1 timed out.");
                        short1TimedOutAt = Environment.TickCount;
                    }
                    else
                    {
                        using (lockInstance)
                        {
                            Debug.WriteLine("Short1 acquired lock.");
                            await Task.Delay(50);
                            Debug.WriteLine("Short1 completed.");
                            short1CompletedAt = Environment.TickCount;
                        }
                    }
                });

                var shortTask2 = Task.Run(async() =>
                {
                    Debug.WriteLine("Short2 entered.");
                    await Task.Delay(500);
                    Debug.WriteLine("Short2 starting work.");
                    using (await SemaphoreLock.TakeAsync(semaphore))
                    {
                        Debug.WriteLine("Short2 acquired lock.");
                        await Task.Delay(50);
                        Debug.WriteLine("Short2 completed.");
                        short2CompletedAt = Environment.TickCount;
                    }
                });

                Task.WaitAll(longTask, shortTask1, shortTask2);

                Assert.IsFalse(short1CompletedAt.HasValue);
                Assert.IsTrue(short1TimedOutAt.HasValue);
                Assert.IsTrue(short2CompletedAt.HasValue);
                Assert.IsTrue(longCompletedAt.HasValue);
                Assert.IsTrue(short1TimedOutAt.Value < longCompletedAt.Value);
                Assert.IsTrue(short1TimedOutAt.Value < short2CompletedAt.Value);
                Assert.IsTrue(longCompletedAt.Value < short2CompletedAt.Value);
            }
        }