static int Main(string[] args) { AppDomain currentDomain = AppDomain.CurrentDomain; currentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledExceptionHandler); Application.SetUnhandledExceptionMode(UnhandledExceptionMode.CatchException); Application.ThreadException += new System.Threading.ThreadExceptionEventHandler(UnhandledThreadExceptionHandler); //ObjectStore.WaitForThenBlockBackgroundThreads(10000); try { if (!CommandLine.Parser.Default.ParseArguments(args, options)) { Console.WriteLine("Invalid command line options: {0}", options.GetUsage()); return(-1); } ScheduleEntriesInjector.InjectReplacementScheduleEntriesMethods(); //MergeProgramsInjector.ReplaceMergePrograms(); MergeProgramsInjector.ReplaceCheckIfProgramsMatch(); // new SchedulerWorkerInjector().ReplaceThreadSetup(); StoredObjectsEnumeratorInjector.ReplaceUpdate(); ObjectStore objStore = Util.object_store; MxfImporter.Import(new StreamReader(options.inputMxfPath).BaseStream, Util.object_store, MxfImportProgressCallback); Console.WriteLine("Waiting for any background threads to complete."); Util.WaitForBackgroundThreads(); } catch (Exception e) { Console.WriteLine("Exception occurred: {0} {1}", e, e.StackTrace); return(-1); } if (options.reindexWhenDone) { reindexDatabase(); } return(0); }
private void ReplacementMergeScheduleEntriesInner(ScheduleEntry[] scheduleEntriesToMerge) { if (scheduleEntriesToMerge.Count() == 0) { return; // nothing to do. } Util.WaitForBackgroundThreads(); Service targetService = scheduleEntriesToMerge[0].Service; Util.Trace(TraceLevel.Info, "Processing schedule entries for {0}", targetService); long id = targetService.Id; FixServiceAssignmentsForServiceChannels(targetService); Util.WaitForBackgroundThreads(); OriginalMergeScheduleEntries(scheduleEntriesToMerge); Util.WaitForBackgroundThreads(); ScheduleEntries self = ThisAsScheduleEntries(); Mutex mutex = null; try { mutex = targetService.AcquireUpdateLock(); List <ScheduleEntry> storeEntries = GetScheduleEntriesForService(new ScheduleEntries(self.ObjectStore), targetService); storeEntries.Sort(CompareScheduleEntryStartTimes); Util.Trace(TraceLevel.Verbose, "store: {0} mxf: {1}", ListScheduleEntrys(storeEntries), ListScheduleEntrys(scheduleEntriesToMerge)); #region pad store entry list with bogus begin/end time entries // Create bogus store entries at the beginning and end of time to make the loop below simpler. ScheduleEntry endOfTimeEntry = new ScheduleEntry(); endOfTimeEntry.StartTime = DateTime.MaxValue; endOfTimeEntry.EndTime = DateTime.MaxValue; storeEntries.Add(endOfTimeEntry); ScheduleEntry beginningOfTimeEntry = new ScheduleEntry(); beginningOfTimeEntry.StartTime = DateTime.MinValue; beginningOfTimeEntry.StartTime = DateTime.MinValue; storeEntries.Insert(0, beginningOfTimeEntry); #endregion List <ScheduleEntry> adds = new List <ScheduleEntry>(); List <ScheduleEntry> updates = new List <ScheduleEntry>(); List <ScheduleEntry> deletes = new List <ScheduleEntry>(); int mxfIndex = 0; int storeIndex = 1; DateTime lastMXFEndTime = new DateTime(0); while (mxfIndex < scheduleEntriesToMerge.Count()) { ScheduleEntry mxfEntry = scheduleEntriesToMerge[mxfIndex]; ScheduleEntry storeEntry = storeEntries[storeIndex]; if (lastMXFEndTime > storeEntry.StartTime) { ScheduleEntry lastMxfEntry = scheduleEntriesToMerge[mxfIndex - 1]; if (lastMXFEndTime > storeEntry.EndTime) { Util.Trace(TraceLevel.Verbose, "Store entry is contained within timeslot of previous MXF entry, removing it. store: {0} mxf: {1}", storeEntry, mxfEntry); if (!Program.options.safeMode) { deletes.Add(storeEntry); } ++storeIndex; continue; } Util.Trace(TraceLevel.Verbose, "Store entry overlaps with previous MXF entry. Truncating start. store: {0} mxf: {1}", storeEntry, lastMxfEntry); if (!Program.options.safeMode) { storeEntry.StartTime = lastMxfEntry.EndTime; updates.Add(storeEntry); ++storeIndex; continue; } } if (TimeIsAboutAtOrBefore(storeEntry.EndTime, mxfEntry.StartTime)) { Util.Trace(TraceLevel.Verbose, "Ignoring store ScheduleEntry {0} as it does not overlap the current MXF entry : {1}", storeEntry, mxfEntry); ++storeIndex; continue; } if (TimeslotsMatch(mxfEntry, storeEntry)) { lastMXFEndTime = storeEntry.EndTime; if (mxfEntry.Program.Id != storeEntry.Program.Id) { SeriesInfo mxfSeries = mxfEntry.Program.Series; SeriesInfo storeSeries = storeEntry.Program.Series; if (mxfSeries != null && storeSeries != null && mxfSeries.Id == storeSeries.Id && mxfEntry.Program.IsGeneric && !storeEntry.Program.IsGeneric) { Util.Trace(TraceLevel.Info, "Skipping update because the MXF has a generic entry while DB already has a specific episode: store: {0} mxf: {1}", storeEntry, mxfEntry); } else { Util.Trace(TraceLevel.Warning, "Programs do not match after normal ScheduleEntriesToMerge, queueing update. Store: {0} MXF: {1}", storeEntry, mxfEntry); if (!Program.options.safeMode) { storeEntry.Program = mxfEntry.Program; MergeProgramsInjector.UpdateScheduleEntryFlags(mxfEntry, storeEntry); updates.Add(storeEntry); } } } else if (!MergeProgramsInjector.ScheduleEntryFlagsMatch(storeEntry, mxfEntry)) { Util.Trace(TraceLevel.Warning, "Mismatched scheduleEntry flags found, queueing update. store: {0} MXF: {1}", storeEntry, mxfEntry); if (!Program.options.safeMode) { MergeProgramsInjector.UpdateScheduleEntryFlags(mxfEntry, storeEntry); // MS MergeScheduleEntries treats this as an add/remove rather than an update. I don't like this, hopefully // this way can work. updates.Add(storeEntry); } } else { Util.Trace(TraceLevel.Verbose, "Entry for store and MXF already match: {0}", storeEntry); } ++mxfIndex; ++storeIndex; continue; } ScheduleEntry lastStoreEntry = storeEntries[storeIndex - 1]; // If we get here, store entry ends after mxf entry starts. Find out if the program ID matches; it may be only a timeslot change. if (storeEntry.Program.Id == mxfEntry.Program.Id) { Util.Trace(TraceLevel.Warning, "DB entry overlapping the MXF ScheduleEntry has the same program. Updating the timeslot and possibly flags. store: {0} MXF: {1}", storeEntry, mxfEntry); if (!Program.options.safeMode) { if (TimeApproxEquals(mxfEntry.StartTime, lastStoreEntry.EndTime)) { storeEntry.StartTime = lastStoreEntry.EndTime; } else { storeEntry.StartTime = mxfEntry.StartTime; } ScheduleEntry nextStoreEntry = storeEntries[storeIndex + 1]; if (TimeApproxEquals(mxfEntry.EndTime, nextStoreEntry.StartTime)) { storeEntry.EndTime = nextStoreEntry.StartTime; } else { storeEntry.EndTime = mxfEntry.EndTime; } MergeProgramsInjector.UpdateScheduleEntryFlags(mxfEntry, storeEntry); updates.Add(storeEntry); } lastMXFEndTime = storeEntry.EndTime; ++mxfIndex; ++storeIndex; continue; } if (storeEntry.StartTime < mxfEntry.StartTime && TimeIsAboutAtOrBefore(storeEntry.EndTime, mxfEntry.EndTime)) { Util.Trace(TraceLevel.Warning, "DB entry overlapping MXF ScheduleEntry is earlier. Truncating the end of it. store: {0} mxf: {1}", storeEntry, mxfEntry); if (!Program.options.safeMode) { storeEntry.EndTime = mxfEntry.StartTime; updates.Add(storeEntry); } ++storeIndex; continue; } if (TimeIsAboutAtOrBefore(mxfEntry.StartTime, storeEntry.StartTime) && TimeIsAboutAtOrBefore(storeEntry.EndTime, mxfEntry.EndTime)) { Util.Trace(TraceLevel.Warning, "DB entry timeslot is within MXF ScheduleEntry timeslot. Deleting it. store: {0} mxf: {1}", storeEntry, mxfEntry); if (!Program.options.safeMode) { deletes.Add(storeEntry); } ++storeIndex; continue; } if (TimeIsAboutAtOrBefore(mxfEntry.EndTime, storeEntry.StartTime)) { Util.Trace(TraceLevel.Warning, "Next db entry is entirely after the MXF entry. Adding the MXF entry. store: {0} mxf: {1}", storeEntry, mxfEntry); if (!Program.options.safeMode) { // check for rounding error. if (mxfEntry.EndTime > storeEntry.StartTime) { mxfEntry.EndTime = storeEntry.StartTime; } adds.Add(mxfEntry); } lastMXFEndTime = mxfEntry.EndTime; ++mxfIndex; continue; } // If we ge there, store entry starts within MXF entry and ends later. Util.Trace(TraceLevel.Warning, "Overlapping store entry is at end of MXF ScheduleEntry. Truncating the start. store: {0} mxf: {1}", storeEntry, mxfEntry); if (!Program.options.safeMode) { storeEntry.StartTime = mxfEntry.EndTime; updates.Add(storeEntry); } ++storeIndex; } if (!Program.options.safeMode && updates.Count + adds.Count + deletes.Count > 0) { List <ScheduleEntry> emptyList = new List <ScheduleEntry>(); ApplyMergedScheduleEntriesToStore(targetService, emptyList, emptyList, deletes); ApplyMergedScheduleEntriesToStore(targetService, updates, emptyList, emptyList); ApplyMergedScheduleEntriesToStore(targetService, emptyList, adds, emptyList); } } finally { targetService.ReleaseUpdateLock(mutex); } }