예제 #1
0
 /// <summary>
 /// Disconnect from the KCD if required.
 /// </summary>
 private void DisconnectFromKcdIfNeeded()
 {
     if (!WantKcdConnected() && m_kws.InKcdConnectTree())
     {
         WmSm.HandleKwsToDisconnect(m_kws);
     }
 }
예제 #2
0
        /// <summary>
        /// Called when the login fails for some reason.
        /// </summary>
        public void HandleLoginFailure(Exception ex)
        {
            WmSm.LockNotif();

            Debug.Assert(m_ks.LoginStatus == KwsLoginStatus.LoggingIn);

            // Update our login state.
            UpdateStateOnLogout(ex);

            // The events are out of sync.
            if (m_ks.LoginResult == KwsLoginResult.OOS)
            {
                // Request a rebuild. We have to delete both the cached events and
                // the user data. This is nasty.
                if (m_cd.MainStatus == KwsMainStatus.Good || m_cd.MainStatus == KwsMainStatus.RebuildRequired)
                {
                    m_cd.MainStatus   = KwsMainStatus.RebuildRequired;
                    m_cd.RebuildFlags = KwsRebuildFlag.FlushKcdData | KwsRebuildFlag.FlushLocalData;
                }
            }

            // Make the workspace work offline if required. The core operations
            // may have already marked the workspace for removal.
            if (m_cd.CurrentTask == KwsTask.WorkOnline)
            {
                SetUserTask(KwsTask.WorkOffline);
                RequestTaskSwitch(KwsTask.WorkOffline, ex);
            }

            WmSm.UnlockNotif();
        }
예제 #3
0
 /// <summary>
 /// Connect to the KCD if required.
 /// </summary>
 private void ConnectToKcdIfNeeded()
 {
     if (WantKcdConnected() && !m_kws.InKcdConnectTree())
     {
         WmSm.HandleKwsToConnect(m_kws);
     }
 }
예제 #4
0
        /////////////////////////////////////////////
        // Interface methods for external parties. //
        /////////////////////////////////////////////

        /// <summary>
        /// This method must be called by each application when it has started.
        /// </summary>
        public void OnAppStarted()
        {
            // The applications are no longer starting.
            if (m_cd.AppStatus != KwsAppStatus.Starting)
            {
                return;
            }

            // Not all applications have started.
            foreach (KwsApp app in m_kws.AppTree.Values)
            {
                if (app.AppStatus != KwsAppStatus.Started)
                {
                    return;
                }
            }

            WmSm.LockNotif();

            // All applications are started.
            m_cd.AppStatus = KwsAppStatus.Started;

            // Notify the listeners.
            WmSm.QueueNotif(new KwsSmNotifApp(m_kws, m_cd.AppStatus));

            // Let the state machine sort it out.
            RequestRun("Applications started");

            WmSm.UnlockNotif();
        }
예제 #5
0
        /// <summary>
        /// This method should be called when an unexpected failure occurs
        /// in the workspace.
        /// </summary>
        public void HandleMiscFailure(Exception ex)
        {
            WmSm.LockNotif();

            KLogging.LogException(ex);

            // We cannot handle failures during task switches. We need the
            // task switches to succeed to recover from failures.
            if (m_taskSwitchFlag)
            {
                KBase.HandleException(ex, true);
            }

            // Increase the severity of the rebuild required if possible.
            if (m_cd.CurrentTask == KwsTask.Rebuild)
            {
                WorsenRebuild(KwsRebuildFlag.FlushKcdData | KwsRebuildFlag.FlushLocalData);
            }

            // Stop the workspace if required.
            SetUserTask(KwsTask.Stop);
            RequestTaskSwitch(KwsTask.Stop, ex);

            // Let the state machine sort it out.
            RequestRun("application failure");

            WmSm.UnlockNotif();
        }
예제 #6
0
 /// <summary>
 /// This method can be called by the state machine methods to request
 /// the state machine to run at Deadline. If Deadline is MinValue, the
 /// state machine will be run again immediately.
 /// </summary>
 public void ScheduleRun(String reason, DateTime deadline)
 {
     if (deadline < NextRunDate)
     {
         NextRunDate = deadline;
         WmSm.ScheduleRun(KwmStrings.Kws + m_kws.InternalID + ": " + reason, deadline);
     }
 }
