예제 #1
0
        public static void Create(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");
            if (Exists(database, name))
                throw new ArgumentException(string.Format("Workflow with the name \"{0}\" already exists.", name), "name");

            var workflow = new Workflow(name);
            database.WorkflowsLock.EnterWriteLock();
            try
            {
                workflow.WorkflowLock.EnterWriteLock();
                try
                {
                    database.WorkflowNames.Add(workflow.Name, workflow.Id);
                    database.Workflows.Add(workflow.Id, workflow);
                }
                finally
                {
                    workflow.WorkflowLock.ExitWriteLock();
                }
            }
            finally
            {
                database.WorkflowsLock.ExitWriteLock();
            }
        }
예제 #2
0
        public static bool Exists(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");

            database.WorkflowsLock.EnterReadLock();
            try
            {
                return database.WorkflowNames.ContainsKey(name);
            }
            finally
            {
                database.WorkflowsLock.ExitReadLock();
            }
        }
예제 #3
0
        public static bool IsEmpty(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");

            database.QueuesLock.EnterReadLock();
            try
            {
                if (!database.QueueNames.ContainsKey(name))
                    throw new ArgumentException(string.Format("Queue with the name \"{0}\" not found.", name), "name");

                var queue = database.Queues[database.QueueNames[name]];
                queue.QueueLock.EnterReadLock();
                try
                {
                    return !queue.QueuedTasks.Any();
                }
                finally
                {
                    queue.QueueLock.ExitReadLock();
                }
            }
            finally
            {
                database.QueuesLock.ExitReadLock();
            }
        }
예제 #4
0
        public static QueueTask Dequeue(Database database, string queueName)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (queueName == null)
                throw new ArgumentNullException("queueName", "queueName is null.");

            if (Queue.IsEmpty(database, queueName))
                return null;

            Workflow workflow;
            Task task;
            Queue queue;
            Guid workflowId, taskId;

            for (int attemptNum = 0; attemptNum < MAX_DEQUEUE_ATTEMPTS; attemptNum++)
            {
                queue = Queue.Get(database, queueName);
                queue.QueueLock.EnterReadLock();
                try
                {
                    if (queue.QueuedTasks.Count == 0)
                        return null;
                    var first = queue.QueuedTasks.First.Value;
                    workflowId = first.Item1;
                    taskId = first.Item2;
                }
                finally
                {
                    queue.QueueLock.ExitReadLock();
                }

                workflow = Workflow.Get(database, workflowId);
                if (workflow == null)
                    continue;
                workflow.WorkflowLock.EnterReadLock();
                try
                {
                    task = workflow.Tasks[taskId];
                }
                finally
                {
                    workflow.WorkflowLock.ExitReadLock();
                }

                workflow.WorkflowLock.EnterWriteLock();
                try
                {
                    queue.QueueLock.EnterWriteLock();
                    try
                    {
                        // Validate state;
                        if (queue.QueuedTasks.Count == 0)
                            return null;
                        if (queue.QueuedTasks.First().Item2 != taskId)
                            continue;
                        queue.QueuedTasks.RemoveFirst();
                        queue.RunningTasks.Add(taskId);
                        task.State = TaskState.Running;
                        return new QueueTask()
                        {
                            WorkflowName = workflow.Name,
                            TaskName = task.Name,
                        };
                    }
                    finally
                    {
                        queue.QueueLock.ExitWriteLock();
                    }
                }
                finally
                {
                    workflow.WorkflowLock.ExitWriteLock();
                }
            }
            return null;
        }
예제 #5
0
        public static void Delete(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");
            if (!Queue.Exists(database, name))
                throw new ArgumentException(string.Format("Queue with the name \"{0}\" not found.", name), "name");
            if (!Queue.IsEmpty(database, name))
                throw new InvalidOperationException(string.Format("Failed deleting queue with name \"{0}\", queue is not empty.", name));

            var queue = Queue.Get(database, name);

            queue.QueueLock.EnterWriteLock();
            try
            {
                if (queue.QueuedTasks.Any())
                    throw new InvalidOperationException(string.Format("Failed deleting queue with name \"{0}\", queue is not empty.", name));

                database.QueuesLock.EnterWriteLock();
                try
                {
                    queue.QueuedTasks = null;
                    database.Queues.Remove(queue.Id);
                    database.QueueNames.Remove(queue.Name);
                }
                finally
                {
                    database.QueuesLock.ExitWriteLock();
                }
            }
            finally
            {
                queue.QueueLock.ExitWriteLock();
            }
        }
