private void AssertReadLockContended(AsyncUpgradeableReaderWriterLock rwLock)
 {
     using (CancellationTokenSource timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(200)))
     {
         Assert.Throws <TaskCanceledException>(() => rwLock.EnterReadLockAsync(timeout.Token).ConfigureAwait(false).GetAwaiter().GetResult());
     }
 }
 private void AssertReadLockUncontended(AsyncUpgradeableReaderWriterLock rwLock)
 {
     using (CancellationTokenSource timeout = new CancellationTokenSource(TimeSpan.FromMilliseconds(200)))
         // Will throw an OperationCanceledException if unable to get the lock within 200 ms
         using (rwLock.EnterReadLockAsync(timeout.Token).ConfigureAwait(false).GetAwaiter().GetResult())
         {
             ;
         }
 }
 private Task HoldReadLockAsync(AsyncUpgradeableReaderWriterLock rwLock, ManualResetEventSlim setWhenLockHeld, CancellationToken cancellationToken)
 {
     return(Task.Run(() =>
     {
         using (rwLock.EnterReadLockAsync(CancellationToken.None).ConfigureAwait(false).GetAwaiter().GetResult())
         {
             setWhenLockHeld.Set();
             cancellationToken.WaitHandle.WaitOne();
         }
     }));
 }
Beispiel #4
0
        public async Task LoadRecSourceAsync(Func <ITrainableJsonRecSource> recSourceFactory, string name, bool replaceExisting, CancellationToken cancellationToken)
        {
            // Acquire read lock on current list, write lock on pending list
            // If name already exists on current list and replaceExisting = false, throw.
            // If name already exists on pending list, throw.
            // Otherwise, add name to pending list, release locks, and proceed.

            using (var recSourcesReadLock = await m_recSourcesLockAsync.EnterReadLockAsync(cancellationToken).ConfigureAwait(false))
                using (var pendingRecSourcesWriteLock = await m_pendingRecSourcesLockAsync.EnterWriteLockAsync(cancellationToken).ConfigureAwait(false))
                {
                    if (m_recSources.ContainsKey(name) && !replaceExisting)
                    {
                        throw new RecServiceErrorException(new Error(errorCode: ErrorCodes.Unknown,
                                                                     message: string.Format("A recommendation source with the name \"{0}\" already exists.", name)));
                    }
                    if (m_pendingRecSources.Contains(name))
                    {
                        throw new RecServiceErrorException(new Error(errorCode: ErrorCodes.Unknown,
                                                                     message: string.Format("A recommendation source with the name \"{0}\" is currently being trained.", name)));
                    }

                    m_pendingRecSources.Add(name);
                }

            try
            {
                // Need to hold read lock on training data while training so that a retrain can't happen while we're training here.
                // Rec sources must be trained with the current m_trainingData, not an old version.
                using (var trainingDataReadLock = await m_trainingDataLockAsync.EnterReadLockAsync(cancellationToken).ConfigureAwait(false))
                {
                    if (m_trainingData == null && !m_finalized)
                    {
                        throw new RecServiceErrorException(new Error(errorCode: ErrorCodes.NoTrainingData,
                                                                     message: "A reload/retrain in low memory mode failed, leaving the rec service without training data or rec sources. Issue a ReloadTrainingData command to load training data, then load rec sources."));
                    }
                    else if (m_trainingData == null && m_finalized)
                    {
                        throw new RecServiceErrorException(new Error(errorCode: ErrorCodes.Finalized,
                                                                     message: "Rec sources have been finalized. A non-finalized retrain must be invoked to be able to add rec sources."));
                    }

                    ITrainableJsonRecSource recSource = recSourceFactory();
                    Logging.Log.InfoFormat("Training rec source with name \"{0}\", replaceExisting={1}: {2}", name, replaceExisting, recSource);
                    Stopwatch timer = Stopwatch.StartNew();

                    recSource.Train(m_trainingData, m_usernames, cancellationToken);
                    timer.Stop();
                    Logging.Log.InfoFormat("Trained rec source {0}. Took {1}", name, timer.Elapsed);

                    using (var recSourcesWriteLock = await m_recSourcesLockAsync.EnterWriteLockAsync(cancellationToken).ConfigureAwait(false))
                        using (var pendingRecSourcesWriteLock = await m_pendingRecSourcesLockAsync.EnterWriteLockAsync(cancellationToken).ConfigureAwait(false))
                        {
                            m_recSources[name]         = recSource;
                            m_recSourceFactories[name] = recSourceFactory;
                            m_pendingRecSources.Remove(name);
                        }
                }
            }
            catch (Exception)
            {
                m_pendingRecSources.Remove(name);
                throw;
            }

            Logging.Log.InfoFormat("Loaded rec source {0}.", name);
            GC.Collect();
            Logging.Log.InfoFormat("Memory use: {0} bytes", GC.GetTotalMemory(forceFullCollection: false));
        }