예제 #7
0
 /// <summary>
 /// This method should be called when the UI is exited.
 /// </summary>
 public static void OnUiExit()
 {
     Debug.Assert(UiEntryCount > 0);
     UiEntryCount--;
     if (UiEntryCount == 0)
     {
         WmSm.HandleUiExit();
     }
 }
예제 #8
0
        /// <summary>
        /// Called when the workspace logs out normally.
        /// </summary>
        public void HandleNormalLogout()
        {
            WmSm.LockNotif();

            Debug.Assert(m_ks.LoginStatus == KwsLoginStatus.LoggingOut);

            // Update our login state.
            UpdateStateOnLogout(null);

            WmSm.UnlockNotif();
        }
예제 #9
0
        /// <summary>
        /// Update KcdEventUpToDateFlag, EAnpFreshnessID and handle notifications.
        /// </summary>
        private void UpdateKcdEventUpToDateState()
        {
            bool newValue = AreKcdEventUpToDate();

            if (m_ks.KcdEventUpToDateFlag == newValue)
            {
                return;
            }
            m_ks.KcdEventUpToDateFlag = newValue;
            if (newValue)
            {
                WmSm.QueueNotif(new KwsSmNotifKcdEventUpToDate(m_kws));
            }
        }
예제 #10
0
        /// <summary>
        /// Called when the KCD connection status has changed. This method is
        /// only called by the WM state machine.
        /// </summary>
        public void HandleKcdConnStatusChange(KcdConnStatus status, Exception ex)
        {
            // Update our login state.
            if (status == KcdConnStatus.Disconnecting || status == KcdConnStatus.Disconnected)
            {
                UpdateStateOnLogout(ex);
            }

            // Notify the listeners.
            WmSm.QueueNotif(new KwsSmNotifKcdConn(m_kws, status, ex));

            // Let the state machine sort it out.
            RequestRun("KCD connection status change");
        }
예제 #11
0
 /// <summary>
 /// Switch the current task to the task specified. Don't call this
 /// outside RequestSwitchTask() unless you know what you are doing.
 /// The state machine will run ASAP to handle the new state.
 /// </summary>
 private void SwitchTask(KwsTask task, Exception ex)
 {
     // The order of the calls is important here.
     WmSm.LockNotif();
     Debug.Assert(m_taskSwitchFlag == false);
     m_taskSwitchFlag = true;
     m_cd.CurrentTask = task;
     StopAppIfNeeded(ex);
     DisconnectFromKcdIfNeeded();
     LogoutIfNeeded();
     StopRebuildIfNeeded();
     UpdateKcdEventUpToDateState();
     m_kws.OnStateChange(WmStateChange.Transient);
     RequestRun("task switch to " + task);
     m_taskSwitchFlag = false;
     WmSm.QueueNotif(new KwsSmNotifTaskSwitch(m_kws, task, ex));
     WmSm.UnlockNotif();
 }
예제 #12
0
        public static void Relink(WmDeserializer ds)
        {
            Cd = ds.WmCd;
            WmSm.Relink();
            KcdBroker.OnEvent            += WmSm.HandleKcdBrokerNotification;
            KmodBroker.OnThreadCollected += WmSm.OnThreadCollected;
            EAnpBroker.OnClose           += WmSm.OnThreadCollected;
            EAnpBroker.OnChannelOpen     += WmEAnp.HandleChannelOpen;

            foreach (UInt64 internalID in ds.KwsCdList.Keys)
            {
                Workspace   kws   = new Workspace();
                KwsCoreData kwsCd = ds.KwsCdList[internalID];
                kws.Relink(internalID, kwsCd);
            }

            AdjustPublicKwsID();
        }