예제 #6
0
        public static void Create(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");
            if (Exists(database, name))
                throw new ArgumentException(string.Format("Queue with the name \"{0}\" already exists.", name), "name");

            var queue = new Queue(name);
            queue.QueueLock.EnterWriteLock();
            try
            {
                database.QueuesLock.EnterWriteLock();
                try
                {
                    database.QueueNames.Add(queue.Name, queue.Id);
                    database.Queues.Add(queue.Id, queue);
                }
                finally
                {
                    database.QueuesLock.ExitWriteLock();
                }
            }
            finally
            {
                queue.QueueLock.ExitWriteLock();
            }
        }
예제 #7
0
        public static void Resume(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");

            var workflow = Get(database, name);
            workflow.WorkflowLock.EnterWriteLock();
            try
            {
                if (!workflow.Suspended)
                    return;

                database.QueuesLock.EnterReadLock();
                try
                {
                    var tasksToQueue = workflow.Tasks.Values.Where(task => task.State == TaskState.Queued).ToList();
                    var queues = tasksToQueue.Select(task => task.QueueId).OrderBy(id => id).Distinct().Select(id => database.Queues[id]).ToList();
                    int queueLocksHeld = 0;
                    try
                    {
                        foreach (var queue in queues)
                        {
                            queue.QueueLock.EnterWriteLock();
                            queueLocksHeld++;
                        }

                        foreach (var task in tasksToQueue)
                        {
                            database.Queues[task.QueueId].QueuedTasks.AddLast(new LinkedListNode<Tuple<Guid, Guid>>(new Tuple<Guid, Guid>(workflow.Id, task.Id)));
                        }

                        workflow.Suspended = false;
                    }
                    finally
                    {
                        // Release write locks for any that were taken.
                        for (int i = 0; i < queueLocksHeld; i++)
                        {
                            queues[i].QueueLock.ExitWriteLock();
                        }
                    }
                }
                finally
                {
                    database.QueuesLock.ExitReadLock();
                }
            }
            finally
            {
                workflow.WorkflowLock.ExitWriteLock();
            }
        }
예제 #8
0
        internal static Queue Get(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");

            database.QueuesLock.EnterReadLock();
            try
            {
                if (!database.QueueNames.ContainsKey(name))
                    throw new Exception(string.Format("Queue named \"{0}\" not found.", name));
                return database.Queues[database.QueueNames[name]];
            }
            finally
            {
                database.QueuesLock.ExitReadLock();
            }
        }
예제 #9
0
        public static int RunningCount(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");

            var queue = Get(database, name);

            queue.QueueLock.EnterReadLock();
            try
            {
                return queue.RunningTasks.Count;
            }
            finally
            {
                queue.QueueLock.ExitReadLock();
            }
        }
예제 #10
0
 public void Initialise()
 {
     this.database = new Database();
 }
예제 #11
0
        public static bool IsSuspended(Database database, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");

            var workflow = Get(database, name);
            workflow.WorkflowLock.EnterReadLock();
            try
            {
                return workflow.Suspended;
            }
            finally
            {
                workflow.WorkflowLock.ExitReadLock();
            }
        }
예제 #12
0
        internal static Workflow Get(Database database, Guid id)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (id == Guid.Empty)
                throw new ArgumentException("id", "id is empty.");

            database.WorkflowsLock.EnterReadLock();
            try
            {
                if (!database.Workflows.ContainsKey(id))
                    return null;
                return database.Workflows[id];
            }
            finally
            {
                database.WorkflowsLock.ExitReadLock();
            }
        }
예제 #13
0
 public static void Suspend(Database database, string name)
 {
     throw new NotImplementedException();
 }
