Exemple #1
0
        public void Enqueue(TaskWorker new_worker)
        {
            bool start = false;

            lock ( _sync ) {
                Queue work_queue = (Queue)_task_to_workers[new_worker.Task];
                if (work_queue == null)
                {
                    //This is a new task:
                    work_queue = new Queue();
                    _task_to_workers[new_worker.Task] = work_queue;
                    //Start the job!
                    start = true;
                }
                //In any case, add the worker:
                new_worker.FinishEvent += this.TaskEndHandler;
                work_queue.Enqueue(new_worker);
                _worker_count++;
            }

            /*
             * Get to work!
             */
            if (start && (1 == _is_active))
            {
                Start(new_worker);
            }
        }
Exemple #2
0
        /**
         * This creates a TaskWorker that represents the next step that should
         * be taken for the ta.  It can only be two tasks: create the edge
         * (EdgeWorker) or wait and try again (RestartState).
         *
         * We return null if:
         *  - the TA is null
         *  - Linker is finished
         *  - a Connection was already created
         *  - this TA has been restarted too many times
         *
         * If we cannot get a ConnectionTable.Lock with SetTarget, we return a
         * RestartState to wait a little while to try to get the lock again.
         *
         * @returns the next TaskWorker that should be enqueued, does not start or
         * Enqueue it.
         */
        protected BC.TaskWorker StartAttempt(TransportAddress next_ta)
        {
            BC.TaskWorker next_task = null;
            if ((next_ta == null) || (_added_cons != 0) || IsFinished || ConnectionInTable)
            {
                //Looks like we are already connected...
                return(null);
            }
            try {
#if LINK_DEBUG
                if (BU.ProtocolLog.LinkDebug.Enabled)
                {
                    BU.ProtocolLog.Write(BU.ProtocolLog.LinkDebug,
                                         String.Format("{0}: Linker ({1}) attempting to lock {2}", _local_n.Address, _lid, _target));
                }
#endif

                /*
                 * If we cannot set this address as our target, we
                 * stop before we even try to make an edge.
                 *
                 * Locks flow around in complex ways, but we
                 * (or one of our LinkProtocolState)
                 * will hold the lock
                 */
                SetTarget();
#if LINK_DEBUG
                if (BU.ProtocolLog.LinkDebug.Enabled)
                {
                    BU.ProtocolLog.Write(BU.ProtocolLog.LinkDebug,
                                         String.Format("{0}: Linker ({1}) acquired lock on {2}", _local_n.Address, _lid, _target));
                    BU.ProtocolLog.Write(BU.ProtocolLog.LinkDebug,
                                         String.Format("{0}: Linker: ({1}) Trying TA: {2}", _local_n.Address, _lid, next_ta));
                }
#endif
                next_task              = new EdgeWorker(_local_n, next_ta);
                next_task.FinishEvent += this.EdgeWorkerHandler;
            }
            catch (CTLockException) {
                /*
                 * If we cannot get a lock on the address in SetTarget()
                 * we wait and and try again
                 */
#if LINK_DEBUG
                if (BU.ProtocolLog.LinkDebug.Enabled)
                {
                    BU.ProtocolLog.Write(BU.ProtocolLog.LinkDebug,
                                         String.Format("{0}: Linker ({1}) failed to lock {2}", _local_n.Address, _lid, _target));
                }
#endif
                next_task = GetRestartState(next_ta);
            }
            catch (ConnectionExistsException) {
                //We already have a connection to the target
            }
            catch (Exception) {
            }
            return(next_task);
        }
Exemple #3
0
 protected override void Start(BC.TaskWorker tw)
 {
     try {
         LocalNode.EnqueueAction(tw);
     }
     catch {
         /*
          * We could get an exception if queue in LocalNode is closed
          */
         tw.Start();
     }
 }