예제 #13
0
        /// <summary>
        /// Called when the workspace becomes logged in.
        /// </summary>
        public void HandleLoginSuccess()
        {
            WmSm.LockNotif();

            Debug.Assert(m_ks.LoginStatus == KwsLoginStatus.LoggingIn);

            // We're now logged in.
            m_ks.LoginStatus = KwsLoginStatus.LoggedIn;

            // Update the event up to date state.
            UpdateKcdEventUpToDateState();

            // Notify the listeners.
            WmSm.QueueNotif(new KwsSmNotifKcdLogin(m_kws, m_ks.LoginStatus, null));

            // Let the state machine sort it out.
            RequestRun("Workspace login success");

            WmSm.UnlockNotif();
        }
예제 #14
0
        /// <summary>
        /// Dispatch an KCD event and update the state as needed.
        /// </summary>
        private void DispatchKcdEvent(AnpMsg msg)
        {
            // Dispatch the event to the appropriate handler.
            KwsAnpEventStatus newStatus = DispatchAnpEventToHandler(msg);

            // For quenching purposes we assume the event was processed.
            WmSm.HandleKcdEventProcessed();

            // If the ANP event has been processed, update its entry in the
            // database and the catch up state as required.
            if (newStatus == KwsAnpEventStatus.Processed)
            {
                if (msg.ID > 0)
                {
                    Debug.Assert(m_ks.NbUnprocessedEvent > 0);
                    m_kws.UpdateKAnpEventStatusInDb(msg.ID, KwsAnpEventStatus.Processed);
                    m_ks.NbUnprocessedEvent--;
                    UpdateKcdEventUpToDateState();
                    m_kws.OnStateChange(WmStateChange.Permanent);
                }
            }
        }
예제 #15
0
        /// <summary>
        /// Called when the workspace logs out normally, the login fails or
        /// the connection to the KCD is lost.
        /// </summary>
        private void UpdateStateOnLogout(Exception ex)
        {
            if (m_ks.LoginStatus == KwsLoginStatus.LoggedOut)
            {
                return;
            }

            // Set the last exception.
            m_kws.Cd.LastException = ex;
            m_kws.OnStateChange(WmStateChange.Transient);

            // Update the login status.
            m_kws.KcdLoginHandler.ResetOnLogout();

            // Cancel all the pending KCD queries that depend on the login
            // state.
            m_kws.Kcd.CancelKwsKcdQuery(m_kws);

            // Update the event up to date state.
            UpdateKcdEventUpToDateState();

            // Notify the listeners.
            WmSm.QueueNotif(new KwsSmNotifKcdLogin(m_kws, m_ks.LoginStatus, ex));
        }
예제 #16
0
        /// <summary>
        /// Request a switch to the task specified, if possible. 'Ex' is
        /// non-null if the task switch is occurring because an error occurred.
        /// </summary>
        public void RequestTaskSwitch(KwsTask task, Exception ex)
        {
            WmSm.LockNotif();

            try
            {
                // Validate.
                if (m_taskSwitchFlag ||
                    task == KwsTask.Stop && !CanStop() ||
                    task == KwsTask.Spawn && !CanSpawn() ||
                    task == KwsTask.Rebuild && !CanRebuild() ||
                    task == KwsTask.WorkOffline && !CanWorkOffline() ||
                    task == KwsTask.WorkOnline && !CanWorkOnline() ||
                    task == KwsTask.DeleteLocally && !CanDeleteLocally() ||
                    task == KwsTask.DeleteRemotely && !CanDeleteRemotely())
                {
                    KLogging.Log("Request to switch to task " + task + " ignored.");
                    return;
                }

                KLogging.Log("Switching to task " + task + ".");

                // Update some state prior to the task switch.
                if (task == KwsTask.Rebuild)
                {
                    m_cd.MainStatus = KwsMainStatus.RebuildRequired;
                    m_rebuildStep   = KwsRebuildTaskStep.None;
                }

                else if (task == KwsTask.WorkOnline)
                {
                    ResetKcdFailureState();
                }

                else if (task == KwsTask.DeleteLocally)
                {
                    m_cd.MainStatus = KwsMainStatus.OnTheWayOut;
                    m_kws.AddToKwsRemoveTree();
                    m_kws.OnStateChange(WmStateChange.Permanent);
                }

                else if (task == KwsTask.DeleteRemotely)
                {
                    ResetKcdFailureState();
                    m_deleteRemotelyStep = KwsDeleteRemotelyStep.ConnectedAndLoggedOut;
                }

                if (task == KwsTask.Spawn ||
                    task == KwsTask.Rebuild ||
                    task == KwsTask.WorkOffline ||
                    task == KwsTask.WorkOnline)
                {
                    m_cd.LastException = null;
                    m_kws.OnStateChange(WmStateChange.Permanent);
                }

                // Perform the task switch, if required.
                if (task != m_cd.CurrentTask)
                {
                    SwitchTask(task, ex);
                }
            }

            catch (Exception ex2)
            {
                KBase.HandleException(ex2, true);
            }

            finally
            {
                WmSm.UnlockNotif();
            }
        }
