aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs1101
1 files changed, 1101 insertions, 0 deletions
diff --git a/ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs b/ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs
new file mode 100644
index 0000000..6812777
--- /dev/null
+++ b/ThirdParty/3Di/LoadBalancer/LoadBalancerPlugin.cs
@@ -0,0 +1,1101 @@
1/*
2* Copyright (c) Contributors, http://opensimulator.org/
3* See CONTRIBUTORS.TXT for a full list of copyright holders.
4*
5* Redistribution and use in source and binary forms, with or without
6* modification, are permitted provided that the following conditions are met:
7* * Redistributions of source code must retain the above copyright
8* notice, this list of conditions and the following disclaimer.
9* * Redistributions in binary form must reproduce the above copyright
10* notice, this list of conditions and the following disclaimer in the
11* documentation and/or other materials provided with the distribution.
12* * Neither the name of the OpenSim Project nor the
13* names of its contributors may be used to endorse or promote products
14* derived from this software without specific prior written permission.
15*
16* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
17* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
20* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*
27*/
28
29using System;
30using System.IO;
31using System.Net;
32using System.Xml;
33using System.Text;
34using System.Xml.Serialization;
35using System.Net.Sockets;
36using System.Collections;
37using System.Collections.Generic;
38using System.Diagnostics;
39using System.Threading;
40
41using OpenSim.Framework;
42using OpenSim.Framework.Console;
43using OpenSim.Framework.Servers;
44using OpenSim.Region.Environment;
45using OpenSim.Region.Environment.Scenes;
46using OpenSim.Region.ClientStack;
47
48using Nwc.XmlRpc;
49using Nini.Config;
50
51using Mono.Addins;
52
53using libsecondlife;
54using libsecondlife.Packets;
55
56[assembly:Addin]
57[assembly:AddinDependency ("OpenSim", "0.5")]
58
59namespace OpenSim.ApplicationPlugins.LoadBalancer
60{
61 [Extension("/OpenSim/Startup")]
62 public class LoadBalancerPlugin : IApplicationPlugin
63 {
64 private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
65
66 private OpenSimMain simMain;
67 private BaseHttpServer commandServer;
68
69 private List<UDPServer> udpServers;
70 private List<RegionInfo> regionData;
71
72 private int proxyOffset;
73 private string proxyURL;
74 private SceneManager sceneManager;
75 private string serializeDir;
76
77 private TcpServer mTcpServer;
78 private TcpClient mTcpClient;
79
80 public void Initialise(OpenSimMain openSim)
81 {
82 m_log.Info("[BALANCER] "+"Entering Initialize()");
83
84 StartTcpServer();
85 ClientView.SynchronizeClient = new ClientView.SynchronizeClientHandler(SynchronizePackets);
86 AsynchronousSocketListener.PacketHandler = new AsynchronousSocketListener.PacketRecieveHandler(SynchronizePacketRecieve);
87
88 this.sceneManager = openSim.SceneManager;
89 this.udpServers = openSim.UdpServers;
90 this.regionData = openSim.RegionData;
91 this.simMain = openSim;
92 this.commandServer = openSim.HttpServer;
93
94 proxyOffset = Int32.Parse(openSim.ConfigSource.Configs["Network"].GetString("proxy_offset", "0"));
95 proxyURL = openSim.ConfigSource.Configs["Network"].GetString("proxy_url", "");
96 if(proxyURL.Length==0) return;
97
98 serializeDir = openSim.ConfigSource.Configs["Network"].GetString("serialize_dir", "/tmp/");
99
100 commandServer.AddXmlRPCHandler("SerializeRegion", SerializeRegion);
101 commandServer.AddXmlRPCHandler("DeserializeRegion_Move", DeserializeRegion_Move);
102 commandServer.AddXmlRPCHandler("DeserializeRegion_Clone", DeserializeRegion_Clone);
103 commandServer.AddXmlRPCHandler("TerminateRegion", TerminateRegion);
104
105 commandServer.AddXmlRPCHandler("SplitRegion", SplitRegion);
106 commandServer.AddXmlRPCHandler("MergeRegions", MergeRegions);
107 commandServer.AddXmlRPCHandler("UpdatePhysics", UpdatePhysics);
108 commandServer.AddXmlRPCHandler("GetStatus", GetStatus);
109
110 m_log.Info("[BALANCER] "+"Exiting Initialize()");
111 }
112
113 private void StartTcpServer()
114 {
115 Thread server_thread = new Thread(new ThreadStart(
116 delegate {
117 mTcpServer = new TcpServer(10001);
118 mTcpServer.start();
119 }));
120 server_thread.Start();
121 }
122
123 public void Close()
124 {
125 }
126
127 private XmlRpcResponse GetStatus(XmlRpcRequest request)
128 {
129 XmlRpcResponse response = new XmlRpcResponse();
130 try
131 {
132 m_log.Info("[BALANCER] "+"Entering RegionStatus()");
133
134 int src_port = (int)request.Params[0];
135 Scene scene = null;
136 // try to get the scene object
137 RegionInfo src_region = SearchRegionFromPortNum(src_port);
138 if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
139 {
140 m_log.Error("[BALANCER] "+"The Scene is not found");
141 return response;
142 }
143 // serialization of client's informations
144 List<ScenePresence> presences = scene.GetScenePresences();
145 int get_scene_presence = presences.Count;
146 int get_scene_presence_filter = 0;
147 foreach (ScenePresence pre in presences)
148 {
149 ClientView client = (ClientView) pre.ControllingClient;
150 //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true) {
151 if(client.PacketProcessingEnabled==true) {
152 get_scene_presence_filter++;
153 }
154 }
155 List<ScenePresence> avatars = scene.GetAvatars();
156 int get_avatar = avatars.Count;
157 int get_avatar_filter = 0;
158 string avatar_names = "";
159 foreach (ScenePresence pre in avatars)
160 {
161 ClientView client = (ClientView) pre.ControllingClient;
162 //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true) {
163 if(client.PacketProcessingEnabled==true) {
164 get_avatar_filter++;
165 avatar_names += pre.Firstname + " " + pre.Lastname + "; ";
166 }
167 }
168
169 Hashtable responseData = new Hashtable();
170 responseData["get_scene_presence_filter"] = get_scene_presence_filter;
171 responseData["get_scene_presence"] = get_scene_presence;
172 responseData["get_avatar_filter"] = get_avatar_filter;
173 responseData["get_avatar"] = get_avatar;
174 responseData["avatar_names"] = avatar_names;
175 response.Value = responseData;
176
177 m_log.Info("[BALANCER] "+"Exiting RegionStatus()");
178 }
179 catch (Exception e)
180 {
181 m_log.Error("[BALANCER] "+e.ToString());
182 m_log.Error("[BALANCER] "+e.StackTrace);
183 }
184 return response;
185 }
186
187 private XmlRpcResponse SerializeRegion(XmlRpcRequest request)
188 {
189 try
190 {
191 m_log.Info("[BALANCER] "+"Entering SerializeRegion()");
192
193 string src_url = (string)request.Params[0];
194 int src_port = (int)request.Params[1];
195
196 SerializeRegion(src_url, src_port);
197
198 m_log.Info("[BALANCER] "+"Exiting SerializeRegion()");
199 }
200 catch (Exception e)
201 {
202 m_log.Error("[BALANCER] "+e.ToString());
203 m_log.Error("[BALANCER] "+e.StackTrace);
204 }
205
206 return new XmlRpcResponse();
207 }
208
209 private XmlRpcResponse DeserializeRegion_Move(XmlRpcRequest request)
210 {
211 try
212 {
213 m_log.Info("[BALANCER] "+"Entering DeserializeRegion_Move()");
214
215 string src_url = (string)request.Params[0];
216 int src_port = (int)request.Params[1];
217 string dst_url = (string)request.Params[2];
218 int dst_port = (int)request.Params[3];
219
220 DeserializeRegion_Move(src_port, dst_port, src_url, dst_url);
221
222 m_log.Info("[BALANCER] "+"Exiting DeserializeRegion_Move()");
223 }
224 catch (Exception e)
225 {
226 m_log.Error("[BALANCER] "+e.ToString());
227 m_log.Error("[BALANCER] "+e.StackTrace);
228 }
229
230 return new XmlRpcResponse();
231 }
232
233 private XmlRpcResponse DeserializeRegion_Clone(XmlRpcRequest request)
234 {
235 try
236 {
237 m_log.Info("[BALANCER] "+"Entering DeserializeRegion_Clone()");
238
239 string src_url = (string)request.Params[0];
240 int src_port = (int)request.Params[1];
241 string dst_url = (string)request.Params[2];
242 int dst_port = (int)request.Params[3];
243
244 DeserializeRegion_Clone(src_port, dst_port, src_url, dst_url);
245
246 m_log.Info("[BALANCER] "+"Exiting DeserializeRegion_Clone()");
247 }
248 catch (Exception e)
249 {
250 m_log.Error("[BALANCER] "+e.ToString());
251 m_log.Error("[BALANCER] "+e.StackTrace);
252 throw e;
253 }
254
255 return new XmlRpcResponse();
256 }
257
258 private XmlRpcResponse TerminateRegion(XmlRpcRequest request)
259 {
260 try
261 {
262 m_log.Info("[BALANCER] "+"Entering TerminateRegion()");
263
264 int src_port = (int)request.Params[0];
265
266 // backgroud
267 WaitCallback callback = new WaitCallback(TerminateRegion);
268 ThreadPool.QueueUserWorkItem(callback, src_port);
269
270 m_log.Info("[BALANCER] "+"Exiting TerminateRegion()");
271 }
272 catch (Exception e)
273 {
274 m_log.Error("[BALANCER] "+e.ToString());
275 m_log.Error("[BALANCER] "+e.StackTrace);
276 }
277
278 return new XmlRpcResponse();
279 }
280
281 // internal functions
282
283 private void SerializeRegion(string src_url, int src_port)
284 {
285 RegionInfo src_region = null;
286
287 //------------------------------------------
288 // Processing of origin region
289 //------------------------------------------
290
291 // search origin region
292 src_region = SearchRegionFromPortNum(src_port);
293
294 if (src_region == null)
295 {
296 m_log.Error("[BALANCER] "+"Region not found");
297 return;
298 }
299
300 simMain.ProxyCommand(src_region.proxyUrl, "BlockClientMessages", src_url, src_port + proxyOffset);
301
302 // serialization of origin region's data
303 SerializeRegion(src_region, serializeDir);
304 }
305
306 private void DeserializeRegion_Move(int src_port, int dst_port, string src_url, string dst_url)
307 {
308 RegionInfo dst_region = null;
309
310 //------------------------------------------
311 // Processing of destination region
312 //------------------------------------------
313
314 // import the source region's data
315 dst_region = DeserializeRegion(dst_port, true, serializeDir);
316
317 simMain.ProxyCommand(dst_region.proxyUrl, "ChangeRegion", src_port + proxyOffset, src_url, dst_port + proxyOffset, dst_url);
318 simMain.ProxyCommand(dst_region.proxyUrl, "UnblockClientMessages", dst_url, dst_port + proxyOffset);
319 }
320
321 private void DeserializeRegion_Clone(int src_port, int dst_port, string src_url, string dst_url)
322 {
323 RegionInfo dst_region = null;
324
325 //------------------------------------------
326 // Processing of destination region
327 //------------------------------------------
328
329 // import the source region's data
330 dst_region = DeserializeRegion(dst_port, false, serializeDir);
331
332 // Decide who is in charge for each section
333 int[] port = new int[] { src_port, dst_port };
334 string[] url = new string[] { "http://" + src_url + ":" + commandServer.Port, "http://" + dst_url + ":" + commandServer.Port };
335 for(int i=0; i<2; i++) simMain.XmlRpcCommand(url[i], "SplitRegion", i, 2, port[0], port[1], url[0], url[1]);
336
337 // Enable the proxy
338 simMain.ProxyCommand(dst_region.proxyUrl, "AddRegion", src_port + proxyOffset, src_url, dst_port + proxyOffset, dst_url);
339 simMain.ProxyCommand(dst_region.proxyUrl, "UnblockClientMessages", dst_url, dst_port + proxyOffset);
340 }
341
342 private void TerminateRegion(object param)
343 {
344 RegionInfo src_region = null;
345 int src_port = (int)param;
346
347 //------------------------------------------
348 // Processing of remove region
349 //------------------------------------------
350
351 // search origin region
352 src_region = SearchRegionFromPortNum(src_port);
353
354 if (src_region == null)
355 {
356 m_log.Error("[BALANCER] "+"Region not found");
357 return;
358 }
359
360 isSplit = false;
361
362 // remove client resources
363 RemoveAllClientResource(src_region);
364 // remove old region
365 RemoveRegion(src_region.RegionID, src_region.InternalEndPoint.Port);
366
367 m_log.Info("[BALANCER] "+"Region terminated");
368 }
369
370 private RegionInfo SearchRegionFromPortNum(int portnum)
371 {
372 RegionInfo result = null;
373
374 foreach (RegionInfo rinfo in regionData)
375 {
376 if (rinfo.InternalEndPoint.Port == portnum)
377 {
378// m_log.Info("BALANCER",
379// "Region found. Internal Port = {0}, Handle={1}",
380// rinfo.InternalEndPoint.Port, rinfo.RegionHandle);
381 result = rinfo;
382 break;
383 }
384 }
385
386 return result;
387 }
388
389 private UDPServer SearchUDPServerFromPortNum(int portnum)
390 {
391 return udpServers.Find( delegate(UDPServer server) { return (portnum + proxyOffset == ((IPEndPoint) server.Server.LocalEndPoint).Port); });
392 }
393
394 private void SerializeRegion(RegionInfo src_region, string export_dir)
395 {
396 Scene scene = null;
397 List<ScenePresence> presences;
398 string filename;
399 int i = 0;
400
401 // try to get the scene object
402 if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
403 {
404 m_log.Error("[BALANCER] "+"The Scene is not found");
405 return;
406 }
407
408 // create export directory
409 DirectoryInfo dirinfo = new DirectoryInfo(export_dir);
410 if (!dirinfo.Exists)
411 {
412 dirinfo.Create();
413 }
414
415 // serialization of client's informations
416 presences = scene.GetScenePresences();
417
418 foreach (ScenePresence pre in presences)
419 {
420 SerializeClient(i, scene, pre, export_dir);
421 i++;
422 }
423
424 // serialization of region data
425 SearializableRegionInfo dst_region = new SearializableRegionInfo(src_region);
426
427 filename = export_dir + "RegionInfo_" + src_region.RegionID.ToString() + ".bin";
428 Util.SerializeToFile(filename, dst_region);
429
430 // backup current scene's entities
431 //scene.Backup();
432
433 m_log.InfoFormat("[BALANCER] "+"region serialization completed [{0}]",
434 src_region.RegionID.ToString());
435 }
436
437 private void SerializeClient(int idx, Scene scene, ScenePresence pre, string export_dir)
438 {
439 string filename;
440 IClientAPI controller = null;
441
442 m_log.InfoFormat("[BALANCER] "+"agent id : {0}", pre.m_uuid);
443
444 uint[] circuits = scene.ClientManager.GetAllCircuits(pre.m_uuid);
445
446 foreach (uint code in circuits)
447 {
448 m_log.InfoFormat("[BALANCER] "+"circuit code : {0}", code);
449
450 if (scene.ClientManager.TryGetClient(code, out controller))
451 {
452 ClientInfo info = controller.GetClientInfo();
453
454 filename = export_dir + "ClientInfo-" + String.Format("{0:0000}", idx) + "_" + controller.CircuitCode.ToString() + ".bin";
455
456 Util.SerializeToFile(filename, info);
457
458 m_log.InfoFormat("[BALANCER] "+"client info serialized [filename={0}]", filename);
459 }
460 }
461
462 //filename = export_dir + "Presence_" + controller.AgentId.ToString() + ".bin";
463 filename = export_dir + "Presence_" + String.Format("{0:0000}", idx) + ".bin";
464
465 Util.SerializeToFile(filename, pre);
466
467 m_log.InfoFormat("[BALANCER] "+"scene presence serialized [filename={0}]", filename);
468 }
469
470 private RegionInfo DeserializeRegion(int dst_port, bool move_flag, string import_dir)
471 {
472 string[] files = null;
473 RegionInfo dst_region = null;
474
475 try
476 {
477 // deserialization of region data
478 files = Directory.GetFiles(import_dir, "RegionInfo_*.bin");
479
480 foreach (string filename in files)
481 {
482 m_log.InfoFormat("[BALANCER] RegionInfo filename = [{0}]", filename);
483
484 dst_region = new RegionInfo((SearializableRegionInfo)Util.DeserializeFromFile(filename));
485
486 m_log.InfoFormat("[BALANCER] "+"RegionID = [{0}]", dst_region.RegionID.ToString());
487 m_log.InfoFormat("[BALANCER] "+"RegionHandle = [{0}]", dst_region.RegionHandle);
488 m_log.InfoFormat("[BALANCER] "+"ProxyUrl = [{0}]", dst_region.proxyUrl);
489 m_log.InfoFormat("[BALANCER] "+"OriginRegionID = [{0}]", dst_region.originRegionID.ToString());
490
491 CreateCloneRegion(dst_region, dst_port, true);
492
493 File.Delete(filename);
494
495 m_log.InfoFormat("[BALANCER] "+"region deserialized [{0}]", dst_region.RegionID);
496 }
497
498 // deserialization of client data
499 DeserializeClient(dst_region, import_dir);
500
501 m_log.InfoFormat("[BALANCER] "+"region deserialization completed [{0}]",
502 dst_region.ToString());
503 }
504 catch (Exception e)
505 {
506 m_log.Error("[BALANCER] "+e.ToString());
507 m_log.Error("[BALANCER] "+e.StackTrace);
508 throw e;
509 }
510
511 return dst_region;
512 }
513
514 private void DeserializeClient(RegionInfo dst_region, string import_dir)
515 {
516 ScenePresence sp = null;
517 ClientInfo data = null;
518 Scene scene = null;
519 string[] files = null;
520 IClientAPI controller = null;
521 UDPServer udpserv = null;
522
523 if (sceneManager.TryGetScene(dst_region.RegionID, out scene))
524 {
525 // search udpserver
526 udpserv = SearchUDPServerFromPortNum(scene.RegionInfo.InternalEndPoint.Port);
527
528 // restore the scene presence
529/*
530 files = Directory.GetFiles(import_dir, "Presence_*.bin");
531 Array.Sort(files);
532
533 foreach (string filename in files)
534 {
535 sp = (ScenePresence)Util.DeserializeFromFile(filename);
536 Console.WriteLine("agent id = {0}", sp.m_uuid);
537
538 scene.m_restorePresences.Add(sp.m_uuid, sp);
539 File.Delete(filename);
540
541 m_log.InfoFormat("[BALANCER] "+"scene presence deserialized [{0}]", sp.m_uuid);
542 }
543*/
544 for (int i = 0; ; i++)
545 {
546 string filename = import_dir + "Presence_" + String.Format("{0:0000}", i) + ".bin";
547
548 if (!File.Exists(filename))
549 {
550 break;
551 }
552
553 sp = (ScenePresence)Util.DeserializeFromFile(filename);
554 Console.WriteLine("agent id = {0}", sp.m_uuid);
555
556 scene.m_restorePresences.Add(sp.m_uuid, sp);
557 File.Delete(filename);
558
559 m_log.InfoFormat("[BALANCER] " + "scene presence deserialized [{0}]", sp.m_uuid);
560
561 // restore the ClientView
562
563 files = Directory.GetFiles(import_dir, "ClientInfo-" + String.Format("{0:0000}", i) + "_*.bin");
564
565 foreach (string fname in files)
566 {
567 int start = fname.IndexOf('_');
568 int end = fname.LastIndexOf('.');
569 uint circuit_code = uint.Parse(fname.Substring(start + 1, end - start - 1));
570 m_log.InfoFormat("[BALANCER] " + "client circuit code = {0}", circuit_code);
571
572 data = (ClientInfo)Util.DeserializeFromFile(fname);
573
574 AgentCircuitData agentdata = new AgentCircuitData(data.agentcircuit);
575 scene.AuthenticateHandler.AddNewCircuit(circuit_code, agentdata);
576
577 udpserv.RestoreClient(agentdata, data.userEP, data.proxyEP);
578
579 // waiting for the scene-presense restored
580 lock (scene.m_restorePresences)
581 {
582 Monitor.Wait(scene.m_restorePresences, 3000);
583 }
584
585 if (scene.ClientManager.TryGetClient(circuit_code, out controller))
586 {
587 m_log.InfoFormat("[BALANCER] " + "get client [{0}]", circuit_code);
588 controller.SetClientInfo(data);
589 }
590
591 File.Delete(fname);
592
593 m_log.InfoFormat("[BALANCER] " + "client info deserialized [{0}]", circuit_code);
594 }
595
596 // backup new scene's entities
597 //scene.Backup();
598 }
599 }
600 }
601
602 private void CreateCloneRegion(RegionInfo dst_region, int dst_port, bool createID_flag)
603 {
604 if (createID_flag)
605 {
606 dst_region.RegionID = LLUUID.Random();
607 }
608
609 // change RegionInfo (memory only)
610 dst_region.InternalEndPoint.Port = dst_port;
611 dst_region.ExternalHostName = proxyURL.Split(new char[] { '/', ':' })[3];
612
613 // Create new region
614 simMain.CreateRegion(dst_region, false);
615 }
616
617 private void RemoveRegion(LLUUID regionID, int port)
618 {
619 Scene killScene;
620 if (sceneManager.TryGetScene(regionID, out killScene))
621 {
622 Console.WriteLine("scene found.");
623
624 if ((sceneManager.CurrentScene != null)
625 && (sceneManager.CurrentScene.RegionInfo.RegionID == killScene.RegionInfo.RegionID))
626 {
627 sceneManager.TrySetCurrentScene("..");
628 }
629
630 m_log.Info("Removing region : " + killScene.RegionInfo.RegionName);
631 regionData.Remove(killScene.RegionInfo);
632 sceneManager.CloseScene(killScene);
633 }
634
635 // Shutting down the UDP server
636 UDPServer udpsvr = SearchUDPServerFromPortNum(port);
637
638 if (udpsvr != null)
639 {
640 udpsvr.Server.Close();
641 udpServers.Remove(udpsvr);
642 }
643 }
644
645 private void RemoveAllClientResource(RegionInfo src_region)
646 {
647 Scene scene = null;
648 List<ScenePresence> presences;
649 IClientAPI controller = null;
650
651 // try to get the scene object
652 if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
653 {
654 m_log.Error("[BALANCER] "+"The Scene is not found");
655 return;
656 }
657
658 // serialization of client's informations
659 presences = scene.GetScenePresences();
660
661 // remove all scene presences
662 foreach (ScenePresence pre in presences)
663 {
664 uint[] circuits = scene.ClientManager.GetAllCircuits(pre.m_uuid);
665
666 foreach (uint code in circuits)
667 {
668 m_log.InfoFormat("[BALANCER] "+"circuit code : {0}", code);
669
670 if (scene.ClientManager.TryGetClient(code, out controller))
671 {
672 // stopping clientview thread
673 if (((ClientView)controller).PacketProcessingEnabled)
674 {
675 controller.Stop();
676 ((ClientView)controller).PacketProcessingEnabled = false;
677 }
678 // teminateing clientview thread
679 controller.Terminate();
680 m_log.Info("[BALANCER] "+"client thread stopped");
681 }
682 }
683
684 // remove scene presence
685 scene.RemoveClient(pre.m_uuid);
686 }
687 }
688
689 /*
690 * This section implements scene splitting and synchronization
691 */
692
693 private bool[] isLocalNeighbour;
694 private string[] sceneURL;
695 private int[] regionPortList;
696 private TcpClient[] tcpClientList;
697 private bool isSplit = false;
698
699 private XmlRpcResponse SplitRegion(XmlRpcRequest request)
700 {
701 try
702 {
703 int myID = (int) request.Params[0];
704 int numRegions = (int) request.Params[1];
705 regionPortList = new int[numRegions];
706 sceneURL = new string[numRegions];
707 tcpClientList = new TcpClient[numRegions];
708
709 for(int i=0; i<numRegions; i++)
710 {
711 regionPortList[i]=(int) request.Params[i+2];
712 sceneURL[i]=(string) request.Params[i+2+numRegions];
713 }
714
715 string hostname;
716
717 for(int i=0; i<numRegions; i++)
718 {
719 hostname = sceneURL[i].Split(new char[] { '/', ':' })[3];
720 m_log.InfoFormat("[SPLITSCENE] "+"creating tcp client host:{0}", hostname);
721 tcpClientList[i] = new TcpClient(hostname, 10001);
722 }
723
724 bool isMaster = (myID == 0);
725
726 isLocalNeighbour = new bool[numRegions];
727 for(int i=0; i<numRegions; i++) isLocalNeighbour[i] = (sceneURL[i] == sceneURL[myID]);
728
729 RegionInfo region = SearchRegionFromPortNum(regionPortList[myID]);
730
731 //Console.WriteLine("\n === SplitRegion {0}\n", region.RegionID);
732
733 Scene scene;
734 if (sceneManager.TryGetScene(region.RegionID, out scene))
735 {
736 // Disable event updates, backups etc in the slave(s)
737 if (isMaster) {
738 scene.Region_Status = RegionStatus.Up;
739 }
740 else
741 {
742 scene.Region_Status = RegionStatus.SlaveScene;
743 }
744
745 //Console.WriteLine("=== SplitRegion {0}: Scene found, status {1}", region.RegionID, scene.Region_Status);
746
747 // Disabling half of the avatars in master, and the other half in slave
748
749 int i = 0;
750 List<ScenePresence> presences = scene.GetScenePresences();
751presences.Sort();
752 foreach (ScenePresence pre in presences)
753 {
754 // Divide the presences evenly over the set of subscenes
755 ClientView client = (ClientView) pre.ControllingClient;
756 client.PacketProcessingEnabled = (( (i + myID) % sceneURL.Length) == 0);
757
758 m_log.InfoFormat("[SPLITSCENE] === SplitRegion {0}: SP.PacketEnabled {1}", region.RegionID, client.PacketProcessingEnabled);
759
760 if (!client.PacketProcessingEnabled)
761 {
762 // stopping clientview thread
763 client.Stop();
764 }
765
766 ++i;
767 }
768
769 scene.splitID = myID;
770 scene.SynchronizeScene = new Scene.SynchronizeSceneHandler(SynchronizeScenes);
771 isSplit = true;
772 }
773 else
774 {
775 m_log.Error("[SPLITSCENE] "+String.Format("Scene not found {0}", region.RegionID));
776 }
777 }
778 catch (Exception e)
779 {
780 m_log.Error("[SPLITSCENE] "+e.ToString());
781 m_log.Error("[SPLITSCENE] "+e.StackTrace);
782 }
783
784 return new XmlRpcResponse();
785 }
786
787 private XmlRpcResponse MergeRegions(XmlRpcRequest request)
788 {
789 // This should only be called for the master scene
790 try
791 {
792 m_log.Info("[BALANCER] "+"Entering MergeRegions()");
793
794 string src_url = (string) request.Params[0];
795 int src_port = (int) request.Params[1];
796
797 RegionInfo region = SearchRegionFromPortNum(src_port);
798
799 simMain.ProxyCommand(region.proxyUrl, "BlockClientMessages", src_url, src_port + proxyOffset);
800
801 Scene scene;
802 if (sceneManager.TryGetScene(region.RegionID, out scene))
803 {
804 isSplit = false;
805
806 scene.SynchronizeScene = null;
807 scene.Region_Status = RegionStatus.Up;
808
809 List<ScenePresence> presences = scene.GetScenePresences();
810 foreach (ScenePresence pre in presences)
811 {
812 ClientView client = (ClientView) pre.ControllingClient;
813 if (!client.PacketProcessingEnabled)
814 {
815 client.Restart();
816 client.PacketProcessingEnabled = true;
817 }
818 }
819 }
820
821 // Delete the slave scenes
822 for(int i=1; i<sceneURL.Length; i++)
823 {
824 string url = (sceneURL[i].Split('/')[2]).Split(':')[0]; // get URL part from EP
825 simMain.ProxyCommand(region.proxyUrl, "DeleteRegion", regionPortList[i] + proxyOffset, url);
826 Thread.Sleep(1000);
827 simMain.XmlRpcCommand(sceneURL[i], "TerminateRegion", regionPortList[i]); // TODO: need + proxyOffset?
828 }
829
830 simMain.ProxyCommand(region.proxyUrl, "UnblockClientMessages", src_url, src_port + proxyOffset);
831 }
832 catch (Exception e)
833 {
834 m_log.Error("[BALANCER] "+e.ToString());
835 m_log.Error("[BALANCER] "+e.StackTrace);
836 throw e;
837 }
838
839 return new XmlRpcResponse();
840 }
841
842 private XmlRpcResponse UpdatePhysics(XmlRpcRequest request)
843 {
844 // this callback receives physic scene updates from the other sub-scenes (in split mode)
845
846 int regionPort = (int) request.Params[0];
847 LLUUID scenePresenceID = new LLUUID((byte[]) request.Params[1], 0);
848 LLVector3 position = new LLVector3((byte[]) request.Params[2], 0);
849 LLVector3 velocity = new LLVector3((byte[]) request.Params[3], 0);
850 bool flying = (bool) request.Params[4];
851
852 LocalUpdatePhysics(regionPort, scenePresenceID, position, velocity, flying);
853
854 return new XmlRpcResponse();
855 }
856
857 private void LocalUpdatePhysics(int regionPort, LLUUID scenePresenceID, LLVector3 position, LLVector3 velocity, bool flying)
858 {
859 //m_log.Info("[SPLITSCENE] "+String.Format("UpdatePhysics called {0}", regionID));
860
861 //m_log.Info("[SPLITSCENE] "+"LocalUpdatePhysics [region port:{0}, client:{1}, position:{2}, velocity:{3}, flying:{4}]",
862 // regionPort, scenePresenceID.ToString(), position.ToString(),
863 // velocity.ToString(), flying);
864
865 RegionInfo region = SearchRegionFromPortNum(regionPort);
866
867 // Find and update the scene precense
868 Scene scene;
869 if (sceneManager.TryGetScene(region.RegionID, out scene))
870 {
871 ScenePresence pre = scene.GetScenePresences().Find(delegate(ScenePresence x) { return x.UUID == scenePresenceID; });
872
873 if (pre == null)
874 {
875 m_log.ErrorFormat("[SPLITSCENE] [LocalUpdatePhysics] ScenePresence is missing... ({0})", scenePresenceID.ToString());
876 return;
877 }
878
879// m_log.Info("[SPLITSCENE] "+"LocalUpdatePhysics [region:{0}, client:{1}]",
880// regionID.ToString(), pre.UUID.ToString());
881
882 pre.AbsolutePosition = position;// will set PhysicsActor.Position
883 pre.Velocity = velocity; // will set PhysicsActor.Velocity
884 pre.PhysicsActor.Flying = flying;
885 }
886 }
887
888 object padlock=new object();
889 private void SynchronizeScenes(Scene scene)
890 {
891 if (!isSplit)
892 {
893 return;
894 }
895
896 lock(padlock)
897 {
898 // Callback activated after a physics scene update
899// int i = 0;
900 List<ScenePresence> presences = scene.GetScenePresences();
901 foreach (ScenePresence pre in presences)
902 {
903 ClientView client = (ClientView) pre.ControllingClient;
904
905 // Because data changes by the physics simulation when the client doesn't move,
906 // if MovementFlag is false, It is necessary to synchronize.
907 //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true)
908 if(client.PacketProcessingEnabled==true)
909 {
910 //m_log.Info("[SPLITSCENE] "+String.Format("Client moving in {0} {1}", scene.RegionInfo.RegionID, pre.AbsolutePosition));
911
912 for (int i = 0; i < sceneURL.Length; i++)
913 {
914 if (i == scene.splitID)
915 {
916 continue;
917 }
918
919 if(isLocalNeighbour[i])
920 {
921 //m_log.Info("[SPLITSCENE] "+"Synchronize ScenePresence (Local) [region:{0}=>{1}, client:{2}]",
922 // scene.RegionInfo.RegionID, regionPortList[i], pre.UUID.ToString());
923 LocalUpdatePhysics(regionPortList[i], pre.UUID, pre.AbsolutePosition, pre.Velocity, pre.PhysicsActor.Flying);
924 }
925 else
926 {
927 //m_log.Info("[SPLITSCENE] "+"Synchronize ScenePresence (Remote) [region port:{0}, client:{1}, position:{2}, velocity:{3}, flying:{4}]",
928 // regionPortList[i], pre.UUID.ToString(), pre.AbsolutePosition.ToString(),
929 // pre.Velocity.ToString(), pre.PhysicsActor.Flying);
930
931
932 simMain.XmlRpcCommand(sceneURL[i], "UpdatePhysics",
933 regionPortList[i], pre.UUID.GetBytes(),
934 pre.AbsolutePosition.GetBytes(), pre.Velocity.GetBytes(),
935 pre.PhysicsActor.Flying);
936
937/*
938 byte[] buff = new byte[12+12+1];
939
940 Buffer.BlockCopy(pre.AbsolutePosition.GetBytes(), 0, buff, 0, 12);
941 Buffer.BlockCopy(pre.Velocity.GetBytes(), 0, buff, 12, 12);
942 buff[24] = (byte)((pre.PhysicsActor.Flying)?1:0);
943
944 // create header
945 InternalPacketHeader header = new InternalPacketHeader();
946
947 header.type = 1;
948 header.throttlePacketType = 0;
949 header.numbytes = buff.Length;
950 header.agent_id = pre.UUID.UUID;
951 header.region_port = regionPortList[i];
952
953 //Send
954 tcpClientList[i].send(header, buff);
955*/
956 }
957 }
958 }
959// ++i;
960 }
961 }
962 }
963
964 public bool SynchronizePackets(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType)
965 {
966 if (!isSplit)
967 {
968 return false;
969 }
970
971 Scene localScene = (Scene)scene;
972
973 for (int i = 0; i < sceneURL.Length; i++)
974 {
975 if (i == localScene.splitID)
976 {
977 continue;
978 }
979
980 if(isLocalNeighbour[i])
981 {
982 //m_log.Info("[SPLITSCENE] "+"Synchronize Packet (Local) [type:{0}, client:{1}]",
983 // packet.Type.ToString(), agentID.ToString());
984 LocalUpdatePacket(regionPortList[i], agentID, packet, throttlePacketType);
985 }
986 else
987 {
988 //m_log.Info("[SPLITSCENE] "+"Synchronize Packet (Remote) [type:{0}, client:{1}]",
989 // packet.Type.ToString(), agentID.ToString());
990 // to bytes
991 byte[] buff = packet.ToBytes();
992
993 // create header
994 InternalPacketHeader header = new InternalPacketHeader();
995
996 header.type = 0;
997 header.throttlePacketType = (int)throttlePacketType;
998 header.numbytes = buff.Length;
999 header.agent_id = agentID.UUID;
1000 header.region_port = regionPortList[i];
1001
1002 //Send
1003 tcpClientList[i].send(header, buff);
1004
1005 PacketPool.Instance.ReturnPacket(packet);
1006 }
1007 }
1008
1009 return true;
1010 }
1011
1012 private void LocalUpdatePacket(int regionPort, LLUUID agentID, Packet packet, ThrottleOutPacketType throttlePacketType)
1013 {
1014 Scene scene;
1015
1016 RegionInfo region = SearchRegionFromPortNum(regionPort);
1017
1018// m_log.Info("[SPLITSCENE] "+"LocalUpdatePacket [region port:{0}, client:{1}, packet type:{2}]",
1019// regionPort, agentID.ToString(), packet.GetType().ToString());
1020
1021 if (sceneManager.TryGetScene(region.RegionID, out scene))
1022 {
1023 ScenePresence pre = scene.GetScenePresences().Find(delegate(ScenePresence x) { return x.UUID == agentID; });
1024
1025 if (pre == null)
1026 {
1027 m_log.ErrorFormat("[SPLITSCENE] [LocalUpdatePacket] ScenePresence is missing... ({0})", agentID.ToString());
1028 return;
1029 }
1030
1031 if (((ClientView)pre.ControllingClient).PacketProcessingEnabled==true)
1032 {
1033 pre.ControllingClient.OutPacket(packet, throttlePacketType);
1034 }
1035 else
1036 {
1037 PacketPool.Instance.ReturnPacket(packet);
1038 }
1039 }
1040 }
1041
1042 public void SynchronizePacketRecieve(InternalPacketHeader header, byte[] buff)
1043 {
1044// m_log.Info("[SPLITSCENE] "+"entering SynchronizePacketRecieve[type={0}]", header.type);
1045
1046 if (!isSplit)
1047 {
1048 return;
1049 }
1050
1051 switch (header.type)
1052 {
1053 case 0:
1054
1055 Packet packet = null;
1056 byte[] zero = new byte[3000];
1057 int packetEnd = 0;
1058
1059 // deserialize packet
1060 packetEnd = buff.Length - 1;
1061// packetEnd = buff.Length;
1062
1063 try
1064 {
1065 //m_log.Info("[SPLITSCENE] "+"PacketPool.Instance : {0}", (PacketPool.Instance == null)?"null":"not null");
1066 //m_log.Info("[SPLITSCENE] "+"buff length={0}", buff.Length);
1067
1068 packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero);
1069
1070 LocalUpdatePacket(header.region_port, new LLUUID(header.agent_id),
1071 packet, (ThrottleOutPacketType)header.throttlePacketType);
1072 }
1073 catch (Exception e)
1074 {
1075 m_log.Error("[SPLITSCENE] "+e.ToString());
1076 m_log.Error("[SPLITSCENE] "+e.StackTrace);
1077 }
1078
1079 break;
1080
1081 case 1:
1082
1083 int regionPort = header.region_port;
1084 LLUUID scenePresenceID = new LLUUID(header.agent_id);
1085 LLVector3 position = new LLVector3(buff, 0);
1086 LLVector3 velocity = new LLVector3(buff, 12);
1087 bool flying = ((buff[24] == (byte)1)?true:false);
1088
1089 LocalUpdatePhysics(regionPort, scenePresenceID, position, velocity, flying);
1090
1091 break;
1092
1093 default:
1094 m_log.Info("[SPLITSCENE] "+"Invalid type");
1095 break;
1096 }
1097
1098// m_log.Info("[SPLITSCENE] "+"exiting SynchronizePacketRecieve");
1099 }
1100 }
1101}