LoadBalancerPlugin.cs 42 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094
  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. using System;
  28. using System.IO;
  29. using System.Net;
  30. using System.Xml;
  31. using System.Text;
  32. using System.Xml.Serialization;
  33. using System.Net.Sockets;
  34. using System.Collections;
  35. using System.Collections.Generic;
  36. using System.Diagnostics;
  37. using System.Threading;
  38. using OpenSim.Framework;
  39. using OpenSim.Framework.Console;
  40. using OpenSim.Framework.Servers;
  41. using OpenSim.Region.Environment;
  42. using OpenSim.Region.Environment.Scenes;
  43. using OpenSim.Region.ClientStack;
  44. using Nwc.XmlRpc;
  45. using Nini.Config;
  46. using Mono.Addins;
  47. using libsecondlife;
  48. using libsecondlife.Packets;
  49. [assembly:Addin]
  50. [assembly:AddinDependency ("OpenSim", "0.5")]
  51. [assembly:AddinDependency ("RegionProxy", "0.1")]
  52. namespace OpenSim.ApplicationPlugins.LoadBalancer
  53. {
  54. [Extension("/OpenSim/Startup")]
  55. public class LoadBalancerPlugin : IApplicationPlugin
  56. {
  57. private static readonly log4net.ILog m_log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
  58. private OpenSimMain simMain;
  59. private BaseHttpServer commandServer;
  60. private List<UDPServer> udpServers;
  61. private List<RegionInfo> regionData;
  62. private int proxyOffset;
  63. private string proxyURL;
  64. private SceneManager sceneManager;
  65. private string serializeDir;
  66. private TcpServer mTcpServer;
  67. public void Initialise(OpenSimMain openSim)
  68. {
  69. m_log.Info("[BALANCER] "+"Entering Initialize()");
  70. proxyURL = openSim.ConfigSource.Configs["Network"].GetString("proxy_url", "");
  71. if(proxyURL.Length==0) return;
  72. StartTcpServer();
  73. ClientView.SynchronizeClient = new ClientView.SynchronizeClientHandler(SynchronizePackets);
  74. AsynchronousSocketListener.PacketHandler = new AsynchronousSocketListener.PacketRecieveHandler(SynchronizePacketRecieve);
  75. this.sceneManager = openSim.SceneManager;
  76. this.udpServers = openSim.UdpServers;
  77. this.regionData = openSim.RegionData;
  78. this.simMain = openSim;
  79. this.commandServer = openSim.HttpServer;
  80. proxyOffset = Int32.Parse(openSim.ConfigSource.Configs["Network"].GetString("proxy_offset", "0"));
  81. serializeDir = openSim.ConfigSource.Configs["Network"].GetString("serialize_dir", "/tmp/");
  82. commandServer.AddXmlRPCHandler("SerializeRegion", SerializeRegion);
  83. commandServer.AddXmlRPCHandler("DeserializeRegion_Move", DeserializeRegion_Move);
  84. commandServer.AddXmlRPCHandler("DeserializeRegion_Clone", DeserializeRegion_Clone);
  85. commandServer.AddXmlRPCHandler("TerminateRegion", TerminateRegion);
  86. commandServer.AddXmlRPCHandler("SplitRegion", SplitRegion);
  87. commandServer.AddXmlRPCHandler("MergeRegions", MergeRegions);
  88. commandServer.AddXmlRPCHandler("UpdatePhysics", UpdatePhysics);
  89. commandServer.AddXmlRPCHandler("GetStatus", GetStatus);
  90. m_log.Info("[BALANCER] "+"Exiting Initialize()");
  91. }
  92. private void StartTcpServer()
  93. {
  94. Thread server_thread = new Thread(new ThreadStart(
  95. delegate {
  96. mTcpServer = new TcpServer(10001);
  97. mTcpServer.start();
  98. }));
  99. server_thread.Start();
  100. }
  101. public void Close()
  102. {
  103. }
  104. private XmlRpcResponse GetStatus(XmlRpcRequest request)
  105. {
  106. XmlRpcResponse response = new XmlRpcResponse();
  107. try
  108. {
  109. m_log.Info("[BALANCER] "+"Entering RegionStatus()");
  110. int src_port = (int)request.Params[0];
  111. Scene scene = null;
  112. // try to get the scene object
  113. RegionInfo src_region = SearchRegionFromPortNum(src_port);
  114. if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
  115. {
  116. m_log.Error("[BALANCER] "+"The Scene is not found");
  117. return response;
  118. }
  119. // serialization of client's informations
  120. List<ScenePresence> presences = scene.GetScenePresences();
  121. int get_scene_presence = presences.Count;
  122. int get_scene_presence_filter = 0;
  123. foreach (ScenePresence pre in presences)
  124. {
  125. ClientView client = (ClientView) pre.ControllingClient;
  126. //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true) {
  127. if(client.PacketProcessingEnabled==true) {
  128. get_scene_presence_filter++;
  129. }
  130. }
  131. List<ScenePresence> avatars = scene.GetAvatars();
  132. int get_avatar = avatars.Count;
  133. int get_avatar_filter = 0;
  134. string avatar_names = "";
  135. foreach (ScenePresence pre in avatars)
  136. {
  137. ClientView client = (ClientView) pre.ControllingClient;
  138. //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true) {
  139. if(client.PacketProcessingEnabled==true) {
  140. get_avatar_filter++;
  141. avatar_names += pre.Firstname + " " + pre.Lastname + "; ";
  142. }
  143. }
  144. Hashtable responseData = new Hashtable();
  145. responseData["get_scene_presence_filter"] = get_scene_presence_filter;
  146. responseData["get_scene_presence"] = get_scene_presence;
  147. responseData["get_avatar_filter"] = get_avatar_filter;
  148. responseData["get_avatar"] = get_avatar;
  149. responseData["avatar_names"] = avatar_names;
  150. response.Value = responseData;
  151. m_log.Info("[BALANCER] "+"Exiting RegionStatus()");
  152. }
  153. catch (Exception e)
  154. {
  155. m_log.Error("[BALANCER] "+e.ToString());
  156. m_log.Error("[BALANCER] "+e.StackTrace);
  157. }
  158. return response;
  159. }
  160. private XmlRpcResponse SerializeRegion(XmlRpcRequest request)
  161. {
  162. try
  163. {
  164. m_log.Info("[BALANCER] "+"Entering SerializeRegion()");
  165. string src_url = (string)request.Params[0];
  166. int src_port = (int)request.Params[1];
  167. SerializeRegion(src_url, src_port);
  168. m_log.Info("[BALANCER] "+"Exiting SerializeRegion()");
  169. }
  170. catch (Exception e)
  171. {
  172. m_log.Error("[BALANCER] "+e.ToString());
  173. m_log.Error("[BALANCER] "+e.StackTrace);
  174. }
  175. return new XmlRpcResponse();
  176. }
  177. private XmlRpcResponse DeserializeRegion_Move(XmlRpcRequest request)
  178. {
  179. try
  180. {
  181. m_log.Info("[BALANCER] "+"Entering DeserializeRegion_Move()");
  182. string src_url = (string)request.Params[0];
  183. int src_port = (int)request.Params[1];
  184. string dst_url = (string)request.Params[2];
  185. int dst_port = (int)request.Params[3];
  186. DeserializeRegion_Move(src_port, dst_port, src_url, dst_url);
  187. m_log.Info("[BALANCER] "+"Exiting DeserializeRegion_Move()");
  188. }
  189. catch (Exception e)
  190. {
  191. m_log.Error("[BALANCER] "+e.ToString());
  192. m_log.Error("[BALANCER] "+e.StackTrace);
  193. }
  194. return new XmlRpcResponse();
  195. }
  196. private XmlRpcResponse DeserializeRegion_Clone(XmlRpcRequest request)
  197. {
  198. try
  199. {
  200. m_log.Info("[BALANCER] "+"Entering DeserializeRegion_Clone()");
  201. string src_url = (string)request.Params[0];
  202. int src_port = (int)request.Params[1];
  203. string dst_url = (string)request.Params[2];
  204. int dst_port = (int)request.Params[3];
  205. DeserializeRegion_Clone(src_port, dst_port, src_url, dst_url);
  206. m_log.Info("[BALANCER] "+"Exiting DeserializeRegion_Clone()");
  207. }
  208. catch (Exception e)
  209. {
  210. m_log.Error("[BALANCER] "+e.ToString());
  211. m_log.Error("[BALANCER] "+e.StackTrace);
  212. throw e;
  213. }
  214. return new XmlRpcResponse();
  215. }
  216. private XmlRpcResponse TerminateRegion(XmlRpcRequest request)
  217. {
  218. try
  219. {
  220. m_log.Info("[BALANCER] "+"Entering TerminateRegion()");
  221. int src_port = (int)request.Params[0];
  222. // backgroud
  223. WaitCallback callback = new WaitCallback(TerminateRegion);
  224. ThreadPool.QueueUserWorkItem(callback, src_port);
  225. m_log.Info("[BALANCER] "+"Exiting TerminateRegion()");
  226. }
  227. catch (Exception e)
  228. {
  229. m_log.Error("[BALANCER] "+e.ToString());
  230. m_log.Error("[BALANCER] "+e.StackTrace);
  231. }
  232. return new XmlRpcResponse();
  233. }
  234. // internal functions
  235. private void SerializeRegion(string src_url, int src_port)
  236. {
  237. RegionInfo src_region = null;
  238. //------------------------------------------
  239. // Processing of origin region
  240. //------------------------------------------
  241. // search origin region
  242. src_region = SearchRegionFromPortNum(src_port);
  243. if (src_region == null)
  244. {
  245. m_log.Error("[BALANCER] "+"Region not found");
  246. return;
  247. }
  248. Util.XmlRpcCommand(src_region.proxyUrl, "BlockClientMessages", src_url, src_port + proxyOffset);
  249. // serialization of origin region's data
  250. SerializeRegion(src_region, serializeDir);
  251. }
  252. private void DeserializeRegion_Move(int src_port, int dst_port, string src_url, string dst_url)
  253. {
  254. RegionInfo dst_region = null;
  255. //------------------------------------------
  256. // Processing of destination region
  257. //------------------------------------------
  258. // import the source region's data
  259. dst_region = DeserializeRegion(dst_port, true, serializeDir);
  260. Util.XmlRpcCommand(dst_region.proxyUrl, "ChangeRegion", src_port + proxyOffset, src_url, dst_port + proxyOffset, dst_url);
  261. Util.XmlRpcCommand(dst_region.proxyUrl, "UnblockClientMessages", dst_url, dst_port + proxyOffset);
  262. }
  263. private void DeserializeRegion_Clone(int src_port, int dst_port, string src_url, string dst_url)
  264. {
  265. RegionInfo dst_region = null;
  266. //------------------------------------------
  267. // Processing of destination region
  268. //------------------------------------------
  269. // import the source region's data
  270. dst_region = DeserializeRegion(dst_port, false, serializeDir);
  271. // Decide who is in charge for each section
  272. int[] port = new int[] { src_port, dst_port };
  273. string[] url = new string[] { "http://" + src_url + ":" + commandServer.Port, "http://" + dst_url + ":" + commandServer.Port };
  274. for(int i=0; i<2; i++) Util.XmlRpcCommand(url[i], "SplitRegion", i, 2, port[0], port[1], url[0], url[1]);
  275. // Enable the proxy
  276. Util.XmlRpcCommand(dst_region.proxyUrl, "AddRegion", src_port + proxyOffset, src_url, dst_port + proxyOffset, dst_url);
  277. Util.XmlRpcCommand(dst_region.proxyUrl, "UnblockClientMessages", dst_url, dst_port + proxyOffset);
  278. }
  279. private void TerminateRegion(object param)
  280. {
  281. RegionInfo src_region = null;
  282. int src_port = (int)param;
  283. //------------------------------------------
  284. // Processing of remove region
  285. //------------------------------------------
  286. // search origin region
  287. src_region = SearchRegionFromPortNum(src_port);
  288. if (src_region == null)
  289. {
  290. m_log.Error("[BALANCER] "+"Region not found");
  291. return;
  292. }
  293. isSplit = false;
  294. // remove client resources
  295. RemoveAllClientResource(src_region);
  296. // remove old region
  297. RemoveRegion(src_region.RegionID, src_region.InternalEndPoint.Port);
  298. m_log.Info("[BALANCER] "+"Region terminated");
  299. }
  300. private RegionInfo SearchRegionFromPortNum(int portnum)
  301. {
  302. RegionInfo result = null;
  303. foreach (RegionInfo rinfo in regionData)
  304. {
  305. if (rinfo.InternalEndPoint.Port == portnum)
  306. {
  307. // m_log.Info("BALANCER",
  308. // "Region found. Internal Port = {0}, Handle={1}",
  309. // rinfo.InternalEndPoint.Port, rinfo.RegionHandle);
  310. result = rinfo;
  311. break;
  312. }
  313. }
  314. return result;
  315. }
  316. private UDPServer SearchUDPServerFromPortNum(int portnum)
  317. {
  318. return udpServers.Find( delegate(UDPServer server) { return (portnum + proxyOffset == ((IPEndPoint) server.Server.LocalEndPoint).Port); });
  319. }
  320. private void SerializeRegion(RegionInfo src_region, string export_dir)
  321. {
  322. Scene scene = null;
  323. List<ScenePresence> presences;
  324. string filename;
  325. int i = 0;
  326. // try to get the scene object
  327. if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
  328. {
  329. m_log.Error("[BALANCER] "+"The Scene is not found");
  330. return;
  331. }
  332. // create export directory
  333. DirectoryInfo dirinfo = new DirectoryInfo(export_dir);
  334. if (!dirinfo.Exists)
  335. {
  336. dirinfo.Create();
  337. }
  338. // serialization of client's informations
  339. presences = scene.GetScenePresences();
  340. foreach (ScenePresence pre in presences)
  341. {
  342. SerializeClient(i, scene, pre, export_dir);
  343. i++;
  344. }
  345. // serialization of region data
  346. SearializableRegionInfo dst_region = new SearializableRegionInfo(src_region);
  347. filename = export_dir + "RegionInfo_" + src_region.RegionID.ToString() + ".bin";
  348. Util.SerializeToFile(filename, dst_region);
  349. // backup current scene's entities
  350. //scene.Backup();
  351. m_log.InfoFormat("[BALANCER] "+"region serialization completed [{0}]",
  352. src_region.RegionID.ToString());
  353. }
  354. private void SerializeClient(int idx, Scene scene, ScenePresence pre, string export_dir)
  355. {
  356. string filename;
  357. IClientAPI controller = null;
  358. m_log.InfoFormat("[BALANCER] "+"agent id : {0}", pre.UUID);
  359. uint[] circuits = scene.ClientManager.GetAllCircuits(pre.UUID);
  360. foreach (uint code in circuits)
  361. {
  362. m_log.InfoFormat("[BALANCER] "+"circuit code : {0}", code);
  363. if (scene.ClientManager.TryGetClient(code, out controller))
  364. {
  365. ClientInfo info = controller.GetClientInfo();
  366. filename = export_dir + "ClientInfo-" + String.Format("{0:0000}", idx) + "_" + controller.CircuitCode.ToString() + ".bin";
  367. Util.SerializeToFile(filename, info);
  368. m_log.InfoFormat("[BALANCER] "+"client info serialized [filename={0}]", filename);
  369. }
  370. }
  371. //filename = export_dir + "Presence_" + controller.AgentId.ToString() + ".bin";
  372. filename = export_dir + "Presence_" + String.Format("{0:0000}", idx) + ".bin";
  373. Util.SerializeToFile(filename, pre);
  374. m_log.InfoFormat("[BALANCER] "+"scene presence serialized [filename={0}]", filename);
  375. }
  376. private RegionInfo DeserializeRegion(int dst_port, bool move_flag, string import_dir)
  377. {
  378. string[] files = null;
  379. RegionInfo dst_region = null;
  380. try
  381. {
  382. // deserialization of region data
  383. files = Directory.GetFiles(import_dir, "RegionInfo_*.bin");
  384. foreach (string filename in files)
  385. {
  386. m_log.InfoFormat("[BALANCER] RegionInfo filename = [{0}]", filename);
  387. dst_region = new RegionInfo((SearializableRegionInfo)Util.DeserializeFromFile(filename));
  388. m_log.InfoFormat("[BALANCER] "+"RegionID = [{0}]", dst_region.RegionID.ToString());
  389. m_log.InfoFormat("[BALANCER] "+"RegionHandle = [{0}]", dst_region.RegionHandle);
  390. m_log.InfoFormat("[BALANCER] "+"ProxyUrl = [{0}]", dst_region.proxyUrl);
  391. m_log.InfoFormat("[BALANCER] "+"OriginRegionID = [{0}]", dst_region.originRegionID.ToString());
  392. CreateCloneRegion(dst_region, dst_port, true);
  393. File.Delete(filename);
  394. m_log.InfoFormat("[BALANCER] "+"region deserialized [{0}]", dst_region.RegionID);
  395. }
  396. // deserialization of client data
  397. DeserializeClient(dst_region, import_dir);
  398. m_log.InfoFormat("[BALANCER] "+"region deserialization completed [{0}]",
  399. dst_region.ToString());
  400. }
  401. catch (Exception e)
  402. {
  403. m_log.Error("[BALANCER] "+e.ToString());
  404. m_log.Error("[BALANCER] "+e.StackTrace);
  405. throw e;
  406. }
  407. return dst_region;
  408. }
  409. private void DeserializeClient(RegionInfo dst_region, string import_dir)
  410. {
  411. ScenePresence sp = null;
  412. ClientInfo data = null;
  413. Scene scene = null;
  414. string[] files = null;
  415. IClientAPI controller = null;
  416. UDPServer udpserv = null;
  417. if (sceneManager.TryGetScene(dst_region.RegionID, out scene))
  418. {
  419. // search udpserver
  420. udpserv = SearchUDPServerFromPortNum(scene.RegionInfo.InternalEndPoint.Port);
  421. // restore the scene presence
  422. for (int i = 0; ; i++)
  423. {
  424. string filename = import_dir + "Presence_" + String.Format("{0:0000}", i) + ".bin";
  425. if (!File.Exists(filename))
  426. {
  427. break;
  428. }
  429. sp = (ScenePresence)Util.DeserializeFromFile(filename);
  430. Console.WriteLine("agent id = {0}", sp.UUID);
  431. scene.m_restorePresences.Add(sp.UUID, sp);
  432. File.Delete(filename);
  433. m_log.InfoFormat("[BALANCER] " + "scene presence deserialized [{0}]", sp.UUID);
  434. // restore the ClientView
  435. files = Directory.GetFiles(import_dir, "ClientInfo-" + String.Format("{0:0000}", i) + "_*.bin");
  436. foreach (string fname in files)
  437. {
  438. int start = fname.IndexOf('_');
  439. int end = fname.LastIndexOf('.');
  440. uint circuit_code = uint.Parse(fname.Substring(start + 1, end - start - 1));
  441. m_log.InfoFormat("[BALANCER] " + "client circuit code = {0}", circuit_code);
  442. data = (ClientInfo)Util.DeserializeFromFile(fname);
  443. AgentCircuitData agentdata = new AgentCircuitData(data.agentcircuit);
  444. scene.AuthenticateHandler.AddNewCircuit(circuit_code, agentdata);
  445. udpserv.RestoreClient(agentdata, data.userEP, data.proxyEP);
  446. // waiting for the scene-presense restored
  447. lock (scene.m_restorePresences)
  448. {
  449. Monitor.Wait(scene.m_restorePresences, 3000);
  450. }
  451. if (scene.ClientManager.TryGetClient(circuit_code, out controller))
  452. {
  453. m_log.InfoFormat("[BALANCER] " + "get client [{0}]", circuit_code);
  454. controller.SetClientInfo(data);
  455. }
  456. File.Delete(fname);
  457. m_log.InfoFormat("[BALANCER] " + "client info deserialized [{0}]", circuit_code);
  458. }
  459. // backup new scene's entities
  460. //scene.Backup();
  461. }
  462. }
  463. }
  464. private void CreateCloneRegion(RegionInfo dst_region, int dst_port, bool createID_flag)
  465. {
  466. if (createID_flag)
  467. {
  468. dst_region.RegionID = LLUUID.Random();
  469. }
  470. // change RegionInfo (memory only)
  471. dst_region.InternalEndPoint.Port = dst_port;
  472. dst_region.ExternalHostName = proxyURL.Split(new char[] { '/', ':' })[3];
  473. // Create new region
  474. simMain.CreateRegion(dst_region, false);
  475. }
  476. private void RemoveRegion(LLUUID regionID, int port)
  477. {
  478. Scene killScene;
  479. if (sceneManager.TryGetScene(regionID, out killScene))
  480. {
  481. Console.WriteLine("scene found.");
  482. if ((sceneManager.CurrentScene != null)
  483. && (sceneManager.CurrentScene.RegionInfo.RegionID == killScene.RegionInfo.RegionID))
  484. {
  485. sceneManager.TrySetCurrentScene("..");
  486. }
  487. m_log.Info("Removing region : " + killScene.RegionInfo.RegionName);
  488. regionData.Remove(killScene.RegionInfo);
  489. sceneManager.CloseScene(killScene);
  490. }
  491. // Shutting down the UDP server
  492. UDPServer udpsvr = SearchUDPServerFromPortNum(port);
  493. if (udpsvr != null)
  494. {
  495. udpsvr.Server.Close();
  496. udpServers.Remove(udpsvr);
  497. }
  498. }
  499. private void RemoveAllClientResource(RegionInfo src_region)
  500. {
  501. Scene scene = null;
  502. List<ScenePresence> presences;
  503. IClientAPI controller = null;
  504. // try to get the scene object
  505. if (sceneManager.TryGetScene(src_region.RegionID, out scene) == false)
  506. {
  507. m_log.Error("[BALANCER] "+"The Scene is not found");
  508. return;
  509. }
  510. // serialization of client's informations
  511. presences = scene.GetScenePresences();
  512. // remove all scene presences
  513. foreach (ScenePresence pre in presences)
  514. {
  515. uint[] circuits = scene.ClientManager.GetAllCircuits(pre.UUID);
  516. foreach (uint code in circuits)
  517. {
  518. m_log.InfoFormat("[BALANCER] "+"circuit code : {0}", code);
  519. if (scene.ClientManager.TryGetClient(code, out controller))
  520. {
  521. // stopping clientview thread
  522. if (((ClientView)controller).PacketProcessingEnabled)
  523. {
  524. controller.Stop();
  525. ((ClientView)controller).PacketProcessingEnabled = false;
  526. }
  527. // teminateing clientview thread
  528. controller.Terminate();
  529. m_log.Info("[BALANCER] "+"client thread stopped");
  530. }
  531. }
  532. // remove scene presence
  533. scene.RemoveClient(pre.UUID);
  534. }
  535. }
  536. /*
  537. * This section implements scene splitting and synchronization
  538. */
  539. private bool[] isLocalNeighbour;
  540. private string[] sceneURL;
  541. private int[] regionPortList;
  542. private TcpClient[] tcpClientList;
  543. private bool isSplit = false;
  544. private XmlRpcResponse SplitRegion(XmlRpcRequest request)
  545. {
  546. try
  547. {
  548. int myID = (int) request.Params[0];
  549. int numRegions = (int) request.Params[1];
  550. regionPortList = new int[numRegions];
  551. sceneURL = new string[numRegions];
  552. tcpClientList = new TcpClient[numRegions];
  553. for(int i=0; i<numRegions; i++)
  554. {
  555. regionPortList[i]=(int) request.Params[i+2];
  556. sceneURL[i]=(string) request.Params[i+2+numRegions];
  557. }
  558. string hostname;
  559. for(int i=0; i<numRegions; i++)
  560. {
  561. hostname = sceneURL[i].Split(new char[] { '/', ':' })[3];
  562. m_log.InfoFormat("[SPLITSCENE] "+"creating tcp client host:{0}", hostname);
  563. tcpClientList[i] = new TcpClient(hostname, 10001);
  564. }
  565. bool isMaster = (myID == 0);
  566. isLocalNeighbour = new bool[numRegions];
  567. for(int i=0; i<numRegions; i++) isLocalNeighbour[i] = (sceneURL[i] == sceneURL[myID]);
  568. RegionInfo region = SearchRegionFromPortNum(regionPortList[myID]);
  569. //Console.WriteLine("\n === SplitRegion {0}\n", region.RegionID);
  570. Scene scene;
  571. if (sceneManager.TryGetScene(region.RegionID, out scene))
  572. {
  573. // Disable event updates, backups etc in the slave(s)
  574. if (isMaster) {
  575. scene.Region_Status = RegionStatus.Up;
  576. }
  577. else
  578. {
  579. scene.Region_Status = RegionStatus.SlaveScene;
  580. }
  581. //Console.WriteLine("=== SplitRegion {0}: Scene found, status {1}", region.RegionID, scene.Region_Status);
  582. // Disabling half of the avatars in master, and the other half in slave
  583. int i = 0;
  584. List<uint> circuits = scene.ClientManager.GetAllCircuitCodes();
  585. circuits.Sort();
  586. IClientAPI controller = null;
  587. foreach (uint code in circuits)
  588. {
  589. m_log.InfoFormat("[BALANCER] "+"circuit code : {0}", code);
  590. if (scene.ClientManager.TryGetClient(code, out controller))
  591. {
  592. // Divide the presences evenly over the set of subscenes
  593. ClientView client = (ClientView) controller;
  594. client.PacketProcessingEnabled = (( (i + myID) % sceneURL.Length) == 0);
  595. m_log.InfoFormat("[SPLITSCENE] === SplitRegion {0}: SP.PacketEnabled {1}", region.RegionID, client.PacketProcessingEnabled);
  596. if (!client.PacketProcessingEnabled)
  597. {
  598. // stopping clientview thread
  599. client.Stop();
  600. }
  601. ++i;
  602. }
  603. }
  604. scene.splitID = myID;
  605. scene.SynchronizeScene = new Scene.SynchronizeSceneHandler(SynchronizeScenes);
  606. isSplit = true;
  607. }
  608. else
  609. {
  610. m_log.Error("[SPLITSCENE] "+String.Format("Scene not found {0}", region.RegionID));
  611. }
  612. }
  613. catch (Exception e)
  614. {
  615. m_log.Error("[SPLITSCENE] "+e.ToString());
  616. m_log.Error("[SPLITSCENE] "+e.StackTrace);
  617. }
  618. return new XmlRpcResponse();
  619. }
  620. private XmlRpcResponse MergeRegions(XmlRpcRequest request)
  621. {
  622. // This should only be called for the master scene
  623. try
  624. {
  625. m_log.Info("[BALANCER] "+"Entering MergeRegions()");
  626. string src_url = (string) request.Params[0];
  627. int src_port = (int) request.Params[1];
  628. RegionInfo region = SearchRegionFromPortNum(src_port);
  629. Util.XmlRpcCommand(region.proxyUrl, "BlockClientMessages", src_url, src_port + proxyOffset);
  630. Scene scene;
  631. if (sceneManager.TryGetScene(region.RegionID, out scene))
  632. {
  633. isSplit = false;
  634. scene.SynchronizeScene = null;
  635. scene.Region_Status = RegionStatus.Up;
  636. List<ScenePresence> presences = scene.GetScenePresences();
  637. foreach (ScenePresence pre in presences)
  638. {
  639. ClientView client = (ClientView) pre.ControllingClient;
  640. if (!client.PacketProcessingEnabled)
  641. {
  642. client.Restart();
  643. client.PacketProcessingEnabled = true;
  644. }
  645. }
  646. }
  647. // Delete the slave scenes
  648. for(int i=1; i<sceneURL.Length; i++)
  649. {
  650. string url = (sceneURL[i].Split('/')[2]).Split(':')[0]; // get URL part from EP
  651. Util.XmlRpcCommand(region.proxyUrl, "DeleteRegion", regionPortList[i] + proxyOffset, url);
  652. Thread.Sleep(1000);
  653. Util.XmlRpcCommand(sceneURL[i], "TerminateRegion", regionPortList[i]); // TODO: need + proxyOffset?
  654. }
  655. Util.XmlRpcCommand(region.proxyUrl, "UnblockClientMessages", src_url, src_port + proxyOffset);
  656. }
  657. catch (Exception e)
  658. {
  659. m_log.Error("[BALANCER] "+e.ToString());
  660. m_log.Error("[BALANCER] "+e.StackTrace);
  661. throw e;
  662. }
  663. return new XmlRpcResponse();
  664. }
  665. private XmlRpcResponse UpdatePhysics(XmlRpcRequest request)
  666. {
  667. // this callback receives physic scene updates from the other sub-scenes (in split mode)
  668. int regionPort = (int) request.Params[0];
  669. LLUUID scenePresenceID = new LLUUID((byte[]) request.Params[1], 0);
  670. LLVector3 position = new LLVector3((byte[]) request.Params[2], 0);
  671. LLVector3 velocity = new LLVector3((byte[]) request.Params[3], 0);
  672. bool flying = (bool) request.Params[4];
  673. LocalUpdatePhysics(regionPort, scenePresenceID, position, velocity, flying);
  674. return new XmlRpcResponse();
  675. }
  676. private void LocalUpdatePhysics(int regionPort, LLUUID scenePresenceID, LLVector3 position, LLVector3 velocity, bool flying)
  677. {
  678. //m_log.Info("[SPLITSCENE] "+String.Format("UpdatePhysics called {0}", regionID));
  679. //m_log.Info("[SPLITSCENE] "+"LocalUpdatePhysics [region port:{0}, client:{1}, position:{2}, velocity:{3}, flying:{4}]",
  680. // regionPort, scenePresenceID.ToString(), position.ToString(),
  681. // velocity.ToString(), flying);
  682. RegionInfo region = SearchRegionFromPortNum(regionPort);
  683. // Find and update the scene precense
  684. Scene scene;
  685. if (sceneManager.TryGetScene(region.RegionID, out scene))
  686. {
  687. ScenePresence pre = scene.GetScenePresences().Find(delegate(ScenePresence x) { return x.UUID == scenePresenceID; });
  688. if (pre == null)
  689. {
  690. m_log.ErrorFormat("[SPLITSCENE] [LocalUpdatePhysics] ScenePresence is missing... ({0})", scenePresenceID.ToString());
  691. return;
  692. }
  693. // m_log.Info("[SPLITSCENE] "+"LocalUpdatePhysics [region:{0}, client:{1}]",
  694. // regionID.ToString(), pre.UUID.ToString());
  695. pre.AbsolutePosition = position;// will set PhysicsActor.Position
  696. pre.Velocity = velocity; // will set PhysicsActor.Velocity
  697. pre.PhysicsActor.Flying = flying;
  698. }
  699. }
  700. object padlock=new object();
  701. private void SynchronizeScenes(Scene scene)
  702. {
  703. if (!isSplit)
  704. {
  705. return;
  706. }
  707. lock(padlock)
  708. {
  709. // Callback activated after a physics scene update
  710. // int i = 0;
  711. List<ScenePresence> presences = scene.GetScenePresences();
  712. foreach (ScenePresence pre in presences)
  713. {
  714. ClientView client = (ClientView) pre.ControllingClient;
  715. // Because data changes by the physics simulation when the client doesn't move,
  716. // if MovementFlag is false, It is necessary to synchronize.
  717. //if(pre.MovementFlag!=0 && client.PacketProcessingEnabled==true)
  718. if(client.PacketProcessingEnabled==true)
  719. {
  720. //m_log.Info("[SPLITSCENE] "+String.Format("Client moving in {0} {1}", scene.RegionInfo.RegionID, pre.AbsolutePosition));
  721. for (int i = 0; i < sceneURL.Length; i++)
  722. {
  723. if (i == scene.splitID)
  724. {
  725. continue;
  726. }
  727. if(isLocalNeighbour[i])
  728. {
  729. //m_log.Info("[SPLITSCENE] "+"Synchronize ScenePresence (Local) [region:{0}=>{1}, client:{2}]",
  730. // scene.RegionInfo.RegionID, regionPortList[i], pre.UUID.ToString());
  731. LocalUpdatePhysics(regionPortList[i], pre.UUID, pre.AbsolutePosition, pre.Velocity, pre.PhysicsActor.Flying);
  732. }
  733. else
  734. {
  735. //m_log.Info("[SPLITSCENE] "+"Synchronize ScenePresence (Remote) [region port:{0}, client:{1}, position:{2}, velocity:{3}, flying:{4}]",
  736. // regionPortList[i], pre.UUID.ToString(), pre.AbsolutePosition.ToString(),
  737. // pre.Velocity.ToString(), pre.PhysicsActor.Flying);
  738. Util.XmlRpcCommand(sceneURL[i], "UpdatePhysics",
  739. regionPortList[i], pre.UUID.GetBytes(),
  740. pre.AbsolutePosition.GetBytes(), pre.Velocity.GetBytes(),
  741. pre.PhysicsActor.Flying);
  742. /*
  743. byte[] buff = new byte[12+12+1];
  744. Buffer.BlockCopy(pre.AbsolutePosition.GetBytes(), 0, buff, 0, 12);
  745. Buffer.BlockCopy(pre.Velocity.GetBytes(), 0, buff, 12, 12);
  746. buff[24] = (byte)((pre.PhysicsActor.Flying)?1:0);
  747. // create header
  748. InternalPacketHeader header = new InternalPacketHeader();
  749. header.type = 1;
  750. header.throttlePacketType = 0;
  751. header.numbytes = buff.Length;
  752. header.agent_id = pre.UUID.UUID;
  753. header.region_port = regionPortList[i];
  754. //Send
  755. tcpClientList[i].send(header, buff);
  756. */
  757. }
  758. }
  759. }
  760. // ++i;
  761. }
  762. }
  763. }
  764. public bool SynchronizePackets(IScene scene, Packet packet, LLUUID agentID, ThrottleOutPacketType throttlePacketType)
  765. {
  766. if (!isSplit)
  767. {
  768. return false;
  769. }
  770. Scene localScene = (Scene)scene;
  771. for (int i = 0; i < sceneURL.Length; i++)
  772. {
  773. if (i == localScene.splitID)
  774. {
  775. continue;
  776. }
  777. if(isLocalNeighbour[i])
  778. {
  779. //m_log.Info("[SPLITSCENE] "+"Synchronize Packet (Local) [type:{0}, client:{1}]",
  780. // packet.Type.ToString(), agentID.ToString());
  781. LocalUpdatePacket(regionPortList[i], agentID, packet, throttlePacketType);
  782. }
  783. else
  784. {
  785. //m_log.Info("[SPLITSCENE] "+"Synchronize Packet (Remote) [type:{0}, client:{1}]",
  786. // packet.Type.ToString(), agentID.ToString());
  787. // to bytes
  788. byte[] buff = packet.ToBytes();
  789. // create header
  790. InternalPacketHeader header = new InternalPacketHeader();
  791. header.type = 0;
  792. header.throttlePacketType = (int)throttlePacketType;
  793. header.numbytes = buff.Length;
  794. header.agent_id = agentID.UUID;
  795. header.region_port = regionPortList[i];
  796. //Send
  797. tcpClientList[i].send(header, buff);
  798. PacketPool.Instance.ReturnPacket(packet);
  799. }
  800. }
  801. return true;
  802. }
  803. private void LocalUpdatePacket(int regionPort, LLUUID agentID, Packet packet, ThrottleOutPacketType throttlePacketType)
  804. {
  805. Scene scene;
  806. RegionInfo region = SearchRegionFromPortNum(regionPort);
  807. // m_log.Info("[SPLITSCENE] "+"LocalUpdatePacket [region port:{0}, client:{1}, packet type:{2}]",
  808. // regionPort, agentID.ToString(), packet.GetType().ToString());
  809. if (sceneManager.TryGetScene(region.RegionID, out scene))
  810. {
  811. ScenePresence pre = scene.GetScenePresences().Find(delegate(ScenePresence x) { return x.UUID == agentID; });
  812. if (pre == null)
  813. {
  814. m_log.ErrorFormat("[SPLITSCENE] [LocalUpdatePacket] ScenePresence is missing... ({0})", agentID.ToString());
  815. return;
  816. }
  817. if (((ClientView)pre.ControllingClient).PacketProcessingEnabled==true)
  818. {
  819. pre.ControllingClient.OutPacket(packet, throttlePacketType);
  820. }
  821. else
  822. {
  823. PacketPool.Instance.ReturnPacket(packet);
  824. }
  825. }
  826. }
  827. public void SynchronizePacketRecieve(InternalPacketHeader header, byte[] buff)
  828. {
  829. // m_log.Info("[SPLITSCENE] "+"entering SynchronizePacketRecieve[type={0}]", header.type);
  830. if (!isSplit)
  831. {
  832. return;
  833. }
  834. switch (header.type)
  835. {
  836. case 0:
  837. Packet packet = null;
  838. byte[] zero = new byte[3000];
  839. int packetEnd = 0;
  840. // deserialize packet
  841. packetEnd = buff.Length - 1;
  842. // packetEnd = buff.Length;
  843. try
  844. {
  845. //m_log.Info("[SPLITSCENE] "+"PacketPool.Instance : {0}", (PacketPool.Instance == null)?"null":"not null");
  846. //m_log.Info("[SPLITSCENE] "+"buff length={0}", buff.Length);
  847. packet = PacketPool.Instance.GetPacket(buff, ref packetEnd, zero);
  848. LocalUpdatePacket(header.region_port, new LLUUID(header.agent_id),
  849. packet, (ThrottleOutPacketType)header.throttlePacketType);
  850. }
  851. catch (Exception e)
  852. {
  853. m_log.Error("[SPLITSCENE] "+e.ToString());
  854. m_log.Error("[SPLITSCENE] "+e.StackTrace);
  855. }
  856. break;
  857. case 1:
  858. int regionPort = header.region_port;
  859. LLUUID scenePresenceID = new LLUUID(header.agent_id);
  860. LLVector3 position = new LLVector3(buff, 0);
  861. LLVector3 velocity = new LLVector3(buff, 12);
  862. bool flying = ((buff[24] == (byte)1)?true:false);
  863. LocalUpdatePhysics(regionPort, scenePresenceID, position, velocity, flying);
  864. break;
  865. default:
  866. m_log.Info("[SPLITSCENE] "+"Invalid type");
  867. break;
  868. }
  869. // m_log.Info("[SPLITSCENE] "+"exiting SynchronizePacketRecieve");
  870. }
  871. }
  872. }