private void UpdateAnimeGroupsAndTheirContracts(ISessionWrapper session, IReadOnlyCollection <SVR_AnimeGroup> groups) { ServerState.Instance.DatabaseBlocked = new ServerState.DatabaseBlockedInfo { Blocked = true, Status = "Updating statistics and contracts for AnimeGroups" }; _log.Info("Updating statistics and contracts for AnimeGroups"); var allCreatedGroupUsers = new ConcurrentBag <List <SVR_AnimeGroup_User> >(); // Update batches of AnimeGroup contracts in parallel. Each parallel branch requires it's own session since NHibernate sessions aren't thread safe. // The reason we're doing this in parallel is because updating contacts does a reasonable amount of work (including LZ4 compression) Parallel.ForEach(groups.Batch(DefaultBatchSize), new ParallelOptions { MaxDegreeOfParallelism = 4 }, localInit: () => DatabaseFactory.SessionFactory.OpenStatelessSession(), body: (groupBatch, state, localSession) => { var createdGroupUsers = new List <SVR_AnimeGroup_User>(groupBatch.Length); // We shouldn't need to keep track of updates to AnimeGroup_Users in the below call, because they should have all been deleted, // therefore they should all be new SVR_AnimeGroup.BatchUpdateStats(groupBatch, watchedStats: true, missingEpsStats: true, createdGroupUsers: createdGroupUsers); allCreatedGroupUsers.Add(createdGroupUsers); SVR_AnimeGroup.BatchUpdateContracts(localSession.Wrap(), groupBatch, updateStats: true); return(localSession); }, localFinally: localSession => { localSession.Dispose(); }); _animeGroupRepo.UpdateBatch(session, groups); _log.Info("AnimeGroup statistics and contracts have been updated"); ServerState.Instance.DatabaseBlocked = new ServerState.DatabaseBlockedInfo { Blocked = true, Status = "Creating AnimeGroup_Users and updating plex/kodi contracts" }; _log.Info("Creating AnimeGroup_Users and updating plex/kodi contracts"); List <SVR_AnimeGroup_User> animeGroupUsers = allCreatedGroupUsers.SelectMany(groupUsers => groupUsers) .ToList(); // Insert the AnimeGroup_Users so that they get assigned a primary key before we update plex/kodi contracts _animeGroupUserRepo.InsertBatch(session, animeGroupUsers); // We need to repopulate caches for AnimeGroup_User and AnimeGroup because we've updated/inserted them // and they need to be up to date for the plex/kodi contract updating to work correctly _animeGroupUserRepo.Populate(session, displayname: false); _animeGroupRepo.Populate(session, displayname: false); // NOTE: There are situations in which UpdatePlexKodiContracts will cause database database writes to occur, so we can't // use Parallel.ForEach for the time being (If it was guaranteed to only read then we'd be ok) foreach (SVR_AnimeGroup_User groupUser in animeGroupUsers) { groupUser.UpdatePlexKodiContracts(session); } _animeGroupUserRepo.UpdateBatch(session, animeGroupUsers); _log.Info("AnimeGroup_Users have been created"); }
private void UpdateAnimeGroupsAndTheirContracts(IEnumerable <SVR_AnimeGroup> groups) { _log.Info("Updating statistics and contracts for AnimeGroups"); var allCreatedGroupUsers = new ConcurrentBag <List <SVR_AnimeGroup_User> >(); // Update batches of AnimeGroup contracts in parallel. Each parallel branch requires it's own session since NHibernate sessions aren't thread safe. // The reason we're doing this in parallel is because updating contacts does a reasonable amount of work (including LZ4 compression) Parallel.ForEach(groups.Batch(DefaultBatchSize), new ParallelOptions { MaxDegreeOfParallelism = 4 }, body: (groupBatch, state, localSession) => { var createdGroupUsers = new List <SVR_AnimeGroup_User>(groupBatch.Length); // We shouldn't need to keep track of updates to AnimeGroup_Users in the below call, because they should have all been deleted, // therefore they should all be new SVR_AnimeGroup.BatchUpdateStats(groupBatch, watchedStats: true, missingEpsStats: true, createdGroupUsers: createdGroupUsers); allCreatedGroupUsers.Add(createdGroupUsers); SVR_AnimeGroup.BatchUpdateContracts(groupBatch, updateStats: true); }); _log.Info("AnimeGroup statistics and contracts have been updated"); _log.Info("Creating AnimeGroup_Users and updating plex/kodi contracts"); // Insert the AnimeGroup_Users so that they get assigned a primary key before we update plex/kodi contracts // We need to repopulate caches for AnimeGroup_User and AnimeGroup because we've updated/inserted them // and they need to be up to date for the plex/kodi contract updating to work correctly // NOTE: There are situations in which UpdatePlexKodiContracts will cause database database writes to occur, so we can't // use Parallel.ForEach for the time being (If it was guaranteed to only read then we'd be ok) List <int> ids = allCreatedGroupUsers.SelectMany(a => a).Select(a => a.AnimeGroup_UserID).ToList(); using (var upd = Repo.Instance.AnimeGroup_User.BeginBatchUpdate(() => Repo.Instance.AnimeGroup_User.GetMany(ids))) { foreach (SVR_AnimeGroup_User guser in upd) { guser.UpdatePlexKodiContracts_RA(); upd.Update(guser); } upd.Commit(); } _log.Info("AnimeGroup_Users have been created"); }