Exemple #1
0
        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()));
        }
Exemple #2
0
        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();
        }
Exemple #4
0
        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);
            //}
        }
Exemple #5
0
 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);
 }
Exemple #6
0
        /// <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);
                }
            }
        }
Exemple #7
0
 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);
     }));
 }
Exemple #8
0
 public void SaveChangesOutsideTransaction(object entity, ITimingBucket timings = null)
 {
     this.SaveChangesInternal(entity, true, timings);
 }
Exemple #9
0
 /// <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);
 }
Exemple #10
0
 /// <summary>
 /// Processes the work unit.
 /// </summary>
 /// <param name="context"></param>
 void IWorkUnit.Process(WorkUnitProcessingContext context, ITimingBucket timings)
 {
     this.Process(context, timings);
 }
Exemple #11
0
        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));
            }
        }
Exemple #12
0
        /// <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];
                }
            }
        }
Exemple #13
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);
                    }
                }
            }
        }