Exemple #4
0
//////////////////
///
/// Protected/Private methods
///
/////////////////

        /**
         * @param success if this is true, we have a new edge to try else, make a new edge
         * @param target_ta the transport address this edge was created with
         * @param e the new edge, if success
         * @param x the exception which may be present if sucess is false
         */
        protected void EdgeWorkerHandler(object edgeworker, EventArgs args)
        {
            EdgeWorker ew         = (EdgeWorker)edgeworker;
            bool       close_edge = false;

            BC.TaskWorker next_task = null;
            try {
                Edge e = ew.NewEdge; //This can throw an exception
                SetTarget();         //This can also throw an exception

                //If we make it here, we did not have any problem.

                next_task              = new LinkProtocolState(this, ew.TA, e);
                next_task.FinishEvent += this.LinkProtocolStateFinishHandler;
            }
            catch (LinkException) {
                //This happens if SetTarget sees that we are already connected
                //Our only choice here is to close the edge and give up.
                close_edge = true;
            }
            catch (EdgeException) {
                /*
                 * If there is some problem creating the edge,
                 * we wind up here.  Just move on
                 */
                next_task = StartAttempt(NextTA());
            }
            catch (Exception ex) {
                /*
                 * The edge creation didn't work out so well
                 */
                BU.ProtocolLog.WriteIf(BU.ProtocolLog.LinkDebug, ex.ToString());
                next_task = StartAttempt(NextTA());
            }
            if (close_edge)
            {
                try {
                    ew.NewEdge.Close();
                }
                catch (Exception) {
                    //Ignore any exception
                }
            }
            if (next_task != null)
            {
                /*
                 * We should start a new task now
                 */
                _task_queue.Enqueue(next_task);
            }
        }
Exemple #5
0
/////////////
///
///  Public methods
///
///////////

        /**
         * This tells the Linker to make its best effort to create
         * a connection to another node
         */
        override public void Start()
        {
#if LINK_DEBUG
            if (BU.ProtocolLog.LinkDebug.Enabled)
            {
                BU.ProtocolLog.Write(BU.ProtocolLog.LinkDebug, String.Format("{0}, Linker({1}).Start at: {2}", _local_n.Address, _lid, DateTime.UtcNow));
            }
#endif
            //Try to set _started to 1, if already set to one, throw an exception
            if (Interlocked.Exchange(ref _started, 1) == 1)
            {
                throw new Exception("Linker already Started");
            }
            //Just move to the next (first) TA
            //Get the set of addresses to try
            int parallel_attempts = _MAX_PARALLEL_ATTEMPTS;
            if (_target == null)
            {
                //Try more attempts in parallel to get leaf connections.
                //This is a hack to make initial connection faster
                parallel_attempts = 2 * parallel_attempts;
            }
            //This would be an ideal place for a list comprehension
            ArrayList tasks_to_start = new ArrayList(parallel_attempts);
            for (int i = 0; i < parallel_attempts; i++)
            {
                BC.TaskWorker t = StartAttempt(NextTA());
                if (t != null)
                {
                    tasks_to_start.Add(t);
                }
            }
            foreach (BC.TaskWorker t in tasks_to_start)
            {
                _task_queue.Enqueue(t);
            }

            /*
             * We have so far prevented ourselves from sending the
             * FinishEvent.  Now, we have laid all the ground work,
             * if there are no active tasks, there won't ever be,
             * so lets check to see if we need to fire the finish
             * event
             */
            Interlocked.Exchange(ref _hold_fire, 0);
            if (_task_queue.WorkerCount == 0)
            {
                FinishCheckHandler(_task_queue, EventArgs.Empty);
            }
        }