예제 #14
0
        public static QueueTask Peek(Database database, string queueName)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (queueName == null)
                throw new ArgumentNullException("queueName", "queueName is null.");

            Guid workflowId, taskId;
            var queue = Queue.Get(database, queueName);

            queue.QueueLock.EnterReadLock();
            try
            {
                if (queue.QueuedTasks.Count == 0)
                    return null;

                var first = queue.QueuedTasks.First.Value;
                workflowId = first.Item1;
                taskId = first.Item2;
            }
            finally
            {
                queue.QueueLock.ExitReadLock();
            }

            database.WorkflowsLock.EnterReadLock();
            try
            {
                if (!database.Workflows.ContainsKey(workflowId))
                    return null;
                var workflow = database.Workflows[workflowId];
                workflow.WorkflowLock.EnterReadLock();
                try
                {
                    return new QueueTask()
                    {
                        WorkflowName = workflow.Name,
                        TaskName = workflow.Tasks[taskId].Name,
                    };
                }
                finally
                {
                    workflow.WorkflowLock.ExitReadLock();
                }
            }
            finally
            {
                database.WorkflowsLock.ExitReadLock();
            }
        }
예제 #15
0
        public static void Create(Database database, string workflowName, string name, string queueName)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (workflowName == null)
                throw new ArgumentNullException("workflowName", "workflowName is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");
            if (queueName == null)
                throw new ArgumentNullException("queueName", "queueName is null.");

            Task task;
            var workflow = Workflow.Get(database, workflowName);
            var queue = Queue.Get(database, queueName);
            queue.QueueLock.EnterReadLock();
            try
            {
                task = new Task(name, queue.Id);
            }
            finally
            {
                queue.QueueLock.ExitReadLock();
            }

            database.WorkflowsLock.EnterReadLock();
            try
            {
                if (!database.WorkflowNames.ContainsKey(workflowName))
                    throw new Exception(string.Format("Workflow with the name \"{0}\" not found.", workflowName));
                workflow = database.Workflows[database.WorkflowNames[workflowName]];
                if (workflow.Suspended)
                {
                    workflow.WorkflowLock.EnterUpgradeableReadLock();
                    try
                    {
                        workflow.Tasks.Add(task.Id, task);
                        workflow.TaskNames.Add(task.Name, task.Id);
                    }
                    finally
                    {
                        workflow.WorkflowLock.ExitUpgradeableReadLock();
                    }
                }
                else
                {
                    database.QueuesLock.EnterReadLock();
                    try
                    {
                        workflow.WorkflowLock.EnterUpgradeableReadLock();
                        try
                        {
                            queue.QueueLock.EnterWriteLock();
                            try
                            {
                                workflow.Tasks.Add(task.Id, task);
                                workflow.TaskNames.Add(task.Name, task.Id);
                                queue.QueuedTasks.AddLast(new LinkedListNode<Tuple<Guid, Guid>>(new Tuple<Guid, Guid>(workflow.Id, task.Id)));
                            }
                            finally
                            {
                                queue.QueueLock.ExitWriteLock();
                            }
                        }
                        finally
                        {
                            workflow.WorkflowLock.ExitUpgradeableReadLock();
                        }
                    }
                    finally
                    {
                        database.QueuesLock.ExitReadLock();
                    }
                }
            }
            finally
            {
                database.WorkflowsLock.ExitReadLock();
            }
        }
예제 #16
0
 /// <summary>
 /// Requeue a task if it was unable to be completed.
 /// </summary>
 /// <param name="database">Database instance.</param>
 /// <param name="workflowName">Name of the workflow of the task to requeue.</param>
 /// <param name="taskName">Name of the task to requeue.</param>
 public static void Requeue(Database database, string workflowName, string taskName)
 {
     throw new NotImplementedException();
 }
예제 #17
0
        internal static Task Get(Database database, string workflowName, string name)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (workflowName == null)
                throw new ArgumentNullException("workflowName", "workflowName is null.");
            if (name == null)
                throw new ArgumentNullException("name", "name is null.");

            Workflow workflow = Workflow.Get(database, workflowName);
            workflow.WorkflowLock.EnterReadLock();
            try
            {
                if (!workflow.TaskNames.ContainsKey(name))
                    throw new Exception(string.Format("Task named \"{0}\" not found in the workflow named \"{1}\".", name, workflowName));
                return workflow.Tasks[workflow.TaskNames[name]];
            }
            finally
            {
                workflow.WorkflowLock.ExitReadLock();
            }
        }
