public static bool LoadFullyIfNeeded(BubbleGroup group, bool sync = false) { if (@group == null) { return(false); } var loadedSomething = false; lock (BubbleGroupDatabase.OperationLock) { var unifiedGroup = @group as UnifiedBubbleGroup; var adjustUnifiedGroupUnreadIndicatorIfExists = false; var associatedGroups = unifiedGroup != null ? unifiedGroup.Groups.ToList() : new[] { @group }.ToList(); var associatedPartiallyLoadedGroups = associatedGroups.Where(x => x.PartiallyLoaded).ToList(); foreach (var partiallyLoadedGroup in associatedPartiallyLoadedGroups) { var partiallyLoadedBubblesToRemove = partiallyLoadedGroup.Bubbles.ToList(); var rollingBack = false; TryAgain: try { loadedSomething = true; partiallyLoadedGroup.PartiallyLoaded = false; foreach (var bubble in BubbleGroupDatabase.FetchBubbles(partiallyLoadedGroup).Reverse()) { partiallyLoadedGroup.Bubbles.Add(bubble); } foreach (var partiallyLoadedBubbleToRemove in partiallyLoadedBubblesToRemove) { partiallyLoadedGroup.Bubbles.Remove(partiallyLoadedBubbleToRemove); } if (partiallyLoadedGroup.Bubbles.Count < 1) { foreach (var partiallyLoadedBubbleToRemove in partiallyLoadedBubblesToRemove) { partiallyLoadedGroup.Bubbles.Add(partiallyLoadedBubbleToRemove); } } } catch (Exception ex) { Utils.DebugPrint("Failed to fully load partially loaded group " + partiallyLoadedGroup.ID + ": " + ex); if (!rollingBack) { Utils.DebugPrint("Attempting to roll back the last transaction...."); BubbleGroupSettingsManager.SetUnreadIndicatorGuid(partiallyLoadedGroup, null, false); adjustUnifiedGroupUnreadIndicatorIfExists = true; rollingBack = true; var lastModifiedIndex = BubbleGroupIndex.GetLastModifiedIndex(partiallyLoadedGroup.ID); if (lastModifiedIndex.HasValue) { try { BubbleGroupDatabase.RollBackTo(partiallyLoadedGroup, lastModifiedIndex.Value); goto TryAgain; } catch (Exception ex2) { Utils.DebugPrint("Failed to rollback: " + ex2); // fall-through. It's unrecoverable! } } else { // fall-through. It's unrecoverable! } } Utils.DebugPrint("Partially loaded group is dead. Killing and restarting (lost data occurred)."); BubbleGroupDatabase.Kill(partiallyLoadedGroup); BubbleGroupSync.RemoveFromSync(partiallyLoadedGroup); BubbleGroupDatabase.AddBubbles(partiallyLoadedGroup, partiallyLoadedBubblesToRemove.ToArray()); } } if (unifiedGroup != null && !unifiedGroup.UnifiedGroupLoaded) { Populate(unifiedGroup); } if (unifiedGroup != null && adjustUnifiedGroupUnreadIndicatorIfExists) { BubbleGroupSettingsManager.SetUnreadIndicatorGuid(unifiedGroup, null, false); } } if (!sync && loadedSomething) { Task.Factory.StartNew(() => { var unifiedGroup = @group as UnifiedBubbleGroup; if (unifiedGroup != null) { BubbleQueueManager.Send(unifiedGroup.Groups.Where(x => ServiceManager.IsRunning(x.Service)) .Select(x => x.Service.Information.ServiceName).ToArray()); } else if (ServiceManager.IsRunning(@group.Service)) { BubbleQueueManager.Send(new[] { @group.Service.Information.ServiceName }); } BubbleQueueManager.SetNotQueuedToFailures(@group); }); } return(loadedSomething); }