aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Region/CoreModules/Framework/EntityTransfer/EntityTransferStateMachine.cs148
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;
38using OpenSim.Framework.Client; 38using OpenSim.Framework.Client;
39using OpenSim.Region.Framework.Interfaces; 39using OpenSim.Region.Framework.Interfaces;
40using OpenSim.Region.Framework.Scenes; 40using OpenSim.Region.Framework.Scenes;
41using OpenSim.Region.Physics.Manager; 41using OpenSim.Region.PhysicsModules.SharedBase;
42using OpenSim.Services.Interfaces; 42using OpenSim.Services.Interfaces;
43using GridRegion = OpenSim.Services.Interfaces.GridRegion; 43using 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 }