예제 #17
0
 /// <summary>
 /// Request the WM to clear the errors of our KCD, if any.
 /// </summary>
 private void ResetKcdFailureState()
 {
     WmSm.ResetKcdFailureState(m_kws.Kcd);
 }
예제 #18
0
 /// <summary>
 /// Blame the KCD of this workspace for the failure specified.
 /// </summary>
 private void BlameKcd(Exception ex)
 {
     WmSm.HandleTroublesomeKcd(m_kws.Kcd, ex);
 }
예제 #19
0
파일: Program.cs 프로젝트: tmbx/kwm-ng
        /// <summary>
        /// Enter the main mode of the KWM. Return true if the application
        /// must continue.
        /// </summary>
        private static bool EnterMainMode()
        {
            // Perform early linking.
            Wm.LocalDbBroker.Relink(Wm.LocalDb);

            // FIXME.
#if true
            // Open a temporary console.
            ConsoleWindow foo = new ConsoleWindow();
            foo.Show();
            foo.OnConsoleClosing += delegate(Object sender, EventArgs args)
            {
                WmSm.RequestStop();
            };

            // Create an empty database.
            Wm.LocalDb.DeleteDb();
            Wm.LocalDb.OpenOrCreateDb(KwmPath.GetKwmDbPath());
            Wm.LocalDbBroker.InitDb();
            WmDeserializer ds = new WmDeserializer();
            ds.Deserialize();
            Debug.Assert(ds.Ex == null);
#else
            // Open or create the database.
            Wm.LocalDb.OpenOrCreateDb(KwmPath.GetKwmDbPath());
            Wm.LocalDbBroker.InitDb();

            // Try to deserialize.
            WmDeserializer ds = new WmDeserializer();
            ds.Deserialize();

            // The deserialization failed.
            if (ds.Ex != null)
            {
                // If the user doesn't want to recover, bail out.
                if (!TellUserAboutDsrFailure())
                {
                    return(false);
                }

                // Backup, delete and recreate a database.
                BackupDb();
                Wm.LocalDb.DeleteDb();
                Wm.LocalDb.OpenOrCreateDb(KwmPath.GetKwmDbPath());
                Wm.LocalDbBroker.InitDb();

                // Retry to deserialize.
                ds = new WmDeserializer();
                ds.Deserialize();
                if (ds.Ex != null)
                {
                    throw ds.Ex;
                }

                // Set the next internal workspace ID to a high value based on
                // the date to avoid conflicts with old KFS directories.
                ds.WmCd.NextKwsInternalID = (UInt64)(DateTime.Now - new DateTime(2010, 1, 1)).TotalSeconds;
            }
#endif

            // Relink the workspace manager object graphs.
            Wm.Relink(ds);

            // Open the lingering database transaction.
            Wm.LocalDb.BeginTransaction();

            // Serialize the WM state that has changed.
            Wm.Serialize();

            // Export the workspaces, then exit.
            if (ExportKwsPath != "")
            {
                WmKwsImportExport.ExportKws(ExportKwsPath, 0);
                return(false);
            }

            // Set the handle to the message window.
            SetKwmHandle(MsgWindow.Handle);

            // Pass the hand to the WM state machine.
            WmSm.RequestStart();

            return(true);
        }