예제 #18
0
        public static void Complete(Database database, string workflowName, string taskName)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (workflowName == null)
                throw new ArgumentNullException("workflowName", "workflowName is null.");
            if (taskName == null)
                throw new ArgumentNullException("taskName", "taskName is null.");

            Workflow workflow;
            Task task;
            Queue queue;
            bool workflowCompleted = false;

            database.WorkflowsLock.EnterReadLock();
            try
            {
                database.QueuesLock.EnterReadLock();
                try
                {
                    workflow = database.Workflows[database.WorkflowNames[workflowName]];
                    workflow.WorkflowLock.EnterWriteLock();
                    try
                    {
                        task = workflow.Tasks[workflow.TaskNames[taskName]];
                        queue = database.Queues[task.QueueId];

                        var queuesIdsToLock = task.DependencyTo.Select(taskId => workflow.Tasks[taskId].QueueId).ToList();
                        queuesIdsToLock.Add(task.QueueId);
                        queuesIdsToLock = queuesIdsToLock.OrderBy(id => id).Distinct().ToList();
                        int queueLockCount = 0;

                        try
                        {
                            foreach (var queueId in queuesIdsToLock)
                            {
                                database.Queues[queueId].QueueLock.EnterWriteLock();
                                queueLockCount++;
                            }

                            queue.RunningTasks.Remove(task.Id);
                            task.State = TaskState.Completed;
                            workflow.CompletedTasks.Add(task.Id);
                            foreach (var nextTaskId in task.DependencyTo)
                            {
                                var nextTask = workflow.Tasks[nextTaskId];
                                nextTask.OutstandingDependencies.Remove(task.Id);
                                if (nextTask.OutstandingDependencies.Count == 0)
                                {
                                    nextTask.State = TaskState.Queued;
                                    var nextQueue = database.Queues[nextTask.QueueId];
                                    nextQueue.QueuedTasks.AddLast(new LinkedListNode<Tuple<Guid, Guid>>(new Tuple<Guid, Guid>(workflow.Id, nextTask.Id)));
                                }
                            }

                            if (workflow.CompletedTasks.Count == workflow.Tasks.Count)
                            {
                                workflowCompleted = true;
                            }
                        }
                        finally
                        {
                            // Release all taken locks in order taken.
                            for (int i = queueLockCount - 1; i >= 0; i--)
                            {
                                database.Queues[queuesIdsToLock[i]].QueueLock.ExitWriteLock();
                            }
                        }
                    }
                    finally
                    {
                        workflow.WorkflowLock.ExitWriteLock();
                    }
                }
                finally
                {
                    database.QueuesLock.ExitReadLock();
                }
            }
            finally
            {
                database.WorkflowsLock.ExitReadLock();
            }

            if (workflowCompleted)
            {
                database.WorkflowsLock.EnterWriteLock();
                try
                {
                    database.WorkflowNames.Remove(workflow.Name);
                    database.Workflows.Remove(workflow.Id);
                }
                finally
                {
                    database.WorkflowsLock.ExitWriteLock();
                }
            }
        }
