diff options
Diffstat (limited to 'OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs')
-rw-r--r-- | OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs | 148 |
1 files changed, 118 insertions, 30 deletions
diff --git a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs index d0cab49..a3109e0 100644 --- a/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs +++ b/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs | |||
@@ -38,7 +38,7 @@ using OpenSim.Framework.Capabilities; | |||
38 | using OpenSim.Framework.Client; | 38 | using OpenSim.Framework.Client; |
39 | using OpenSim.Region.Framework.Interfaces; | 39 | using OpenSim.Region.Framework.Interfaces; |
40 | using OpenSim.Region.Framework.Scenes; | 40 | using OpenSim.Region.Framework.Scenes; |
41 | using OpenSim.Region.Physics.Manager; | 41 | using OpenSim.Region.PhysicsModules.SharedBase; |
42 | using OpenSim.Services.Interfaces; | 42 | using OpenSim.Services.Interfaces; |
43 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 43 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
44 | 44 | ||
@@ -51,10 +51,12 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
51 | /// This is a state machine. | 51 | /// This is a state machine. |
52 | /// | 52 | /// |
53 | /// [Entry] => Preparing | 53 | /// [Entry] => Preparing |
54 | /// Preparing => { Transferring || CleaningUp || [Exit] } | 54 | /// Preparing => { Transferring || Cancelling || CleaningUp || Aborting || [Exit] } |
55 | /// Transferring => { ReceivedAtDestination || CleaningUp } | 55 | /// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp || Aborting } |
56 | /// ReceivedAtDestination => CleaningUp | 56 | /// Cancelling => CleaningUp || Aborting |
57 | /// ReceivedAtDestination => CleaningUp || Aborting | ||
57 | /// CleaningUp => [Exit] | 58 | /// CleaningUp => [Exit] |
59 | /// Aborting => [Exit] | ||
58 | /// | 60 | /// |
59 | /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp | 61 | /// In other words, agents normally travel throwing Preparing => Transferring => ReceivedAtDestination => CleaningUp |
60 | /// However, any state can transition to CleaningUp if the teleport has failed. | 62 | /// However, any state can transition to CleaningUp if the teleport has failed. |
@@ -64,7 +66,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
64 | Preparing, // The agent is being prepared for transfer | 66 | Preparing, // The agent is being prepared for transfer |
65 | Transferring, // The agent is in the process of being transferred to a destination | 67 | Transferring, // The agent is in the process of being transferred to a destination |
66 | ReceivedAtDestination, // The destination has notified us that the agent has been successfully received | 68 | ReceivedAtDestination, // The destination has notified us that the agent has been successfully received |
67 | CleaningUp // The agent is being changed to child/removed after a transfer | 69 | CleaningUp, // The agent is being changed to child/removed after a transfer |
70 | Cancelling, // The user has cancelled the teleport but we have yet to act upon this. | ||
71 | Aborting // The transfer is aborting. Unlike Cancelling, no compensating actions should be performed | ||
68 | } | 72 | } |
69 | 73 | ||
70 | /// <summary> | 74 | /// <summary> |
@@ -73,6 +77,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
73 | public class EntityTransferStateMachine | 77 | public class EntityTransferStateMachine |
74 | { | 78 | { |
75 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 79 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
80 | private static readonly string LogHeader = "[ENTITY TRANSFER STATE MACHINE]"; | ||
76 | 81 | ||
77 | /// <summary> | 82 | /// <summary> |
78 | /// If true then on a teleport, the source region waits for a callback from the destination region. If | 83 | /// If true then on a teleport, the source region waits for a callback from the destination region. If |
@@ -96,6 +101,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
96 | /// <returns>true if the agent was not already in transit, false if it was</returns> | 101 | /// <returns>true if the agent was not already in transit, false if it was</returns> |
97 | internal bool SetInTransit(UUID id) | 102 | internal bool SetInTransit(UUID id) |
98 | { | 103 | { |
104 | m_log.DebugFormat("{0} SetInTransit. agent={1}, newState=Preparing", LogHeader, id); | ||
99 | lock (m_agentsInTransit) | 105 | lock (m_agentsInTransit) |
100 | { | 106 | { |
101 | if (!m_agentsInTransit.ContainsKey(id)) | 107 | if (!m_agentsInTransit.ContainsKey(id)) |
@@ -115,42 +121,117 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
115 | /// <param name='newState'></param> | 121 | /// <param name='newState'></param> |
116 | /// <returns></returns> | 122 | /// <returns></returns> |
117 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> | 123 | /// <exception cref='Exception'>Illegal transitions will throw an Exception</exception> |
118 | internal void UpdateInTransit(UUID id, AgentTransferState newState) | 124 | internal bool UpdateInTransit(UUID id, AgentTransferState newState) |
119 | { | 125 | { |
126 | m_log.DebugFormat("{0} UpdateInTransit. agent={1}, newState={2}", LogHeader, id, newState); | ||
127 | |||
128 | bool transitionOkay = false; | ||
129 | |||
130 | // We don't want to throw an exception on cancel since this can come it at any time. | ||
131 | bool failIfNotOkay = true; | ||
132 | |||
133 | // Should be a failure message if failure is not okay. | ||
134 | string failureMessage = null; | ||
135 | |||
136 | AgentTransferState? oldState = null; | ||
137 | |||
120 | lock (m_agentsInTransit) | 138 | lock (m_agentsInTransit) |
121 | { | 139 | { |
122 | // Illegal to try and update an agent that's not actually in transit. | 140 | // Illegal to try and update an agent that's not actually in transit. |
123 | if (!m_agentsInTransit.ContainsKey(id)) | 141 | if (!m_agentsInTransit.ContainsKey(id)) |
124 | throw new Exception( | 142 | { |
125 | string.Format( | 143 | if (newState != AgentTransferState.Cancelling && newState != AgentTransferState.Aborting) |
126 | "Agent with ID {0} is not registered as in transit in {1}", | 144 | failureMessage = string.Format( |
127 | id, m_mod.Scene.RegionInfo.RegionName)); | 145 | "Agent with ID {0} is not registered as in transit in {1}", |
128 | 146 | id, m_mod.Scene.RegionInfo.RegionName); | |
129 | AgentTransferState oldState = m_agentsInTransit[id]; | 147 | else |
148 | failIfNotOkay = false; | ||
149 | } | ||
150 | else | ||
151 | { | ||
152 | oldState = m_agentsInTransit[id]; | ||
130 | 153 | ||
131 | bool transitionOkay = false; | 154 | if (newState == AgentTransferState.Aborting) |
155 | { | ||
156 | transitionOkay = true; | ||
157 | } | ||
158 | else if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | ||
159 | { | ||
160 | transitionOkay = true; | ||
161 | } | ||
162 | else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) | ||
163 | { | ||
164 | transitionOkay = true; | ||
165 | } | ||
166 | else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) | ||
167 | { | ||
168 | transitionOkay = true; | ||
169 | } | ||
170 | else | ||
171 | { | ||
172 | if (newState == AgentTransferState.Cancelling | ||
173 | && (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring)) | ||
174 | { | ||
175 | transitionOkay = true; | ||
176 | } | ||
177 | else | ||
178 | { | ||
179 | failIfNotOkay = false; | ||
180 | } | ||
181 | } | ||
132 | 182 | ||
133 | if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp) | 183 | if (!transitionOkay) |
134 | transitionOkay = true; | 184 | failureMessage |
135 | else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing) | 185 | = string.Format( |
136 | transitionOkay = true; | 186 | "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", |
137 | else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring) | 187 | id, oldState, newState, m_mod.Scene.RegionInfo.RegionName); |
138 | transitionOkay = true; | 188 | } |
139 | 189 | ||
140 | if (transitionOkay) | 190 | if (transitionOkay) |
191 | { | ||
141 | m_agentsInTransit[id] = newState; | 192 | m_agentsInTransit[id] = newState; |
142 | else | 193 | |
143 | throw new Exception( | 194 | // m_log.DebugFormat( |
144 | string.Format( | 195 | // "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}", |
145 | "Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}", | 196 | // id, oldState, newState, m_mod.Scene.Name); |
146 | id, oldState, newState, m_mod.Scene.RegionInfo.RegionName)); | 197 | } |
198 | else if (failIfNotOkay) | ||
199 | { | ||
200 | m_log.DebugFormat("{0} UpdateInTransit. Throwing transition failure = {1}", LogHeader, failureMessage); | ||
201 | throw new Exception(failureMessage); | ||
202 | } | ||
203 | // else | ||
204 | // { | ||
205 | // if (oldState != null) | ||
206 | // m_log.DebugFormat( | ||
207 | // "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}", | ||
208 | // id, oldState, newState, m_mod.Scene.Name); | ||
209 | // else | ||
210 | // m_log.DebugFormat( | ||
211 | // "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit", | ||
212 | // id, newState, m_mod.Scene.Name); | ||
213 | // } | ||
147 | } | 214 | } |
215 | |||
216 | return transitionOkay; | ||
148 | } | 217 | } |
149 | 218 | ||
150 | internal bool IsInTransit(UUID id) | 219 | /// <summary> |
220 | /// Gets the current agent transfer state. | ||
221 | /// </summary> | ||
222 | /// <returns>Null if the agent is not in transit</returns> | ||
223 | /// <param name='id'> | ||
224 | /// Identifier. | ||
225 | /// </param> | ||
226 | internal AgentTransferState? GetAgentTransferState(UUID id) | ||
151 | { | 227 | { |
152 | lock (m_agentsInTransit) | 228 | lock (m_agentsInTransit) |
153 | return m_agentsInTransit.ContainsKey(id); | 229 | { |
230 | if (!m_agentsInTransit.ContainsKey(id)) | ||
231 | return null; | ||
232 | else | ||
233 | return m_agentsInTransit[id]; | ||
234 | } | ||
154 | } | 235 | } |
155 | 236 | ||
156 | /// <summary> | 237 | /// <summary> |
@@ -203,14 +284,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
203 | 284 | ||
204 | lock (m_agentsInTransit) | 285 | lock (m_agentsInTransit) |
205 | { | 286 | { |
206 | if (!IsInTransit(id)) | 287 | AgentTransferState? currentState = GetAgentTransferState(id); |
288 | |||
289 | if (currentState == null) | ||
207 | throw new Exception( | 290 | throw new Exception( |
208 | string.Format( | 291 | string.Format( |
209 | "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", | 292 | "Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit", |
210 | id, m_mod.Scene.RegionInfo.RegionName)); | 293 | id, m_mod.Scene.RegionInfo.RegionName)); |
211 | 294 | ||
212 | AgentTransferState currentState = m_agentsInTransit[id]; | ||
213 | |||
214 | if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) | 295 | if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination) |
215 | throw new Exception( | 296 | throw new Exception( |
216 | string.Format( | 297 | string.Format( |
@@ -222,8 +303,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer | |||
222 | 303 | ||
223 | // There should be no race condition here since no other code should be removing the agent transfer or | 304 | // There should be no race condition here since no other code should be removing the agent transfer or |
224 | // changing the state to another other than Transferring => ReceivedAtDestination. | 305 | // changing the state to another other than Transferring => ReceivedAtDestination. |
225 | while (m_agentsInTransit[id] != AgentTransferState.ReceivedAtDestination && count-- > 0) | 306 | |
307 | while (count-- > 0) | ||
226 | { | 308 | { |
309 | lock (m_agentsInTransit) | ||
310 | { | ||
311 | if (m_agentsInTransit[id] == AgentTransferState.ReceivedAtDestination) | ||
312 | break; | ||
313 | } | ||
314 | |||
227 | // m_log.Debug(" >>> Waiting... " + count); | 315 | // m_log.Debug(" >>> Waiting... " + count); |
228 | Thread.Sleep(100); | 316 | Thread.Sleep(100); |
229 | } | 317 | } |