static Program() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); s_mainWindow = new MainWindow(); s_singleInstanceMutex = InterprocessLock.GetNamedMutex(); s_clients = new Lazy <IHubConnectionContext <dynamic> >(() => GlobalHost.ConnectionManager.GetHubContext <DataHub>().Clients); Global = MainWindow.Model.Global; }
private async void RepositoryPublishMain() { //before we get going, lets stall for a few seconds. We aren't a critical operation, and I don't //want to get in the way of the application starting up. await Task.Delay(BackgroundStartupDelay).ConfigureAwait(false); InterprocessLock backgroundLock = null; //we can't do our normal using trick in this situation. try { //we have two totally different modes: Either WE'RE the background processor or someone else is. //if we are then we move on to start publishing. If someone else is then we just poll //the lock to see if whoever owned it has exited. backgroundLock = GetLock(0); while ((backgroundLock == null) && (m_StopRequested == false)) { //we didn't get the lock - so someone else is currently the main background thread. SleepUntilNextCheck(m_MultiprocessLockCheckInterval); backgroundLock = GetLock(0); } //if we got the lock then we want to go ahead and perform background processing. if (backgroundLock != null) { //here is where we want to keep looping - it will return every time the subscription changes. await RepositoryPublishLoop().ConfigureAwait(false); //release the lock; we'll get it on the next round. backgroundLock.Dispose(); backgroundLock = null; } } catch (Exception ex) { GC.KeepAlive(ex); } finally { if (backgroundLock != null) { backgroundLock.Dispose(); } lock (m_SessionPublishThreadLock) { //clear the dispatch thread variable since we're about to exit. m_SessionPublishThread = null; //we want to write out that we had a problem and mark that we're failed so we'll get restarted. m_SessionPublishThreadFailed = true; System.Threading.Monitor.PulseAll(m_SessionPublishThreadLock); } } }
private bool IsSessionRunning(Guid sessionId) { // Hmmm, is it really done, or still running after calling EndSession()? using (InterprocessLock sessionLock = InterprocessLockManager.Lock(this, m_SessionLockFolder, sessionId.ToString(), 0, true)) { if (sessionLock == null) { // It's holding the lock, so it must still be active! return(true); } // Otherwise, it has released the lock, so it really is closed as it said. We're good. return(false); } }
private void Initialize() { if (m_Initialized) { return; } //we need to grab a lock on this session to prevent it from being transported to the same endpoint at the same time. string sessionWorkingFileNamePath = GenerateTemporarySessionFileNamePath(); //we aren't going to do Using - we keep the lock! if (m_SessionTransportLock == null) //if we are retrying to initialize after a failure we may already have it. { m_SessionTransportLock = InterprocessLockManager.Lock(this, GenerateTemporarySessionPath(), GenerateTemporarySessionFileName(), 0, true); } //we aren't waiting to see if we can get the lock - if anyone else has it they must be transferring the session. if (m_SessionTransportLock != null) { //Lets figure out if we're restarting a previous send or starting a new one. m_TempSessionProgressFileNamePath = sessionWorkingFileNamePath + ".txt"; m_BytesWritten = 0; if (File.Exists(m_TempSessionProgressFileNamePath)) { //load up the existing transfer state. try { m_BytesWritten = LoadProgressTrackingFile(); } catch { //oh well, assume no progress. m_PerformCleanup = true; SafeDeleteFile(m_TempSessionProgressFileNamePath); } } else { //make sure we didn't get started, but not finish, writing our temp file. SafeDeleteFile(m_TempSessionProgressFileNamePath); } m_Initialized = true; } }
/// <summary> /// Dispose managed resources /// </summary> /// <param name="releaseManaged"></param> protected virtual void Dispose(bool releaseManaged) { if (releaseManaged) { //we have to get rid of the lock if we have it. m_SessionTransportLock.SafeDispose(); m_SessionTransportLock = null; m_SessionFileStream.SafeDispose(); m_SessionFileStream = null; //and flush any temporary files we have if they aren't in a persistent repository. if (m_DeleteTemporaryFilesOnDispose) { SafeDeleteTemporaryData(); } } }
/// <summary> /// Get the unique lock for the active session, to be held until the session exits. /// </summary> private void GetSessionFileLock() { if (m_SessionFileLock != null) { return; } var sessionId = Log.SessionSummary.Id; var sessionLockName = sessionId.ToString(); try { m_SessionFileLock = InterprocessLockManager.Lock(this, m_SessionLockFolder, sessionLockName, 0, true); if (m_SessionFileLock == null) { Log.Write(LogMessageSeverity.Information, LogCategory, "Loupe Agent unable to get the unique lock for a new session", "The Loupe Agent's FileMessenger was not able to lock this active session as Running. " + "This could interfere with efficiently distinguishing whether this session has crashed or is still running."); #if DEBUG if (Debugger.IsAttached) { Debugger.Break(); } #endif } } catch (Exception ex) //we don't want failure to get the session file lock to be fatal... { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Information, LogWriteMode.Queued, ex, true, LogCategory, "Loupe Agent unable to get the unique lock for a new session due to " + ex.GetBaseException().GetType(), "The Loupe Agent's FileMessenger was not able to lock this active session as Running. " + "This could interfere with efficiently distinguishing whether this session has crashed or is still running."); } } }
/// <summary> /// Release the unique lock for the active session, to be called when the FileMessenger gets disposed. /// </summary> private void ReleaseSessionFileLock() { if (m_SessionFileLock == null) { return; } try { m_SessionFileLock.Dispose(); m_SessionFileLock = null; } catch (Exception ex) { Log.Write(LogMessageSeverity.Information, LogWriteMode.Queued, ex, LogCategory, "Loupe Agent got an error while releasing the unique lock for this session", "The Loupe Agent's FileMessenger was not able to properly release the lock as this session exits. " + "This will likely take care of itself as the process exits, but an exception here is unexpected and unusual."); if (m_SessionFileLock != null && m_SessionFileLock.IsDisposed) { m_SessionFileLock = null; } } }
static Program() { s_singleInstanceMutex = InterprocessLock.GetNamedMutex(false); }
private void Initialize() { if (m_Initialized) { return; } //we need to grab a lock on this session to prevent it from being transported to the same endpoint at the same time. var sessionWorkingFileNamePath = GenerateTemporarySessionFileNamePath(); //we aren't going to do Using - we keep the lock! if (m_SessionTransportLock == null) //if we are retrying to initialize after a failure we may already have it. { m_SessionTransportLock = InterprocessLockManager.Lock(this, GenerateTemporarySessionPath(), GenerateTemporarySessionFileName(), 0, true); } //we aren't waiting to see if we can get the lock - if anyone else has it they must be transferring the session. if (m_SessionTransportLock != null) { //grab a lock on the actual data file - if it's not there, no point in continuing. m_SessionFileStream = Repository.LoadSessionFileStream(SessionId, FileId.Value); //calculate our SHA1 Hash... try { using (var csp = SHA1.Create()) { m_SessionFileHash = BitConverter.ToString(csp.ComputeHash(m_SessionFileStream)); } //now back up the stream to the beginning so we can send the actual data. m_SessionFileStream.Position = 0; } catch (Exception ex) { if (!Log.SilentMode) { Log.Write(LogMessageSeverity.Error, LogWriteMode.Queued, ex, RepositoryPublishClient.LogCategory, "Unable to calculate hash for session file due to " + ex.GetType() + " exception.", "The upload will proceed but without the hash to check the accuracy of the upload.\r\nException: {0}\r\n{1}\r\n", ex.GetType(), ex.Message); } } //Lets figure out if we're restarting a previous send or starting a new one. m_TempSessionProgressFileNamePath = sessionWorkingFileNamePath; m_BytesWritten = 0; if (File.Exists(m_TempSessionProgressFileNamePath)) { //load up the existing transfer state. try { m_BytesWritten = LoadProgressTrackingFile(); } catch { //oh well, assume no progress. m_PerformCleanup = true; SafeDeleteFile(m_TempSessionProgressFileNamePath); } } else { //make sure we didn't get started, but not finish, writing our temp file. SafeDeleteFile(m_TempSessionProgressFileNamePath); } m_Initialized = true; } }
/// <summary> /// Execute repository maintenance on a background thread. /// </summary> private void AsyncPerformMaintenance(object state) { try { //make sure if we log something it never blocks, since that could ultimately result in a deadlock. Publisher.ThreadMustNotBlock(); bool collectionChanged = false; //since external objects can freely modify our configuration, save a copy so we run with a consistent perspective. int maxSizeMegabytes = MaxSizeMegabytes; int maxAgeDays = MaxAgeDays; if (m_LoggingEnabled) { Log.Write(LogMessageSeverity.Information, LogCategory, "Starting Repository Maintenance", "Starting repository maintenance on repository stored at {0}, removing fragments older than {1} days and keeping the repository under {2:N0} megabytes.", RepositoryPath, maxAgeDays, maxSizeMegabytes); } //before we do anything more, we have to get the maintenance lock. using (InterprocessLock maintenanceLock = InterprocessLockManager.Lock(this, m_RepositoryPath, MutiprocessLockName, 0, true)) { if (maintenanceLock == null) { //we couldn't get the lock, so no maintenance today. if (m_LoggingEnabled) { Log.Write(LogMessageSeverity.Warning, LogCategory, "Unable to Perform Maintenance - Repository Locked", "Unable to get the maintenance file lock on the repository stored at {0}, not performing maintenance.", RepositoryPath); } return; } //We may not be able to do pruning - we used to be used just for index DB update (not valid any more) if ((string.IsNullOrEmpty(ApplicationName) == false) && (Log.IsSessionEnding == false)) { //find out if there is any maintenance to do - we start by age and it'll let us know if we have anything else to do. bool capacityPruningRequired; bool sessionsRemoved = ProcessPruneForAge(maxAgeDays, maxSizeMegabytes, out capacityPruningRequired); collectionChanged = (collectionChanged || sessionsRemoved); //make sure capacity pruning is enabled. if (maxSizeMegabytes <= 0) { capacityPruningRequired = false; } //anything more to do? if ((capacityPruningRequired) && (Log.IsSessionEnding == false)) { sessionsRemoved = ProcessPruneForSize(MaxSizeMegabytes); collectionChanged = (collectionChanged || sessionsRemoved); } ////and do crashed session conversion. //bool crashedSessionsChanged = ProcessCrashedSessionConversion(); //collectionChanged = (collectionChanged || crashedSessionsChanged); } } if (collectionChanged) { OnCollectionChanged(new CollectionChangeEventArgs(CollectionChangeAction.Refresh, null)); } if (m_LoggingEnabled) { Log.Write(LogMessageSeverity.Information, LogCategory, "Repository Maintenance Complete", "Repository maintenance completed on repository stored at {0}", RepositoryPath); } } catch (Exception ex) { GC.KeepAlive(ex); if (m_LoggingEnabled) { Log.Write(LogMessageSeverity.Warning, LogCategory, "Unable to Perform Repository Maintenance", "Unable to complete repository maintenance successfully due to an exception: {0}", ex); } } finally { //now we need to mark that we're done, and this is done with a lock for multithread purity. lock (m_Lock) { m_PerformingMaintenance = false; System.Threading.Monitor.PulseAll(m_Lock); } } }