예제 #19
0
        public static void AddDependency(Database database, string workflowName, string nameDependantOn, string nameDependancyTo)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");
            if (workflowName == null)
                throw new ArgumentNullException("workflowName", "workflowName is null.");
            if (nameDependantOn == null)
                throw new ArgumentNullException("nameDependantOn", "nameDependantOn is null.");
            if (workflowName == null)
                throw new ArgumentNullException("nameDependancyTo", "nameDependancyTo is null.");

            var workflow = Workflow.Get(database, workflowName);
            var dependantOn = Task.Get(database, workflowName, nameDependantOn);
            var dependancyTo = Task.Get(database, workflowName, nameDependancyTo);
            var dependancyToQueue = Queue.Get(database, dependancyTo.QueueId);

            workflow.WorkflowLock.EnterWriteLock();
            try
            {
                switch (dependancyTo.State)
                {
                    case TaskState.AwaitDependence:
                        break;
                    case TaskState.Queued:
                        if (!workflow.Suspended)
                        {
                            dependancyToQueue.QueueLock.EnterWriteLock();
                            try
                            {
                                dependancyToQueue.QueuedTasks.Remove(dependancyToQueue.QueuedTasks.First(t => t.Item2 == dependancyTo.Id));
                            }
                            finally
                            {
                                dependancyToQueue.QueueLock.ExitWriteLock();
                            }
                        }
                        break;
                    case TaskState.Running:
                    case TaskState.Completed:
                    case TaskState.Failed:
                    default:
                        throw new InvalidOperationException("Can only add dependancy to a task which has not yet been started.");
                }

                dependancyTo.State = TaskState.AwaitDependence;
                dependantOn.DependencyTo.Add(dependancyTo.Id);
                dependancyTo.DependantOn.Add(dependantOn.Id);

                switch (dependantOn.State)
                {
                    case TaskState.AwaitDependence:
                    case TaskState.Queued:
                    case TaskState.Running:
                        dependancyTo.OutstandingDependencies.Add(dependantOn.Id);
                        break;
                }
            }
            finally
            {
                workflow.WorkflowLock.ExitWriteLock();
            }
        }
예제 #20
0
        internal static Queue Get(Database database, Guid guid)
        {
            if (database == null)
                throw new ArgumentNullException("database", "database is null.");

            database.QueuesLock.EnterReadLock();
            try
            {
                return database.Queues[guid];
            }
            finally
            {
                database.QueuesLock.ExitReadLock();
            }
        }
예제 #21
0
        static void Main(string[] args)
        {
            queueNames = Enumerable.Range(1, QueueCount).Select(i => string.Format("Queue {0}", i)).ToList();
            database = new Database();

            foreach (var name in queueNames)
            {
                Queue.Create(database, name);
            }

            for (int i = 0; i < QueueProcessors; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(QueueProcessor), queueNames[i % QueueCount]);
            }

            for (int i = 0; i < WorkflowCreators; i++)
            {
                ThreadPool.QueueUserWorkItem(new WaitCallback(TaskCreator));
            }

            while (!stopping)
            {
                PrintOverview();

                if (Console.KeyAvailable)
                {
                    var keyPress = Console.ReadKey(true);
                    switch (keyPress.Key)
                    {
                        case ConsoleKey.DownArrow:
                            // Decrease process time.
                            if (TaskCompletionTime.TotalMilliseconds >= 1)
                                TaskCompletionTime = TaskCompletionTime.Add(TimeSpan.FromMilliseconds(-1));
                            break;
                        case ConsoleKey.UpArrow:
                            // Increase process time.
                            TaskCompletionTime = TaskCompletionTime.Add(TimeSpan.FromMilliseconds(1));
                            break;
                        case ConsoleKey.LeftArrow:
                            // Decrease rate of queuing.
                            WorkflowCreationFrequency = WorkflowCreationFrequency.Add(TimeSpan.FromMilliseconds(1));
                            break;
                        case ConsoleKey.RightArrow:
                            // Increase rate of queuing.
                            if (WorkflowCreationFrequency.TotalMilliseconds >= 1)
                                WorkflowCreationFrequency = WorkflowCreationFrequency.Add(TimeSpan.FromMilliseconds(-1));
                            break;
                        case ConsoleKey.OemComma:
                            // < - Decrease check frequency.
                            QueueCheckFrequency = QueueCheckFrequency.Add(TimeSpan.FromMilliseconds(1));
                            break;
                        case ConsoleKey.OemPeriod:
                            // > - Increase check frequency.
                            if (QueueCheckFrequency.TotalMilliseconds >= 1)
                                QueueCheckFrequency = QueueCheckFrequency.Add(TimeSpan.FromMilliseconds(-1));
                            break;
                        case ConsoleKey.X:
                            stopping = true;
                            break;
                        default:
                            break;
                    }
                }

                Thread.Sleep(200);
            }
        }