Exemple #6
0
        /**
         * When a TaskWorker completes, we remove it from the queue and
         * start the next in that task queue
         */
        protected void TaskEndHandler(object worker, EventArgs args)
        {
            TaskWorker   new_worker = null;
            EventHandler eh         = null;

            lock ( _sync ) {
                TaskWorker this_worker = (TaskWorker)worker;
                object     task        = this_worker.Task;
                Queue      work_queue  = (Queue)_task_to_workers[task];
                if (work_queue != null)
                {
                    work_queue.Dequeue();
                    if (work_queue.Count > 0)
                    {
                        //Now the new job is at the head of the queue:
                        new_worker = (TaskWorker)work_queue.Peek();
                    }
                    else
                    {
                        /*
                         * There are no more elements in the queue, forget it:
                         * If we leave a 0 length queue, this would be a memory
                         * leak
                         */
                        _task_to_workers.Remove(task);
                    }
                    _worker_count--;
                    if (_worker_count == 0)
                    {
                        eh = EmptyEvent;
                    }
                }
                else
                {
                    //This TaskEndHandler has been called more than once clearly.
                    Console.Error.WriteLine("ERROR: {0} called TaskEndHandler but no queue for this task: {1}",
                                            worker, task);
                }
            }
            if (new_worker != null && (1 == _is_active))
            {
                //You start me up!
                Start(new_worker);
            }
            if (eh != null)
            {
                eh(this, EventArgs.Empty);
            }
        }
Exemple #7
0
        /**
         * When a RestartState finishes its task, this is the
         * EventHandler that is called.
         *
         * At the end of a RestartState, we call StartAttempt for
         * the TA we are waiting on.  If we have restarted too many
         * times, we move to the next TA, and StartAttempt with that one.
         */
        protected void RestartHandler(object orss, EventArgs args)
        {
            RestartState rss = (RestartState)orss;

            BC.TaskWorker next_task = StartAttempt(rss.TA);
            if (next_task == null)
            {
                //Looks like it's time to move on:
                next_task = StartAttempt(NextTA());
            }
            if (next_task != null)
            {
                _task_queue.Enqueue(next_task);
            }
        }
Exemple #8
0
 /**
  * If you want to control if new TaskWorkers are started in some
  * other thread, or event loop, you can override this method
  */
 protected virtual void Start(TaskWorker tw) {
   tw.Start();
 }
Exemple #9
0
 public void Enqueue(TaskWorker new_worker)
 {
   bool start = false;
   lock( _sync ) {
     Queue work_queue = (Queue)_task_to_workers[ new_worker.Task ];
     if( work_queue == null ) {
       //This is a new task:
       work_queue = new Queue();
       _task_to_workers[ new_worker.Task ] = work_queue;
       //Start the job!
       start = true;
     }
     //In any case, add the worker:
     new_worker.FinishEvent += this.TaskEndHandler;
     work_queue.Enqueue(new_worker);
     _worker_count++;
   }
   /*
    * Get to work!
    */
   if( start  && (1 == _is_active)) {
     Start(new_worker);
   }
 }
