public static Task ProcessItemsInParallel <T>(this IEnumerable <T> items, Action <T> doWork, Action <T> ok = null, Action <T, Exception> failure = null, Action <T> finished = null, ITimingBucket timings = null) { var tasks = new List <Task>(); items.ProcessItemsInternal <T>((item) => { var task = Task.Run <Exception>(() => { try { doWork(item); return(null); } catch (Exception ex) { return(ex); } }); tasks.Add(task); return(task); }, ok, failure, finished, timings); // wait... var log = LogSet.GetLog(typeof(CollectionsExtender)); if (log.IsInfoEnabled) { log.InfoFormat("{0}: waiting for threads...", typeof(T).Name); } return(Task.WhenAll(tasks.ToArray())); }
protected virtual void Process(WorkUnitProcessingContext context, ITimingBucket timings) { if (context == null) { throw new ArgumentNullException("context"); } // walk... SqlStatement[] statements = this.GetStatements(context); foreach (SqlStatement statement in statements) { // mbr - 2016-08-08 - put a longer timeout on schema statements... statement.TimeoutSeconds = 5 * 60; try { context.Connection.ExecuteNonQuery(statement); } catch (Exception ex) { const string message = "The work unit failed."; if (this.ContinueOnError) { this.LogError(() => message, ex); } else { throw new InvalidOperationException(message, ex); } } } }
/// <summary> /// Constructor. /// </summary> // mbr - 26-11-2007 - don't take a connection at this point... // internal WorkUnitProcessingContext(IConnection connection) internal WorkUnitProcessingContext(ITimingBucket timings) { // if(connection == null) // throw new ArgumentNullException("connection"); // _connection = connection; this.ResetBag(); }
private void SaveChangesInternal(object entity, bool outsideTransaction, ITimingBucket timings) { if (entity == null) { throw new ArgumentNullException("entity"); } if (timings == null) { timings = NullTimingBucket.Instance; } // check... if (EntityType == null) { throw new ArgumentNullException("EntityType"); } this.EntityType.AssertIsOfType(entity); // gets the work units... WorkUnitCollection units = null; using (timings.GetTimer("GetWorkUnits")) { units = this.GetWorkUnits(entity); if (units == null) { throw new ArgumentNullException("units"); } if (units.Count == 0) { return; } } // execute... WorkUnitProcessor processor = new WorkUnitProcessor(); using (var child = timings.GetChildBucket("Process")) processor.Process(units); //// mbr - 26-01-2006 - invoke the change register... //using (timings.GetTimer("Signal")) //{ // foreach (WorkUnit unit in units) // ChangeRegister.Current.ChangesCommitted(this.EntityType, entity, unit); //} }
public static void ProcessItems <T>(this IEnumerable <T> items, Action <T> doWork, Action <T> ok = null, Action <T, Exception> failure = null, Action <T> finished = null, ITimingBucket timings = null) { items.ProcessItemsInternal <T>((item) => { try { doWork(item); return(Task.FromResult <Exception>(null)); } catch (Exception ex) { return(Task.FromResult <Exception>(ex)); } }, ok, failure, finished, timings); }
/// <summary> /// Processes the work unit. /// </summary> /// <param name="context"></param> public virtual void Process(WorkUnitProcessingContext context, ITimingBucket timings) { if (context == null) { throw new ArgumentNullException("context"); } // walk... SqlStatement[] statements = null; using (timings.GetTimer("GetStatements")) statements = this.GetStatements(context); using (timings.GetTimer("Execute")) { foreach (SqlStatement statement in statements) { context.Connection.ExecuteNonQuery(statement); } } }
public static Task ProcessItemsAsync <T>(this IEnumerable <T> items, Func <T, Task> doWork, Action <T> ok = null, Action <T, Exception> failure = null, Action <T> finished = null, ITimingBucket timings = null) { return(Task.Run(() => { items.ProcessItemsInternal <T>((item) => { return Task.Run <Exception>(async() => { try { await doWork(item); return null; } catch (Exception ex) { return ex; } }); }, ok, failure, finished, timings); })); }
public void SaveChangesOutsideTransaction(object entity, ITimingBucket timings = null) { this.SaveChangesInternal(entity, true, timings); }
/// <summary> /// Saves changes to the given entity. /// </summary> /// <param name="entity"></param> public void SaveChanges(object entity, ITimingBucket timings = null) { this.SaveChangesInternal(entity, false, timings); }
/// <summary> /// Processes the work unit. /// </summary> /// <param name="context"></param> void IWorkUnit.Process(WorkUnitProcessingContext context, ITimingBucket timings) { this.Process(context, timings); }
internal static void ProcessItemsInternal <T>(this IEnumerable <T> items, Func <T, Task <Exception> > doWork, Action <T> ok, Action <T, Exception> failure, Action <T> finished, ITimingBucket bucket) { if (doWork == null) { throw new ArgumentNullException("doWork"); } var log = LogSet.GetLog(typeof(CollectionsExtender)); if (bucket == null) { bucket = NullTimingBucket.Instance; } var name = typeof(T).Name; var result = new ProcessItemsResult <T>(DateTime.UtcNow); if (items.Any()) { log.LogTrace(() => string.Format("{0}: processing '{1}' items(s)...", name, items.Count())); var tasks = new List <Task>(); foreach (var item in items) { try { var timer = new AccurateTimer(); timer.Start(); var error = doWork(item); timer.Stop(); if (error == null) { throw new InvalidOperationException("Work delegate returned null."); } // error? error.Wait(); if (error.Result != null) { throw new InvalidOperationException("Item processing failed.", error.Result); } // set... result.Timings[item] = timer.DurationAsDecimal; if (ok != null) { ok(item); } } catch (Exception ex) { if (log.IsErrorEnabled) { if (typeof(T).IsAssignableFrom(typeof(IEntityId))) { log.Error(string.Format("Failed to process item of type '{0}' with ID #{1}.", name, ((IEntityId)item).Id), ex); } else { log.Error(string.Format("Failed to process item of type '{0}'.", name), ex); } } if (failure != null) { failure(item, ex); } } finally { if (finished != null) { finished(item); } } } log.LogTrace(() => string.Format("{0}: finished.", name)); } else { log.LogTrace(() => string.Format("{0}: nothing to do.", name)); } }
/// <summary> /// Processes the work unit. /// </summary> /// <param name="context"></param> public override void Process(WorkUnitProcessingContext context, ITimingBucket timings) { if (context == null) { throw new ArgumentNullException("context"); } // check... if (EntityType == null) { throw new ArgumentNullException("EntityType"); } if (context.Connection == null) { throw new InvalidOperationException("context.Connection is null."); } // insert... SqlStatement[] statements = null; using (timings.GetTimer("GetStatements")) { statements = this.GetStatements(context); if (statements == null) { throw new InvalidOperationException("'statements' is null."); } if (statements.Length == 0) { throw new InvalidOperationException("'statements' is zero-length."); } } // get... SqlStatement statement = statements[0]; if (statement == null) { throw new InvalidOperationException("statement is null."); } // run it... object[] result = null; // mbr - 27-10-2005 - if we're sproc mode, get the result differently... if (context.Connection.SqlMode == SqlMode.AdHoc) { if (context.Connection.SupportsMultiStatementQueries) { // debug? using (timings.GetTimer("SingletonExecute")) result = this.Execute(context, statement); } else { using (timings.GetTimer("MultipleExecutes")) { // run... context.Connection.ExecuteNonQuery(statement); // id... if (context.Dialect.LastInsertedIdMode == LastInsertedIdMode.Scalar) { statement = this.CreateSelectIdStatement(context); if (statement == null) { throw new InvalidOperationException("statement is null."); } // run... result = new object[] { context.Connection.ExecuteScalar(statement) }; } else if (context.Dialect.LastInsertedIdMode == LastInsertedIdMode.Parameter) { EntityField[] autos = this.GetAutoIncrementFields(); if (autos == null) { throw new InvalidOperationException("'autos' is null."); } if (autos.Length == 0) { throw new InvalidOperationException("'autos' is zero-length."); } SqlStatementParameter parameter = statement.Parameters[context.Dialect.LastInsertedIdVariableName]; if (parameter == null) { throw new InvalidOperationException("parameter is null."); } // run... result = new object[] { parameter.Value }; } else { throw new NotSupportedException(string.Format("Cannot handle {0}.", context.Dialect.LastInsertedIdMode)); } } } } // mbr - 10-10-2007 - removed. // else if(context.Connection.SqlMode == SqlMode.Sprocs) // { // // run it... // context.Connection.ExecuteNonQuery(statement); // // // get the return parameter... // EntityField[] autoFields = this.EntityType.GetAutoIncrementFields(); // if(autoFields == null) // throw new InvalidOperationException("autoFields is null."); // if(autoFields.Length == 1) // { // // find it... // SqlStatementParameter parameter = statement.Parameters[autoFields[0].NativeName.Name]; // if(parameter == null) // throw new InvalidOperationException("parameter is null."); // // // return... // result = new object[] { parameter.Value }; // } // else if(autoFields.Length > 1) // throw new NotSupportedException(string.Format("Tables with '{0}' auto-increment fields are not supported.", autoFields.Length)); // } else { throw new NotSupportedException(string.Format("Cannot handle '{0}'.", context.Connection.SqlMode)); } // set... using (timings.GetTimer("Passback")) { if (result != null) { context.Bag.LastCreatedId = result[0]; } } }
/// <summary> /// Processes the given work units. /// </summary> /// <param name="units"></param> public void Process(WorkUnitCollection units, bool trace = false, IOperationItem operation = null, bool outsideTransaction = false, ITimingBucket timings = null) { if (units == null) { throw new ArgumentNullException("units"); } if (units.Count == 0) { return; } // operation... if (timings == null) { timings = NullTimingBucket.Instance; } if (operation == null) { operation = NullOperationItem.Instance; } // mbr - 02-10-2007 - case 827 - notify outside... // mbr - 2014-11-30 - changed this to load up the statements... var touchedEts = new List <EntityType>(); var anyNeedsTransaction = units.Count > 1; var context = new WorkUnitProcessingContext(timings); using (timings.GetTimer("Count")) { foreach (IWorkUnit unit in units) { ISaveChangesNotification notification = unit.Entity as ISaveChangesNotification; if (notification != null) { notification.BeforeSaveChangesOutTransaction(unit); } // add... if (!(touchedEts.Contains(unit.EntityType))) { touchedEts.Add(unit.EntityType); } // add... if (unit.NeedsTransaction && !(anyNeedsTransaction)) { anyNeedsTransaction = true; } } } // mbr - 26-11-2007 - get a manager for this thread... IWorkUnitTransactionManager manager = null; using (timings.GetTimer("Initialize manager")) { if (outsideTransaction) { manager = new OutsideTransactionWorkUnitProcessorTransactionManager(); } else { //manager = WorkUnitProcessorTransactionManager.Current; // mbr - 2014-11-30 - we only want to use transactions if we are in a tranaction. the old // approach created a transaction just for single row inserts, which turned out created // quite a slowdown... if (anyNeedsTransaction) { manager = WorkUnitProcessorTransactionManager.Current; } else { manager = WorkUnitProcessorNullTransactionManager.Current; } } if (manager == null) { throw new InvalidOperationException("manager is null."); } // initialise the manager... manager.Initialize(); } try { // mbr - 26-11-2007 - now done in the manager... // if(connection == null) // connection = Database.CreateConnection(units[0].EntityType.DatabaseName); // mbr - 26-11-2007 - don't do transactions here (the manager will do it)... // connection.BeginTransaction(); try { // reset the bag... using (timings.GetTimer("Reset")) context.ResetBag(); // run... operation.ProgressMaximum = units.Count; operation.ProgressValue = 0; // mbr - 06-09-2007 - for c7 - the "before" event can replace the work unit. (done by changing the entity and regenerating.) //foreach(IWorkUnit unit in units) for (int index = 0; index < units.Count; index++) { using (var child = timings.GetChildBucket("Execute")) { // get a connection to use here... IConnection connection = null; using (child.GetTimer("Connect")) { connection = manager.GetConnection(units[index]); if (connection == null) { throw new InvalidOperationException("connection is null."); } // set... context.SetConnection(connection); } // get the unit... IWorkUnit unit = units[index]; try { if (trace) { this.LogInfo(() => string.Format("Running unit '{0}'...", unit)); } ISaveChangesNotification notification = unit.Entity as ISaveChangesNotification; using (child.GetTimer("NotifyPre")) { // before... if (notification != null) { // mbr - 02-10-2007 - case 827 - changed interface. // IWorkUnit newUnit = notification.BeforeSaveChanges(unit); IWorkUnit newUnit = notification.BeforeSaveChangesInTransaction(unit, connection); // patch it.. if (newUnit != unit) { units[index] = newUnit; unit = newUnit; } } } // run it... using (var childChild = child.GetChildBucket("Process")) unit.Process(context, childChild); // set... using (child.GetTimer("Results")) unit.SetResultsBag(context.Bag); // mbr - 10-10-2007 - for c7 - do reconciliation here... using (child.GetTimer("Reconcile")) { WorkUnitCollection forReconciliation = new WorkUnitCollection(); forReconciliation.Add(unit); unit.EntityType.Persistence.ReconcileWorkUnitProcessorResults(forReconciliation); } // mbr - 02-10-2007 - case 827 - call... using (child.GetTimer("NotifyPost")) { if (notification != null) { notification.AfterSaveChangesInTransaction(unit, connection); } } } catch (Exception ex) { throw new InvalidOperationException(string.Format(Cultures.Exceptions, "Failed when processing '{0}'.", unit), ex); } // next... operation.IncrementProgress(); } } // mbr - 26-11-2007 - it's the manager that needs to commit... // connection.Commit(); using (timings.GetTimer("Commit")) manager.Commit(); } catch (Exception ex) { // rollback... try { // mbr - 26-11-2007 - it's the manager that needs to rollback... // connection.Rollback(); manager.Rollback(ex); } catch (Exception rollbackEx) { // mbr - 26-11-2007 - added. if (this.Log.IsWarnEnabled) { this.Log.Warn("A further exception occurred whilst rolling back the transaction.", rollbackEx); } } // throw... throw new InvalidOperationException("Failed to process work units.", ex); } } finally { // mbr - 26-11-2007 - get the manager to tear down... // if(connection != null) // connection.Dispose(); using (timings.GetTimer("Dispose")) manager.Dispose(); // mbr - 2010-04-19 - invalidate the caches... //EntityCache.Invalidate(touchedEts); // flag... foreach (IWorkUnit unit in units) { ISaveChangesNotification notification = unit.Entity as ISaveChangesNotification; if (notification != null) { notification.AfterSaveChangesOutTransaction(unit); } } } }