/// <summary> /// Clear global merge candidates /// </summary> public override void ClearGlobalMergeCanadidates() { try { this.m_pepService.Demand(MdmPermissionPolicyIdentifiers.UnrestrictedMdm); this.m_tracer.TraceInfo("Clearing MDM merge candidates..."); // TODO: When the persistence refactor is done - change this to use the bulk method var classKeys = typeof(TEntity).GetCustomAttributes <ClassConceptKeyAttribute>(false).Select(o => Guid.Parse(o.ClassConcept)); Expression <Func <EntityRelationship, bool> > purgeExpression = o => classKeys.Contains(o.SourceEntity.ClassConceptKey.Value) && o.RelationshipTypeKey == MdmConstants.CandidateLocalRelationship && o.ClassificationKey == MdmConstants.AutomagicClassification && o.ObsoleteVersionSequenceId == null; int offset = 0, totalResults = 1, batchSize = 500; var uuid = Guid.NewGuid(); // Delete thread using (var fetchEvent = new ManualResetEventSlim(false)) { ConcurrentQueue <EntityRelationship> fetchQueue = new ConcurrentQueue <EntityRelationship>(); bool completeProcessing = false; this.m_threadPool.QueueUserWorkItem(_ => { int idx = 0, complete = 0; var processList = new EntityRelationship[25]; while (!completeProcessing && !this.m_disposed) { fetchEvent.Wait(1000); while (fetchQueue.TryDequeue(out var erd)) { processList[idx++] = erd; if (idx == processList.Length) { try { this.ProgressChanged?.Invoke(this, new ProgressChangedEventArgs((float)complete / (float)totalResults, $"Clearing Candidates ({complete} of {totalResults})")); var batch = new Bundle(processList.Select(o => { o.BatchOperation = BatchOperationType.Delete; return(o); })); this.m_batchPersistence.Update(batch, TransactionMode.Commit, AuthenticationContext.SystemPrincipal); complete += processList.Length; } catch (Exception e) { this.m_tracer.TraceWarning("Error updating candidate clear - {0}", e.Message); } idx = 0; } } fetchEvent.Reset(); } }); while (offset < totalResults) { foreach (var er in this.m_relationshipPersistence.QueryFast(purgeExpression, uuid, offset, batchSize, out totalResults, AuthenticationContext.SystemPrincipal)) { fetchQueue.Enqueue(er); } fetchEvent.Set(); offset += batchSize; } completeProcessing = true; // requeest termination while (!fetchQueue.IsEmpty) { Thread.Sleep(1000); } // Now purge them if (this.m_relationshipPersistence is IBulkDataPersistenceService ibps) { purgeExpression = o => (o.RelationshipTypeKey == MdmConstants.CandidateLocalRelationship || o.RelationshipTypeKey == MdmConstants.IgnoreCandidateRelationship || o.RelationshipTypeKey == MdmConstants.MasterRecordRelationship) && o.ObsoleteVersionSequenceId != null; ibps.Purge(TransactionMode.Commit, AuthenticationContext.SystemPrincipal, purgeExpression); } } } catch (Exception e) { this.m_tracer.TraceError("Error clearing MDM merge candidates: {0}", e); throw new MdmException("Error clearing MDM merge candidates", e); } }