/// <summary> /// Processes the rollover of this file. /// </summary> private void m_rolloverTask_Running(object sender, EventArgs <ScheduledTaskRunningReason> e) { //the nature of how the ScheduledTask works //gaurentees that this function will not be called concurrently //The worker can be disposed either via the Stop() method or //the Dispose() method. If via the dispose method, then //don't do any cleanup. if (m_disposed && e.Argument == ScheduledTaskRunningReason.Disposing) { Log.Publish(MessageLevel.Info, "Rollover thread is Disposing"); m_waitForEmptyActiveQueue.Dispose(); return; } lock (m_syncRoot) { int count = m_activeQueue.Count; if (count == 0) { m_waitForEmptyActiveQueue.Set(); return; } //Swap active and processing. SortedPointBuffer <TKey, TValue> swap = m_activeQueue; m_activeQueue = m_processingQueue; m_processingQueue = swap; m_activeQueue.IsReadingMode = false; //Should do nothing, but just to be sure. m_waitForEmptyActiveQueue.Set(); m_currentTransactionIdRollingOver = m_latestTransactionId; m_currentlyRollingOverFullQueue = m_processingQueue.IsFull; } //ToDo: The current inner loop for inserting random data is the sorting process here. //ToDo: If the current speed isn't fast enough, this can be multithreaded to improve //ToDo: the insert performance. However, at this time, the added complexity is //ToDo: not worth it since write speeds are already blazing fast. try { m_processingQueue.IsReadingMode = true; //Very CPU intensive. This does a sort on the incoming measurements. Profiling shows that about 33% of the time is spent sorting elements. PrebufferRolloverArgs <TKey, TValue> args = new PrebufferRolloverArgs <TKey, TValue>(m_processingQueue, m_currentTransactionIdRollingOver); m_onRollover(args); m_processingQueue.IsReadingMode = false; //Clears the queue } catch (Exception ex) { Log.Publish(MessageLevel.Critical, "Rollover process unhandled exception", "The rollover process threw an unhandled exception. There is likely data loss that will result from this exception", null, ex); } m_currentlyRollingOverFullQueue = false; }
private void RolloverTask_Running(object sender, EventArgs <ScheduledTaskRunningReason> e) { //The worker can be disposed either via the Stop() method or //the Dispose() method. If via the dispose method, then //don't do any cleanup. if (m_disposed && e.Argument == ScheduledTaskRunningReason.Disposing) { Log.Publish(MessageLevel.Info, "Rollover thread is Disposing"); m_rolloverComplete.Dispose(); return; } List <SortedTreeTable <TKey, TValue> > pendingTables1; List <SortedTreeTable <TKey, TValue> > pendingTables2; List <SortedTreeTable <TKey, TValue> > pendingTables3; long sequenceNumber; lock (m_syncRoot) { pendingTables1 = m_pendingTables1; pendingTables2 = m_pendingTables2; pendingTables3 = m_pendingTables3; sequenceNumber = m_lastCommitedSequenceNumber; m_pendingTables1 = new List <SortedTreeTable <TKey, TValue> >(); m_pendingTables2 = new List <SortedTreeTable <TKey, TValue> >(); m_pendingTables3 = new List <SortedTreeTable <TKey, TValue> >(); m_rolloverComplete.Set(); } TKey startKey = new TKey(); TKey endKey = new TKey(); startKey.SetMax(); endKey.SetMin(); Log.Publish(MessageLevel.Info, "Pending Tables Report", "Pending Tables V1: " + pendingTables1.Count + " V2: " + pendingTables2.Count + " V3: " + pendingTables3.Count); List <ArchiveTableSummary <TKey, TValue> > summaryTables = new List <ArchiveTableSummary <TKey, TValue> >(); foreach (SortedTreeTable <TKey, TValue> table in pendingTables1) { ArchiveTableSummary <TKey, TValue> summary = new ArchiveTableSummary <TKey, TValue>(table); if (!summary.IsEmpty) { summaryTables.Add(summary); if (startKey.IsGreaterThan(summary.FirstKey)) { summary.FirstKey.CopyTo(startKey); } if (endKey.IsLessThan(summary.LastKey)) { summary.LastKey.CopyTo(endKey); } } } foreach (SortedTreeTable <TKey, TValue> table in pendingTables2) { ArchiveTableSummary <TKey, TValue> summary = new ArchiveTableSummary <TKey, TValue>(table); if (!summary.IsEmpty) { summaryTables.Add(summary); if (startKey.IsGreaterThan(summary.FirstKey)) { summary.FirstKey.CopyTo(startKey); } if (endKey.IsLessThan(summary.LastKey)) { summary.LastKey.CopyTo(endKey); } } } foreach (SortedTreeTable <TKey, TValue> table in pendingTables3) { ArchiveTableSummary <TKey, TValue> summary = new ArchiveTableSummary <TKey, TValue>(table); if (!summary.IsEmpty) { summaryTables.Add(summary); if (startKey.IsGreaterThan(summary.FirstKey)) { summary.FirstKey.CopyTo(startKey); } if (endKey.IsLessThan(summary.LastKey)) { summary.LastKey.CopyTo(endKey); } } } long size = summaryTables.Sum(x => x.SortedTreeTable.BaseFile.ArchiveSize); if (summaryTables.Count > 0) { using (UnionTreeStream <TKey, TValue> reader = new UnionTreeStream <TKey, TValue>(summaryTables.Select(x => new ArchiveTreeStreamWrapper <TKey, TValue>(x)), true)) { SortedTreeTable <TKey, TValue> newTable = m_createNextStageFile.CreateArchiveFile(startKey, endKey, size, reader, null); using (ArchiveListEditor <TKey, TValue> edit = m_list.AcquireEditLock()) { //Add the newly created file. edit.Add(newTable); foreach (SortedTreeTable <TKey, TValue> table in pendingTables1) { edit.TryRemoveAndDelete(table.ArchiveId); } foreach (SortedTreeTable <TKey, TValue> table in pendingTables2) { edit.TryRemoveAndDelete(table.ArchiveId); } foreach (SortedTreeTable <TKey, TValue> table in pendingTables3) { edit.TryRemoveAndDelete(table.ArchiveId); } } } } m_lastRolledOverSequenceNumber.Value = sequenceNumber; if (RolloverComplete != null) { RolloverComplete(sequenceNumber); } }