Exemple #10
0
        protected void LinkProtocolStateFinishHandler(object olps, EventArgs args)
        {
            LinkProtocolState lps = (LinkProtocolState)olps;

#if LINK_DEBUG
            if (BU.ProtocolLog.LinkDebug.Enabled)
            {
                BU.ProtocolLog.Write(BU.ProtocolLog.LinkDebug,
                                     String.Format("{0}: Linker({1}): {2} finished with result: {3} at: {4}",
                                                   _local_n.Address, _lid, lps, lps.MyResult, DateTime.UtcNow));
            }
#endif
            BC.TaskWorker next_task = null;
            switch (lps.MyResult)
            {
            case LinkProtocolState.Result.Success:
                /*
                 * Great, the Connection is up and in our table now
                 * Just do nothing now and wait for the other tasks
                 * to finish, at which point, the Linker will fire
                 * its FinishEvent.
                 */
                Interlocked.Increment(ref _added_cons);
#if LINK_DEBUG
                if (BU.ProtocolLog.LinkDebug.Enabled)
                {
                    BU.ProtocolLog.Write(BU.ProtocolLog.LinkDebug,
                                         String.Format("{0}: Linker({1}) added {2} at: {3}", _local_n.Address,
                                                       _lid, lps.Connection, DateTime.UtcNow));
                }
#endif
                break;

            case LinkProtocolState.Result.RetryThisTA:
                next_task = GetRestartState(lps.TA);
                if (next_task == null)
                {
                    goto case LinkProtocolState.Result.MoveToNextTA;
                }
                break;

            case LinkProtocolState.Result.MoveToNextTA:
                //Hold the lock, it will be transferred:
                // old LPS -> Linker -> new LPS
                next_task = StartAttempt(NextTA());
                break;

            case LinkProtocolState.Result.ProtocolError:
                break;

            case LinkProtocolState.Result.Exception:
                break;

            default:
                //This should not happen.
                Console.Error.WriteLine("unrecognized result: " + lps.MyResult.ToString());
                break;
            }
            if (next_task != null)
            {
                //We have some new task to start
                _task_queue.Enqueue(next_task);
            }
            int current_active = Interlocked.Decrement(ref _active_lps_count);
            if (current_active == 0)
            {
                //We have finished handling this lps finishing,
                //if we have not started another yet, we are not
                //going to right away.  In the mean time, release
                //the lock
                Unlock();
            }
        }
Exemple #11
0
//////////////////
///
/// Protected/Private methods
///
/////////////////

        /**
         * @param success if this is true, we have a new edge to try else, make a new edge
         * @param target_ta the transport address this edge was created with
         * @param e the new edge, if success
         * @param x the exception which may be present if sucess is false
         */
        protected void EdgeWorkerHandler(object edgeworker, EventArgs args)
        {
            EdgeWorker ew         = (EdgeWorker)edgeworker;
            bool       close_edge = false;

            BC.TaskWorker next_task = null;
            try {
                Edge e = ew.NewEdge; //This can throw an exception
                SetTarget();         //This can also throw an exception

                //If we make it here, we did not have any problem.

                next_task              = new LinkProtocolState(this, ew.TA, e);
                next_task.FinishEvent += this.LinkProtocolStateFinishHandler;
                //Keep a proper track of the active LinkProtocolStates:
                Interlocked.Increment(ref _active_lps_count);
            }
            catch (ConnectionExistsException) {
                //We already have a connection to the target
                close_edge = true;
            }
            catch (LinkException) {
                //This happens if SetTarget sees that we are already connected
                //Our only choice here is to close the edge and give up.
                close_edge = true;
            }
            catch (CTLockException) {
                /*
                 * SetTarget could not get the lock on the address.
                 * Try again later
                 */
                close_edge = true;
                next_task  = GetRestartState(ew.TA);
                if (next_task == null)
                {
                    //We've restarted too many times:
                    next_task = StartAttempt(NextTA());
                }
            }
            catch (EdgeException) {
                /*
                 * If there is some problem creating the edge,
                 * we wind up here.  Just move on
                 */
                next_task = StartAttempt(NextTA());
            }
            catch (Exception ex) {
                /*
                 * The edge creation didn't work out so well
                 */
                BU.ProtocolLog.WriteIf(BU.ProtocolLog.LinkDebug, ex.ToString());
                next_task = StartAttempt(NextTA());
            }
            if (close_edge)
            {
                try {
                    ew.NewEdge.Close();
                }
                catch (Exception) {
                    //Ignore any exception
                }
            }
            if (next_task != null)
            {
                /*
                 * We should start a new task now
                 */
                _task_queue.Enqueue(next_task);
            }
        }
Exemple #12
0
 protected override void Start(TaskWorker tw) {
   LocalNode.EnqueueAction(tw);
 }
Exemple #13
0
 /**
  * If you want to control if new TaskWorkers are started in some
  * other thread, or event loop, you can override this method
  */
 protected virtual void Start(TaskWorker tw)
 {
     tw.Start();
 }