aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Framework
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Framework')
-rw-r--r--OpenSim/Framework/Animation.cs19
-rw-r--r--OpenSim/Framework/BlockingQueue.cs36
-rw-r--r--OpenSim/Framework/CachedTextureEventArg.cs46
-rw-r--r--OpenSim/Framework/ChildAgentDataUpdate.cs20
-rw-r--r--OpenSim/Framework/ClientInfo.cs11
-rw-r--r--OpenSim/Framework/Console/ConsoleUtil.cs47
-rw-r--r--OpenSim/Framework/Console/LocalConsole.cs15
-rw-r--r--OpenSim/Framework/Console/RemoteConsole.cs2
-rw-r--r--OpenSim/Framework/DAMap.cs295
-rw-r--r--OpenSim/Framework/DOMap.cs8
-rw-r--r--OpenSim/Framework/EstateSettings.cs1
-rw-r--r--OpenSim/Framework/IClientAPI.cs11
-rw-r--r--OpenSim/Framework/IPeople.cs47
-rw-r--r--OpenSim/Framework/IScene.cs7
-rw-r--r--OpenSim/Framework/Location.cs16
-rw-r--r--OpenSim/Framework/Monitoring/BaseStatsCollector.cs14
-rw-r--r--OpenSim/Framework/Monitoring/Checks/Check.cs118
-rw-r--r--OpenSim/Framework/Monitoring/ChecksManager.cs262
-rw-r--r--OpenSim/Framework/Monitoring/MemoryWatchdog.cs8
-rw-r--r--OpenSim/Framework/Monitoring/ServerStatsCollector.cs349
-rw-r--r--OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs25
-rwxr-xr-xOpenSim/Framework/Monitoring/Stats/CounterStat.cs163
-rwxr-xr-xOpenSim/Framework/Monitoring/Stats/EventHistogram.cs173
-rw-r--r--OpenSim/Framework/Monitoring/Stats/PercentageStat.cs16
-rw-r--r--OpenSim/Framework/Monitoring/Stats/Stat.cs79
-rw-r--r--OpenSim/Framework/Monitoring/StatsLogger.cs108
-rw-r--r--OpenSim/Framework/Monitoring/StatsManager.cs334
-rw-r--r--OpenSim/Framework/Monitoring/Watchdog.cs1
-rw-r--r--OpenSim/Framework/RegionFlags.cs3
-rw-r--r--OpenSim/Framework/Servers/BaseOpenSimServer.cs46
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs40
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs60
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs27
-rw-r--r--OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs15
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs18
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs45
-rw-r--r--OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs16
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs4
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestSessionService.cs13
-rw-r--r--OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs2
-rw-r--r--OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs20
-rw-r--r--OpenSim/Framework/Servers/MainServer.cs13
-rw-r--r--OpenSim/Framework/Servers/ServerBase.cs254
-rw-r--r--OpenSim/Framework/Tests/LocationTest.cs21
-rw-r--r--OpenSim/Framework/Tests/MundaneFrameworkTests.cs2
-rw-r--r--OpenSim/Framework/Tests/UtilTest.cs82
-rw-r--r--OpenSim/Framework/UserProfiles.cs117
-rw-r--r--OpenSim/Framework/Util.cs143
-rw-r--r--OpenSim/Framework/WebUtil.cs80
51 files changed, 2687 insertions, 571 deletions
diff --git a/OpenSim/Framework/Animation.cs b/OpenSim/Framework/Animation.cs
index 232f5a1..3425505 100644
--- a/OpenSim/Framework/Animation.cs
+++ b/OpenSim/Framework/Animation.cs
@@ -120,5 +120,24 @@ namespace OpenSim.Framework
120 sequenceNum = args["seq_num"].AsInteger(); 120 sequenceNum = args["seq_num"].AsInteger();
121 } 121 }
122 122
123 public override bool Equals(object obj)
124 {
125 Animation other = obj as Animation;
126 if (other != null)
127 {
128 return (other.AnimID.Equals(this.AnimID)
129 && other.SequenceNum == this.SequenceNum
130 && other.ObjectID.Equals(this.ObjectID) );
131 }
132 return base.Equals(obj);
133 }
134
135 public override string ToString()
136 {
137 return "AnimID=" + AnimID.ToString()
138 + "/seq=" + SequenceNum.ToString()
139 + "/objID=" + ObjectID.ToString();
140 }
141
123 } 142 }
124} 143}
diff --git a/OpenSim/Framework/BlockingQueue.cs b/OpenSim/Framework/BlockingQueue.cs
index 3658161..3e90fac 100644
--- a/OpenSim/Framework/BlockingQueue.cs
+++ b/OpenSim/Framework/BlockingQueue.cs
@@ -58,7 +58,7 @@ namespace OpenSim.Framework
58 { 58 {
59 lock (m_queueSync) 59 lock (m_queueSync)
60 { 60 {
61 if (m_queue.Count < 1 && m_pqueue.Count < 1) 61 while (m_queue.Count < 1 && m_pqueue.Count < 1)
62 { 62 {
63 Monitor.Wait(m_queueSync); 63 Monitor.Wait(m_queueSync);
64 } 64 }
@@ -76,9 +76,10 @@ namespace OpenSim.Framework
76 { 76 {
77 lock (m_queueSync) 77 lock (m_queueSync)
78 { 78 {
79 if (m_queue.Count < 1 && m_pqueue.Count < 1) 79 bool success = true;
80 while (m_queue.Count < 1 && m_pqueue.Count < 1 && success)
80 { 81 {
81 Monitor.Wait(m_queueSync, msTimeout); 82 success = Monitor.Wait(m_queueSync, msTimeout);
82 } 83 }
83 84
84 if (m_pqueue.Count > 0) 85 if (m_pqueue.Count > 0)
@@ -89,8 +90,17 @@ namespace OpenSim.Framework
89 } 90 }
90 } 91 }
91 92
93 /// <summary>
94 /// Indicate whether this queue contains the given item.
95 /// </summary>
96 /// <remarks>
97 /// This method is not thread-safe. Do not rely on the result without consistent external locking.
98 /// </remarks>
92 public bool Contains(T item) 99 public bool Contains(T item)
93 { 100 {
101 if (m_queue.Count < 1 && m_pqueue.Count < 1)
102 return false;
103
94 lock (m_queueSync) 104 lock (m_queueSync)
95 { 105 {
96 if (m_pqueue.Contains(item)) 106 if (m_pqueue.Contains(item))
@@ -99,16 +109,28 @@ namespace OpenSim.Framework
99 } 109 }
100 } 110 }
101 111
112 /// <summary>
113 /// Return a count of the number of requests on this queue.
114 /// </summary>
115 /// <remarks>
116 /// This method is not thread-safe. Do not rely on the result without consistent external locking.
117 /// </remarks>
102 public int Count() 118 public int Count()
103 { 119 {
104 lock (m_queueSync) 120 return m_queue.Count + m_pqueue.Count;
105 {
106 return m_queue.Count+m_pqueue.Count;
107 }
108 } 121 }
109 122
123 /// <summary>
124 /// Return the array of items on this queue.
125 /// </summary>
126 /// <remarks>
127 /// This method is not thread-safe. Do not rely on the result without consistent external locking.
128 /// </remarks>
110 public T[] GetQueueArray() 129 public T[] GetQueueArray()
111 { 130 {
131 if (m_queue.Count < 1 && m_pqueue.Count < 1)
132 return new T[0];
133
112 lock (m_queueSync) 134 lock (m_queueSync)
113 { 135 {
114 return m_queue.ToArray(); 136 return m_queue.ToArray();
diff --git a/OpenSim/Framework/CachedTextureEventArg.cs b/OpenSim/Framework/CachedTextureEventArg.cs
new file mode 100644
index 0000000..239fc56
--- /dev/null
+++ b/OpenSim/Framework/CachedTextureEventArg.cs
@@ -0,0 +1,46 @@
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 OpenSimulator 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
28using System;
29using System.Text;
30using OpenMetaverse;
31
32namespace OpenSim.Framework
33{
34 public class CachedTextureRequestArg
35 {
36 public int BakedTextureIndex;
37 public UUID WearableHashID;
38 }
39
40 public class CachedTextureResponseArg
41 {
42 public int BakedTextureIndex;
43 public UUID BakedTextureID;
44 public String HostName;
45 }
46}
diff --git a/OpenSim/Framework/ChildAgentDataUpdate.cs b/OpenSim/Framework/ChildAgentDataUpdate.cs
index 8c32734..2a8e67d 100644
--- a/OpenSim/Framework/ChildAgentDataUpdate.cs
+++ b/OpenSim/Framework/ChildAgentDataUpdate.cs
@@ -171,9 +171,10 @@ namespace OpenSim.Framework
171 /// Soon to be decommissioned 171 /// Soon to be decommissioned
172 /// </summary> 172 /// </summary>
173 /// <param name="cAgent"></param> 173 /// <param name="cAgent"></param>
174 public void CopyFrom(ChildAgentDataUpdate cAgent) 174 public void CopyFrom(ChildAgentDataUpdate cAgent, UUID sid)
175 { 175 {
176 AgentID = new UUID(cAgent.AgentID); 176 AgentID = new UUID(cAgent.AgentID);
177 SessionID = sid;
177 178
178 // next: ??? 179 // next: ???
179 Size = new Vector3(); 180 Size = new Vector3();
@@ -291,7 +292,13 @@ namespace OpenSim.Framework
291 public Vector3 AtAxis; 292 public Vector3 AtAxis;
292 public Vector3 LeftAxis; 293 public Vector3 LeftAxis;
293 public Vector3 UpAxis; 294 public Vector3 UpAxis;
294 public bool ChangedGrid; 295
296 /// <summary>
297 /// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the
298 /// scene presence to become root (triggered when the viewer sends a CompleteAgentMovement UDP packet after
299 /// establishing the connection triggered by it's receipt of a TeleportFinish EQ message).
300 /// </summary>
301 public bool SenderWantsToWaitForRoot;
295 302
296 public float Far; 303 public float Far;
297 public float Aspect; 304 public float Aspect;
@@ -362,8 +369,9 @@ namespace OpenSim.Framework
362 args["left_axis"] = OSD.FromString(LeftAxis.ToString()); 369 args["left_axis"] = OSD.FromString(LeftAxis.ToString());
363 args["up_axis"] = OSD.FromString(UpAxis.ToString()); 370 args["up_axis"] = OSD.FromString(UpAxis.ToString());
364 371
365 372 //backwards compatibility
366 args["changed_grid"] = OSD.FromBoolean(ChangedGrid); 373 args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
374 args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
367 args["far"] = OSD.FromReal(Far); 375 args["far"] = OSD.FromReal(Far);
368 args["aspect"] = OSD.FromReal(Aspect); 376 args["aspect"] = OSD.FromReal(Aspect);
369 377
@@ -536,8 +544,8 @@ namespace OpenSim.Framework
536 if (args["up_axis"] != null) 544 if (args["up_axis"] != null)
537 Vector3.TryParse(args["up_axis"].AsString(), out AtAxis); 545 Vector3.TryParse(args["up_axis"].AsString(), out AtAxis);
538 546
539 if (args["changed_grid"] != null) 547 if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null)
540 ChangedGrid = args["changed_grid"].AsBoolean(); 548 SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean();
541 549
542 if (args["far"] != null) 550 if (args["far"] != null)
543 Far = (float)(args["far"].AsReal()); 551 Far = (float)(args["far"].AsReal());
diff --git a/OpenSim/Framework/ClientInfo.cs b/OpenSim/Framework/ClientInfo.cs
index 62acb70..9021315 100644
--- a/OpenSim/Framework/ClientInfo.cs
+++ b/OpenSim/Framework/ClientInfo.cs
@@ -33,12 +33,13 @@ namespace OpenSim.Framework
33{ 33{
34 public class ClientInfo 34 public class ClientInfo
35 { 35 {
36 public AgentCircuitData agentcircuit; 36 public readonly DateTime StartedTime = DateTime.Now;
37 public AgentCircuitData agentcircuit = null;
37 38
38 public Dictionary<uint, byte[]> needAck; 39 public Dictionary<uint, byte[]> needAck;
39 40
40 public List<byte[]> out_packets; 41 public List<byte[]> out_packets = new List<byte[]>();
41 public Dictionary<uint, uint> pendingAcks; 42 public Dictionary<uint, uint> pendingAcks = new Dictionary<uint,uint>();
42 public EndPoint proxyEP; 43 public EndPoint proxyEP;
43 44
44 public uint sequence; 45 public uint sequence;
@@ -53,5 +54,9 @@ namespace OpenSim.Framework
53 public int assetThrottle; 54 public int assetThrottle;
54 public int textureThrottle; 55 public int textureThrottle;
55 public int totalThrottle; 56 public int totalThrottle;
57
58 public Dictionary<string, int> SyncRequests = new Dictionary<string,int>();
59 public Dictionary<string, int> AsyncRequests = new Dictionary<string,int>();
60 public Dictionary<string, int> GenericRequests = new Dictionary<string,int>();
56 } 61 }
57} 62}
diff --git a/OpenSim/Framework/Console/ConsoleUtil.cs b/OpenSim/Framework/Console/ConsoleUtil.cs
index 97a86a8..794bfaf 100644
--- a/OpenSim/Framework/Console/ConsoleUtil.cs
+++ b/OpenSim/Framework/Console/ConsoleUtil.cs
@@ -156,12 +156,32 @@ namespace OpenSim.Framework.Console
156 } 156 }
157 157
158 /// <summary> 158 /// <summary>
159 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 159 /// Convert a console integer to an int, automatically complaining if a console is given.
160 /// </summary> 160 /// </summary>
161 /// <param name='console'>Can be null if no console is available.</param> 161 /// <param name='console'>Can be null if no console is available.</param>
162 /// <param name='rawConsoleVector'>/param> 162 /// <param name='rawConsoleVector'>/param>
163 /// <param name='vector'></param> 163 /// <param name='vector'></param>
164 /// <returns></returns> 164 /// <returns></returns>
165 public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b)
166 {
167 if (!bool.TryParse(rawConsoleString, out b))
168 {
169 if (console != null)
170 console.OutputFormat("ERROR: {0} is not a true or false value", rawConsoleString);
171
172 return false;
173 }
174
175 return true;
176 }
177
178 /// <summary>
179 /// Convert a console integer to an int, automatically complaining if a console is given.
180 /// </summary>
181 /// <param name='console'>Can be null if no console is available.</param>
182 /// <param name='rawConsoleInt'>/param>
183 /// <param name='i'></param>
184 /// <returns></returns>
165 public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i) 185 public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
166 { 186 {
167 if (!int.TryParse(rawConsoleInt, out i)) 187 if (!int.TryParse(rawConsoleInt, out i))
@@ -174,6 +194,31 @@ namespace OpenSim.Framework.Console
174 194
175 return true; 195 return true;
176 } 196 }
197
198 /// <summary>
199 /// Convert a console integer to a natural int, automatically complaining if a console is given.
200 /// </summary>
201 /// <param name='console'>Can be null if no console is available.</param>
202 /// <param name='rawConsoleInt'>/param>
203 /// <param name='i'></param>
204 /// <returns></returns>
205 public static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i)
206 {
207 if (TryParseConsoleInt(console, rawConsoleInt, out i))
208 {
209 if (i < 0)
210 {
211 if (console != null)
212 console.OutputFormat("ERROR: {0} is not a positive integer", rawConsoleInt);
213
214 return false;
215 }
216
217 return true;
218 }
219
220 return false;
221 }
177 222
178 /// <summary> 223 /// <summary>
179 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3 224 /// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
diff --git a/OpenSim/Framework/Console/LocalConsole.cs b/OpenSim/Framework/Console/LocalConsole.cs
index d41481f..a967db6 100644
--- a/OpenSim/Framework/Console/LocalConsole.cs
+++ b/OpenSim/Framework/Console/LocalConsole.cs
@@ -426,6 +426,21 @@ namespace OpenSim.Framework.Console
426 System.Console.Write("{0}", prompt); 426 System.Console.Write("{0}", prompt);
427 427
428 break; 428 break;
429 case ConsoleKey.Delete:
430 if (m_cursorXPosition == m_commandLine.Length)
431 break;
432
433 m_commandLine.Remove(m_cursorXPosition, 1);
434
435 SetCursorLeft(0);
436 m_cursorYPosition = SetCursorTop(m_cursorYPosition);
437
438 if (m_echo)
439 System.Console.Write("{0}{1} ", prompt, m_commandLine);
440 else
441 System.Console.Write("{0}", prompt);
442
443 break;
429 case ConsoleKey.End: 444 case ConsoleKey.End:
430 m_cursorXPosition = m_commandLine.Length; 445 m_cursorXPosition = m_commandLine.Length;
431 break; 446 break;
diff --git a/OpenSim/Framework/Console/RemoteConsole.cs b/OpenSim/Framework/Console/RemoteConsole.cs
index 3e3c2b3..8ad7b0d 100644
--- a/OpenSim/Framework/Console/RemoteConsole.cs
+++ b/OpenSim/Framework/Console/RemoteConsole.cs
@@ -234,7 +234,7 @@ namespace OpenSim.Framework.Console
234 string uri = "/ReadResponses/" + sessionID.ToString() + "/"; 234 string uri = "/ReadResponses/" + sessionID.ToString() + "/";
235 235
236 m_Server.AddPollServiceHTTPHandler( 236 m_Server.AddPollServiceHTTPHandler(
237 uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout 237 uri, new PollServiceEventArgs(null, uri, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout
238 238
239 XmlDocument xmldoc = new XmlDocument(); 239 XmlDocument xmldoc = new XmlDocument();
240 XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration, 240 XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
diff --git a/OpenSim/Framework/DAMap.cs b/OpenSim/Framework/DAMap.cs
index df4a6bc..4995a92 100644
--- a/OpenSim/Framework/DAMap.cs
+++ b/OpenSim/Framework/DAMap.cs
@@ -29,10 +29,12 @@ using System;
29using System.Collections; 29using System.Collections;
30using System.Collections.Generic; 30using System.Collections.Generic;
31using System.IO; 31using System.IO;
32using System.Reflection;
32using System.Text; 33using System.Text;
33using System.Xml; 34using System.Xml;
34using System.Xml.Schema; 35using System.Xml.Schema;
35using System.Xml.Serialization; 36using System.Xml.Serialization;
37using log4net;
36using OpenMetaverse; 38using OpenMetaverse;
37using OpenMetaverse.StructuredData; 39using OpenMetaverse.StructuredData;
38 40
@@ -48,13 +50,20 @@ namespace OpenSim.Framework
48 /// within their data store. However, avoid storing large amounts of data because that 50 /// within their data store. However, avoid storing large amounts of data because that
49 /// would slow down database access. 51 /// would slow down database access.
50 /// </remarks> 52 /// </remarks>
51 public class DAMap : IDictionary<string, OSDMap>, IXmlSerializable 53 public class DAMap : IXmlSerializable
52 { 54 {
53 private static readonly int MIN_STORE_NAME_LENGTH = 4; 55// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
54 56
55 protected OSDMap m_map; 57 private static readonly int MIN_NAMESPACE_LENGTH = 4;
56 58
57 public DAMap() { m_map = new OSDMap(); } 59 private OSDMap m_map = new OSDMap();
60
61 // WARNING: this is temporary for experimentation only, it will be removed!!!!
62 public OSDMap TopLevelMap
63 {
64 get { return m_map; }
65 set { m_map = value; }
66 }
58 67
59 public XmlSchema GetSchema() { return null; } 68 public XmlSchema GetSchema() { return null; }
60 69
@@ -64,39 +73,34 @@ namespace OpenSim.Framework
64 map.ReadXml(rawXml); 73 map.ReadXml(rawXml);
65 return map; 74 return map;
66 } 75 }
67 76
77 public void ReadXml(XmlReader reader)
78 {
79 ReadXml(reader.ReadInnerXml());
80 }
81
68 public void ReadXml(string rawXml) 82 public void ReadXml(string rawXml)
69 { 83 {
70 // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml); 84 // System.Console.WriteLine("Trying to deserialize [{0}]", rawXml);
71 85
72 lock (this) 86 lock (this)
87 {
73 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml); 88 m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml);
89 SanitiseMap(this);
90 }
74 } 91 }
75 92
76 // WARNING: this is temporary for experimentation only, it will be removed!!!! 93 public void WriteXml(XmlWriter writer)
77 public OSDMap TopLevelMap
78 { 94 {
79 get { return m_map; } 95 writer.WriteRaw(ToXml());
80 set { m_map = value; }
81 } 96 }
82
83 97
84 public void ReadXml(XmlReader reader)
85 {
86 ReadXml(reader.ReadInnerXml());
87 }
88
89 public string ToXml() 98 public string ToXml()
90 { 99 {
91 lock (this) 100 lock (this)
92 return OSDParser.SerializeLLSDXmlString(m_map); 101 return OSDParser.SerializeLLSDXmlString(m_map);
93 } 102 }
94 103
95 public void WriteXml(XmlWriter writer)
96 {
97 writer.WriteRaw(ToXml());
98 }
99
100 public void CopyFrom(DAMap other) 104 public void CopyFrom(DAMap other)
101 { 105 {
102 // Deep copy 106 // Deep copy
@@ -104,7 +108,7 @@ namespace OpenSim.Framework
104 string data = null; 108 string data = null;
105 lock (other) 109 lock (other)
106 { 110 {
107 if (other.Count > 0) 111 if (other.CountNamespaces > 0)
108 { 112 {
109 data = OSDParser.SerializeLLSDXmlString(other.m_map); 113 data = OSDParser.SerializeLLSDXmlString(other.m_map);
110 } 114 }
@@ -120,59 +124,132 @@ namespace OpenSim.Framework
120 } 124 }
121 125
122 /// <summary> 126 /// <summary>
123 /// Returns the number of data stores. 127 /// Sanitise the map to remove any namespaces or stores that are not OSDMap.
124 /// </summary> 128 /// </summary>
125 public int Count { get { lock (this) { return m_map.Count; } } } 129 /// <param name='map'>
126 130 /// </param>
127 public bool IsReadOnly { get { return false; } } 131 public static void SanitiseMap(DAMap daMap)
128 132 {
133 List<string> keysToRemove = null;
134
135 OSDMap namespacesMap = daMap.m_map;
136
137 foreach (string key in namespacesMap.Keys)
138 {
139// Console.WriteLine("Processing ns {0}", key);
140 if (!(namespacesMap[key] is OSDMap))
141 {
142 if (keysToRemove == null)
143 keysToRemove = new List<string>();
144
145 keysToRemove.Add(key);
146 }
147 }
148
149 if (keysToRemove != null)
150 {
151 foreach (string key in keysToRemove)
152 {
153// Console.WriteLine ("Removing bad ns {0}", key);
154 namespacesMap.Remove(key);
155 }
156 }
157
158 foreach (OSD nsOsd in namespacesMap.Values)
159 {
160 OSDMap nsOsdMap = (OSDMap)nsOsd;
161 keysToRemove = null;
162
163 foreach (string key in nsOsdMap.Keys)
164 {
165 if (!(nsOsdMap[key] is OSDMap))
166 {
167 if (keysToRemove == null)
168 keysToRemove = new List<string>();
169
170 keysToRemove.Add(key);
171 }
172 }
173
174 if (keysToRemove != null)
175 foreach (string key in keysToRemove)
176 nsOsdMap.Remove(key);
177 }
178 }
179
129 /// <summary> 180 /// <summary>
130 /// Returns the names of the data stores. 181 /// Get the number of namespaces
131 /// </summary> 182 /// </summary>
132 public ICollection<string> Keys { get { lock (this) { return m_map.Keys; } } } 183 public int CountNamespaces { get { lock (this) { return m_map.Count; } } }
133 184
134 /// <summary> 185 /// <summary>
135 /// Returns all the data stores. 186 /// Get the number of stores.
136 /// </summary> 187 /// </summary>
137 public ICollection<OSDMap> Values 188 public int CountStores
138 { 189 {
139 get 190 get
140 { 191 {
192 int count = 0;
193
141 lock (this) 194 lock (this)
142 { 195 {
143 List<OSDMap> stores = new List<OSDMap>(m_map.Count); 196 foreach (OSD osdNamespace in m_map)
144 foreach (OSD llsd in m_map.Values) 197 {
145 stores.Add((OSDMap)llsd); 198 count += ((OSDMap)osdNamespace).Count;
146 return stores; 199 }
147 } 200 }
201
202 return count;
148 } 203 }
149 } 204 }
150 205
151 /// <summary> 206 /// <summary>
152 /// Gets or sets one data store. 207 /// Retrieve a Dynamic Attribute store
153 /// </summary> 208 /// </summary>
154 /// <param name="key">Store name</param> 209 /// <param name="ns">namespace for the store - use "OpenSim" for in-core modules</param>
155 /// <returns></returns> 210 /// <param name="storeName">name of the store within the namespace</param>
156 public OSDMap this[string key] 211 /// <returns>an OSDMap representing the stored data, or null if not found</returns>
157 { 212 public OSDMap GetStore(string ns, string storeName)
158 get 213 {
159 { 214 OSD namespaceOsd;
160 OSD llsd; 215
161 216 lock (this)
162 lock (this) 217 {
218 if (m_map.TryGetValue(ns, out namespaceOsd))
163 { 219 {
164 if (m_map.TryGetValue(key, out llsd)) 220 OSD store;
165 return (OSDMap)llsd; 221
166 else 222 if (((OSDMap)namespaceOsd).TryGetValue(storeName, out store))
167 return null; 223 return (OSDMap)store;
168 } 224 }
169 } 225 }
170 226
171 set 227 return null;
228 }
229
230 /// <summary>
231 /// Saves a Dynamic attribute store
232 /// </summary>
233 /// <param name="ns">namespace for the store - use "OpenSim" for in-core modules</param>
234 /// <param name="storeName">name of the store within the namespace</param>
235 /// <param name="store">an OSDMap representing the data to store</param>
236 public void SetStore(string ns, string storeName, OSDMap store)
237 {
238 ValidateNamespace(ns);
239 OSDMap nsMap;
240
241 lock (this)
172 { 242 {
173 ValidateKey(key); 243 if (!m_map.ContainsKey(ns))
174 lock (this) 244 {
175 m_map[key] = value; 245 nsMap = new OSDMap();
246 m_map[ns] = nsMap;
247 }
248
249 nsMap = (OSDMap)m_map[ns];
250
251// m_log.DebugFormat("[DA MAP]: Setting store to {0}:{1}", ns, storeName);
252 nsMap[storeName] = store;
176 } 253 }
177 } 254 }
178 255
@@ -180,54 +257,46 @@ namespace OpenSim.Framework
180 /// Validate the key used for storing separate data stores. 257 /// Validate the key used for storing separate data stores.
181 /// </summary> 258 /// </summary>
182 /// <param name='key'></param> 259 /// <param name='key'></param>
183 public static void ValidateKey(string key) 260 public static void ValidateNamespace(string ns)
184 { 261 {
185 if (key.Length < MIN_STORE_NAME_LENGTH) 262 if (ns.Length < MIN_NAMESPACE_LENGTH)
186 throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH); 263 throw new Exception("Minimum namespace length is " + MIN_NAMESPACE_LENGTH);
187 } 264 }
188 265
189 public bool ContainsKey(string key) 266 public bool ContainsStore(string ns, string storeName)
190 { 267 {
191 lock (this) 268 OSD namespaceOsd;
192 return m_map.ContainsKey(key);
193 }
194 269
195 public void Add(string key, OSDMap store)
196 {
197 ValidateKey(key);
198 lock (this)
199 m_map.Add(key, store);
200 }
201
202 public void Add(KeyValuePair<string, OSDMap> kvp)
203 {
204 ValidateKey(kvp.Key);
205 lock (this) 270 lock (this)
206 m_map.Add(kvp.Key, kvp.Value); 271 {
207 } 272 if (m_map.TryGetValue(ns, out namespaceOsd))
273 {
274 return ((OSDMap)namespaceOsd).ContainsKey(storeName);
275 }
276 }
208 277
209 public bool Remove(string key) 278 return false;
210 { 279 }
211 lock (this)
212 return m_map.Remove(key);
213 }
214 280
215 public bool TryGetValue(string key, out OSDMap store) 281 public bool TryGetStore(string ns, string storeName, out OSDMap store)
216 { 282 {
283 OSD namespaceOsd;
284
217 lock (this) 285 lock (this)
218 { 286 {
219 OSD llsd; 287 if (m_map.TryGetValue(ns, out namespaceOsd))
220 if (m_map.TryGetValue(key, out llsd))
221 {
222 store = (OSDMap)llsd;
223 return true;
224 }
225 else
226 { 288 {
227 store = null; 289 OSD storeOsd;
228 return false; 290
291 bool result = ((OSDMap)namespaceOsd).TryGetValue(storeName, out storeOsd);
292 store = (OSDMap)storeOsd;
293
294 return result;
229 } 295 }
230 } 296 }
297
298 store = null;
299 return false;
231 } 300 }
232 301
233 public void Clear() 302 public void Clear()
@@ -235,39 +304,25 @@ namespace OpenSim.Framework
235 lock (this) 304 lock (this)
236 m_map.Clear(); 305 m_map.Clear();
237 } 306 }
238
239 public bool Contains(KeyValuePair<string, OSDMap> kvp)
240 {
241 lock (this)
242 return m_map.ContainsKey(kvp.Key);
243 }
244
245 public void CopyTo(KeyValuePair<string, OSDMap>[] array, int index)
246 {
247 throw new NotImplementedException();
248 }
249 307
250 public bool Remove(KeyValuePair<string, OSDMap> kvp) 308 public bool RemoveStore(string ns, string storeName)
251 { 309 {
252 lock (this) 310 OSD namespaceOsd;
253 return m_map.Remove(kvp.Key);
254 }
255 311
256 public System.Collections.IDictionaryEnumerator GetEnumerator()
257 {
258 lock (this) 312 lock (this)
259 return m_map.GetEnumerator(); 313 {
260 } 314 if (m_map.TryGetValue(ns, out namespaceOsd))
315 {
316 OSDMap namespaceOsdMap = (OSDMap)namespaceOsd;
317 namespaceOsdMap.Remove(storeName);
261 318
262 IEnumerator<KeyValuePair<string, OSDMap>> IEnumerable<KeyValuePair<string, OSDMap>>.GetEnumerator() 319 // Don't keep empty namespaces around
263 { 320 if (namespaceOsdMap.Count <= 0)
264 return null; 321 m_map.Remove(ns);
265 } 322 }
323 }
266 324
267 IEnumerator IEnumerable.GetEnumerator() 325 return false;
268 { 326 }
269 lock (this)
270 return m_map.GetEnumerator();
271 }
272 } 327 }
273} \ No newline at end of file 328} \ No newline at end of file
diff --git a/OpenSim/Framework/DOMap.cs b/OpenSim/Framework/DOMap.cs
index 755e129..f5b650b 100644
--- a/OpenSim/Framework/DOMap.cs
+++ b/OpenSim/Framework/DOMap.cs
@@ -42,22 +42,22 @@ namespace OpenSim.Framework
42 /// This class stores and retrieves dynamic objects. 42 /// This class stores and retrieves dynamic objects.
43 /// </summary> 43 /// </summary>
44 /// <remarks> 44 /// <remarks>
45 /// Experimental - DO NOT USE. 45 /// Experimental - DO NOT USE. Does not yet have namespace support.
46 /// </remarks> 46 /// </remarks>
47 public class DOMap 47 public class DOMap
48 { 48 {
49 private IDictionary<string, object> m_map; 49 private IDictionary<string, object> m_map;
50 50
51 public void Add(string key, object dynObj) 51 public void Add(string ns, string objName, object dynObj)
52 { 52 {
53 DAMap.ValidateKey(key); 53 DAMap.ValidateNamespace(ns);
54 54
55 lock (this) 55 lock (this)
56 { 56 {
57 if (m_map == null) 57 if (m_map == null)
58 m_map = new Dictionary<string, object>(); 58 m_map = new Dictionary<string, object>();
59 59
60 m_map.Add(key, dynObj); 60 m_map.Add(objName, dynObj);
61 } 61 }
62 } 62 }
63 63
diff --git a/OpenSim/Framework/EstateSettings.cs b/OpenSim/Framework/EstateSettings.cs
index e03750b..5ddbd61 100644
--- a/OpenSim/Framework/EstateSettings.cs
+++ b/OpenSim/Framework/EstateSettings.cs
@@ -430,6 +430,5 @@ namespace OpenSim.Framework
430 { 430 {
431 return l_EstateGroups.Contains(groupID); 431 return l_EstateGroups.Contains(groupID);
432 } 432 }
433
434 } 433 }
435} 434}
diff --git a/OpenSim/Framework/IClientAPI.cs b/OpenSim/Framework/IClientAPI.cs
index ad3471a..22cc79d 100644
--- a/OpenSim/Framework/IClientAPI.cs
+++ b/OpenSim/Framework/IClientAPI.cs
@@ -65,6 +65,7 @@ namespace OpenSim.Framework
65 public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes); 65 public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes);
66 66
67 public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems); 67 public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, Vector3 AvSize, WearableCacheItem[] CacheItems);
68 public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List<CachedTextureRequestArg> cachedTextureRequest);
68 69
69 public delegate void StartAnim(IClientAPI remoteClient, UUID animID); 70 public delegate void StartAnim(IClientAPI remoteClient, UUID animID);
70 71
@@ -789,6 +790,7 @@ namespace OpenSim.Framework
789 event EstateChangeInfo OnEstateChangeInfo; 790 event EstateChangeInfo OnEstateChangeInfo;
790 event EstateManageTelehub OnEstateManageTelehub; 791 event EstateManageTelehub OnEstateManageTelehub;
791 // [Obsolete("LLClientView Specific.")] 792 // [Obsolete("LLClientView Specific.")]
793 event CachedTextureRequest OnCachedTextureRequest;
792 event SetAppearance OnSetAppearance; 794 event SetAppearance OnSetAppearance;
793 // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")] 795 // [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")]
794 event AvatarNowWearing OnAvatarNowWearing; 796 event AvatarNowWearing OnAvatarNowWearing;
@@ -832,6 +834,8 @@ namespace OpenSim.Framework
832 /// </remarks> 834 /// </remarks>
833 event UpdateAgent OnAgentUpdate; 835 event UpdateAgent OnAgentUpdate;
834 836
837 event UpdateAgent OnAgentCameraUpdate;
838
835 event AgentRequestSit OnAgentRequestSit; 839 event AgentRequestSit OnAgentRequestSit;
836 event AgentSit OnAgentSit; 840 event AgentSit OnAgentSit;
837 event AvatarPickerRequest OnAvatarPickerRequest; 841 event AvatarPickerRequest OnAvatarPickerRequest;
@@ -1100,14 +1104,15 @@ namespace OpenSim.Framework
1100 /// <param name="textureEntry"></param> 1104 /// <param name="textureEntry"></param>
1101 void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry); 1105 void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry);
1102 1106
1107 void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures);
1108
1103 void SendStartPingCheck(byte seq); 1109 void SendStartPingCheck(byte seq);
1104 1110
1105 /// <summary> 1111 /// <summary>
1106 /// Tell the client that an object has been deleted 1112 /// Tell the client that an object has been deleted
1107 /// </summary> 1113 /// </summary>
1108 /// <param name="regionHandle"></param>
1109 /// <param name="localID"></param> 1114 /// <param name="localID"></param>
1110 void SendKillObject(ulong regionHandle, List<uint> localID); 1115 void SendKillObject(List<uint> localID);
1111 1116
1112 void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs); 1117 void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
1113 void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args); 1118 void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
@@ -1486,7 +1491,7 @@ namespace OpenSim.Framework
1486 void SendChangeUserRights(UUID agentID, UUID friendID, int rights); 1491 void SendChangeUserRights(UUID agentID, UUID friendID, int rights);
1487 void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId); 1492 void SendTextBoxRequest(string message, int chatChannel, string objectname, UUID ownerID, string ownerFirstName, string ownerLastName, UUID objectId);
1488 1493
1489 void StopFlying(ISceneEntity presence); 1494 void SendAgentTerseUpdate(ISceneEntity presence);
1490 1495
1491 void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data); 1496 void SendPlacesReply(UUID queryID, UUID transactionID, PlacesReplyData[] data);
1492 } 1497 }
diff --git a/OpenSim/Framework/IPeople.cs b/OpenSim/Framework/IPeople.cs
new file mode 100644
index 0000000..b88e103
--- /dev/null
+++ b/OpenSim/Framework/IPeople.cs
@@ -0,0 +1,47 @@
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 OpenSimulator 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
28using System;
29using System.Collections.Generic;
30using OpenMetaverse;
31
32namespace OpenSim.Framework
33{
34 public class UserData
35 {
36 public UUID Id { get; set; }
37 public string FirstName { get; set; }
38 public string LastName { get; set; }
39 public string HomeURL { get; set; }
40 public Dictionary<string, object> ServerURLs { get; set; }
41 }
42
43 public interface IPeople
44 {
45 List<UserData> GetUserData(string query, int page_size, int page_number);
46 }
47} \ No newline at end of file
diff --git a/OpenSim/Framework/IScene.cs b/OpenSim/Framework/IScene.cs
index 87ec99e..8164f41 100644
--- a/OpenSim/Framework/IScene.cs
+++ b/OpenSim/Framework/IScene.cs
@@ -136,5 +136,10 @@ namespace OpenSim.Framework
136 ISceneObject DeserializeObject(string representation); 136 ISceneObject DeserializeObject(string representation);
137 137
138 bool CheckClient(UUID agentID, System.Net.IPEndPoint ep); 138 bool CheckClient(UUID agentID, System.Net.IPEndPoint ep);
139
140 /// <summary>
141 /// Start the scene and associated scripts within it.
142 /// </summary>
143 void Start();
139 } 144 }
140} 145} \ No newline at end of file
diff --git a/OpenSim/Framework/Location.cs b/OpenSim/Framework/Location.cs
index 9504e03..0b88834 100644
--- a/OpenSim/Framework/Location.cs
+++ b/OpenSim/Framework/Location.cs
@@ -33,10 +33,10 @@ namespace OpenSim.Framework
33 [Serializable] 33 [Serializable]
34 public class Location : ICloneable 34 public class Location : ICloneable
35 { 35 {
36 private readonly int m_x; 36 private readonly uint m_x;
37 private readonly int m_y; 37 private readonly uint m_y;
38 38
39 public Location(int x, int y) 39 public Location(uint x, uint y)
40 { 40 {
41 m_x = x; 41 m_x = x;
42 m_y = y; 42 m_y = y;
@@ -44,21 +44,21 @@ namespace OpenSim.Framework
44 44
45 public Location(ulong regionHandle) 45 public Location(ulong regionHandle)
46 { 46 {
47 m_x = (int) regionHandle; 47 m_x = (uint)(regionHandle >> 32);
48 m_y = (int) (regionHandle >> 32); 48 m_y = (uint)(regionHandle & (ulong)uint.MaxValue);
49 } 49 }
50 50
51 public ulong RegionHandle 51 public ulong RegionHandle
52 { 52 {
53 get { return Utils.UIntsToLong((uint)m_x, (uint)m_y); } 53 get { return Utils.UIntsToLong(m_x, m_y); }
54 } 54 }
55 55
56 public int X 56 public uint X
57 { 57 {
58 get { return m_x; } 58 get { return m_x; }
59 } 59 }
60 60
61 public int Y 61 public uint Y
62 { 62 {
63 get { return m_y; } 63 get { return m_y; }
64 } 64 }
diff --git a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
index 23dba09..96536e8 100644
--- a/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/BaseStatsCollector.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -44,16 +44,16 @@ namespace OpenSim.Framework.Monitoring
44 sb.Append("MEMORY STATISTICS"); 44 sb.Append("MEMORY STATISTICS");
45 sb.Append(Environment.NewLine); 45 sb.Append(Environment.NewLine);
46 sb.AppendFormat( 46 sb.AppendFormat(
47 "Allocated to OpenSim objects: {0} MB\n", 47 "Heap allocated to OpenSim : {0} MB\n",
48 Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)); 48 Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0));
49 49
50 sb.AppendFormat( 50 sb.AppendFormat(
51 "OpenSim last object memory churn : {0} MB/s\n", 51 "Last heap allocation rate : {0} MB/s\n",
52 Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3)); 52 Math.Round((MemoryWatchdog.LastHeapAllocationRate * 1000) / 1024.0 / 1024, 3));
53 53
54 sb.AppendFormat( 54 sb.AppendFormat(
55 "OpenSim average object memory churn : {0} MB/s\n", 55 "Average heap allocation rate: {0} MB/s\n",
56 Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3)); 56 Math.Round((MemoryWatchdog.AverageHeapAllocationRate * 1000) / 1024.0 / 1024, 3));
57 57
58 Process myprocess = Process.GetCurrentProcess(); 58 Process myprocess = Process.GetCurrentProcess();
59 if (!myprocess.HasExited) 59 if (!myprocess.HasExited)
diff --git a/OpenSim/Framework/Monitoring/Checks/Check.cs b/OpenSim/Framework/Monitoring/Checks/Check.cs
new file mode 100644
index 0000000..594386a
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Checks/Check.cs
@@ -0,0 +1,118 @@
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 OpenSimulator 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
28using System;
29using System.Text;
30
31namespace OpenSim.Framework.Monitoring
32{
33 public class Check
34 {
35// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
36
37 public static readonly char[] DisallowedShortNameCharacters = { '.' };
38
39 /// <summary>
40 /// Category of this stat (e.g. cache, scene, etc).
41 /// </summary>
42 public string Category { get; private set; }
43
44 /// <summary>
45 /// Containing name for this stat.
46 /// FIXME: In the case of a scene, this is currently the scene name (though this leaves
47 /// us with a to-be-resolved problem of non-unique region names).
48 /// </summary>
49 /// <value>
50 /// The container.
51 /// </value>
52 public string Container { get; private set; }
53
54 /// <summary>
55 /// Action used to check whether alert should go off.
56 /// </summary>
57 /// <remarks>
58 /// Should return true if check passes. False otherwise.
59 /// </remarks>
60 public Func<Check, bool> CheckFunc { get; private set; }
61
62 /// <summary>
63 /// Message from the last failure, if any. If there is no message or no failure then will be null.
64 /// </summary>
65 /// <remarks>
66 /// Should be set by the CheckFunc when applicable.
67 /// </remarks>
68 public string LastFailureMessage { get; set; }
69
70 public StatVerbosity Verbosity { get; private set; }
71 public string ShortName { get; private set; }
72 public string Name { get; private set; }
73 public string Description { get; private set; }
74
75 public Check(
76 string shortName,
77 string name,
78 string description,
79 string category,
80 string container,
81 Func<Check, bool> checkFunc,
82 StatVerbosity verbosity)
83 {
84 if (ChecksManager.SubCommands.Contains(category))
85 throw new Exception(
86 string.Format("Alert cannot be in category '{0}' since this is reserved for a subcommand", category));
87
88 foreach (char c in DisallowedShortNameCharacters)
89 {
90 if (shortName.IndexOf(c) != -1)
91 throw new Exception(string.Format("Alert name {0} cannot contain character {1}", shortName, c));
92 }
93
94 ShortName = shortName;
95 Name = name;
96 Description = description;
97 Category = category;
98 Container = container;
99 CheckFunc = checkFunc;
100 Verbosity = verbosity;
101 }
102
103 public bool CheckIt()
104 {
105 return CheckFunc(this);
106 }
107
108 public virtual string ToConsoleString()
109 {
110 return string.Format(
111 "{0}.{1}.{2} - {3}",
112 Category,
113 Container,
114 ShortName,
115 Description);
116 }
117 }
118} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/ChecksManager.cs b/OpenSim/Framework/Monitoring/ChecksManager.cs
new file mode 100644
index 0000000..e4a7f8c
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/ChecksManager.cs
@@ -0,0 +1,262 @@
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 OpenSimulator 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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
32using System.Text;
33using log4net;
34
35namespace OpenSim.Framework.Monitoring
36{
37 /// <summary>
38 /// Static class used to register/deregister checks on runtime conditions.
39 /// </summary>
40 public static class ChecksManager
41 {
42 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43
44 // Subcommand used to list other stats.
45 public const string ListSubCommand = "list";
46
47 // All subcommands
48 public static HashSet<string> SubCommands = new HashSet<string> { ListSubCommand };
49
50 /// <summary>
51 /// Checks categorized by category/container/shortname
52 /// </summary>
53 /// <remarks>
54 /// Do not add or remove directly from this dictionary.
55 /// </remarks>
56 public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>> RegisteredChecks
57 = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>>();
58
59 public static void RegisterConsoleCommands(ICommandConsole console)
60 {
61 console.Commands.AddCommand(
62 "General",
63 false,
64 "show checks",
65 "show checks",
66 "Show checks configured for this server",
67 "If no argument is specified then info on all checks will be shown.\n"
68 + "'list' argument will show check categories.\n"
69 + "THIS FACILITY IS EXPERIMENTAL",
70 HandleShowchecksCommand);
71 }
72
73 public static void HandleShowchecksCommand(string module, string[] cmd)
74 {
75 ICommandConsole con = MainConsole.Instance;
76
77 if (cmd.Length > 2)
78 {
79 foreach (string name in cmd.Skip(2))
80 {
81 string[] components = name.Split('.');
82
83 string categoryName = components[0];
84// string containerName = components.Length > 1 ? components[1] : null;
85
86 if (categoryName == ListSubCommand)
87 {
88 con.Output("check categories available are:");
89
90 foreach (string category in RegisteredChecks.Keys)
91 con.OutputFormat(" {0}", category);
92 }
93// else
94// {
95// SortedDictionary<string, SortedDictionary<string, Check>> category;
96// if (!Registeredchecks.TryGetValue(categoryName, out category))
97// {
98// con.OutputFormat("No such category as {0}", categoryName);
99// }
100// else
101// {
102// if (String.IsNullOrEmpty(containerName))
103// {
104// OutputConfiguredToConsole(con, category);
105// }
106// else
107// {
108// SortedDictionary<string, Check> container;
109// if (category.TryGetValue(containerName, out container))
110// {
111// OutputContainerChecksToConsole(con, container);
112// }
113// else
114// {
115// con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
116// }
117// }
118// }
119// }
120 }
121 }
122 else
123 {
124 OutputAllChecksToConsole(con);
125 }
126 }
127
128 /// <summary>
129 /// Registers a statistic.
130 /// </summary>
131 /// <param name='stat'></param>
132 /// <returns></returns>
133 public static bool RegisterCheck(Check check)
134 {
135 SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
136 SortedDictionary<string, Check> container = null, newContainer;
137
138 lock (RegisteredChecks)
139 {
140 // Check name is not unique across category/container/shortname key.
141 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
142 // in a class are run in the same instance of the VM.
143 if (TryGetCheckParents(check, out category, out container))
144 return false;
145
146 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
147 // This means that we don't need to lock or copy them on iteration, which will be a much more
148 // common operation after startup.
149 if (container != null)
150 newContainer = new SortedDictionary<string, Check>(container);
151 else
152 newContainer = new SortedDictionary<string, Check>();
153
154 if (category != null)
155 newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
156 else
157 newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>();
158
159 newContainer[check.ShortName] = check;
160 newCategory[check.Container] = newContainer;
161 RegisteredChecks[check.Category] = newCategory;
162 }
163
164 return true;
165 }
166
167 /// <summary>
168 /// Deregister an check
169 /// </summary>>
170 /// <param name='stat'></param>
171 /// <returns></returns>
172 public static bool DeregisterCheck(Check check)
173 {
174 SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
175 SortedDictionary<string, Check> container = null, newContainer;
176
177 lock (RegisteredChecks)
178 {
179 if (!TryGetCheckParents(check, out category, out container))
180 return false;
181
182 newContainer = new SortedDictionary<string, Check>(container);
183 newContainer.Remove(check.ShortName);
184
185 newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
186 newCategory.Remove(check.Container);
187
188 newCategory[check.Container] = newContainer;
189 RegisteredChecks[check.Category] = newCategory;
190
191 return true;
192 }
193 }
194
195 public static bool TryGetCheckParents(
196 Check check,
197 out SortedDictionary<string, SortedDictionary<string, Check>> category,
198 out SortedDictionary<string, Check> container)
199 {
200 category = null;
201 container = null;
202
203 lock (RegisteredChecks)
204 {
205 if (RegisteredChecks.TryGetValue(check.Category, out category))
206 {
207 if (category.TryGetValue(check.Container, out container))
208 {
209 if (container.ContainsKey(check.ShortName))
210 return true;
211 }
212 }
213 }
214
215 return false;
216 }
217
218 public static void CheckChecks()
219 {
220 lock (RegisteredChecks)
221 {
222 foreach (SortedDictionary<string, SortedDictionary<string, Check>> category in RegisteredChecks.Values)
223 {
224 foreach (SortedDictionary<string, Check> container in category.Values)
225 {
226 foreach (Check check in container.Values)
227 {
228 if (!check.CheckIt())
229 m_log.WarnFormat(
230 "[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage);
231 }
232 }
233 }
234 }
235 }
236
237 private static void OutputAllChecksToConsole(ICommandConsole con)
238 {
239 foreach (var category in RegisteredChecks.Values)
240 {
241 OutputCategoryChecksToConsole(con, category);
242 }
243 }
244
245 private static void OutputCategoryChecksToConsole(
246 ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Check>> category)
247 {
248 foreach (var container in category.Values)
249 {
250 OutputContainerChecksToConsole(con, container);
251 }
252 }
253
254 private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary<string, Check> container)
255 {
256 foreach (Check check in container.Values)
257 {
258 con.Output(check.ToConsoleString());
259 }
260 }
261 }
262} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
index c6010cd..c474622 100644
--- a/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
+++ b/OpenSim/Framework/Monitoring/MemoryWatchdog.cs
@@ -60,17 +60,17 @@ namespace OpenSim.Framework.Monitoring
60 private static bool m_enabled; 60 private static bool m_enabled;
61 61
62 /// <summary> 62 /// <summary>
63 /// Last memory churn in bytes per millisecond. 63 /// Average heap allocation rate in bytes per millisecond.
64 /// </summary> 64 /// </summary>
65 public static double AverageMemoryChurn 65 public static double AverageHeapAllocationRate
66 { 66 {
67 get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; } 67 get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; }
68 } 68 }
69 69
70 /// <summary> 70 /// <summary>
71 /// Average memory churn in bytes per millisecond. 71 /// Last heap allocation in bytes
72 /// </summary> 72 /// </summary>
73 public static double LastMemoryChurn 73 public static double LastHeapAllocationRate
74 { 74 {
75 get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; } 75 get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; }
76 } 76 }
diff --git a/OpenSim/Framework/Monitoring/ServerStatsCollector.cs b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs
new file mode 100644
index 0000000..ac0f0bc
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/ServerStatsCollector.cs
@@ -0,0 +1,349 @@
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 OpenSimulator 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
28using System;
29using System.Collections.Generic;
30using System.Diagnostics;
31using System.Linq;
32using System.Net.NetworkInformation;
33using System.Text;
34using System.Threading;
35using log4net;
36using Nini.Config;
37using OpenMetaverse.StructuredData;
38using OpenSim.Framework;
39
40namespace OpenSim.Framework.Monitoring
41{
42 public class ServerStatsCollector
43 {
44 private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
45 private readonly string LogHeader = "[SERVER STATS]";
46
47 public bool Enabled = false;
48 private static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>();
49
50 public readonly string CategoryServer = "server";
51
52 public readonly string ContainerThreadpool = "threadpool";
53 public readonly string ContainerProcessor = "processor";
54 public readonly string ContainerMemory = "memory";
55 public readonly string ContainerNetwork = "network";
56 public readonly string ContainerProcess = "process";
57
58 public string NetworkInterfaceTypes = "Ethernet";
59
60 readonly int performanceCounterSampleInterval = 500;
61// int lastperformanceCounterSampleTime = 0;
62
63 private class PerfCounterControl
64 {
65 public PerformanceCounter perfCounter;
66 public int lastFetch;
67 public string name;
68 public PerfCounterControl(PerformanceCounter pPc)
69 : this(pPc, String.Empty)
70 {
71 }
72 public PerfCounterControl(PerformanceCounter pPc, string pName)
73 {
74 perfCounter = pPc;
75 lastFetch = 0;
76 name = pName;
77 }
78 }
79
80 PerfCounterControl processorPercentPerfCounter = null;
81
82 // IRegionModuleBase.Initialize
83 public void Initialise(IConfigSource source)
84 {
85 IConfig cfg = source.Configs["Monitoring"];
86
87 if (cfg != null)
88 Enabled = cfg.GetBoolean("ServerStatsEnabled", true);
89
90 if (Enabled)
91 {
92 NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet");
93 }
94 }
95
96 public void Start()
97 {
98 if (RegisteredStats.Count == 0)
99 RegisterServerStats();
100 }
101
102 public void Close()
103 {
104 if (RegisteredStats.Count > 0)
105 {
106 foreach (Stat stat in RegisteredStats.Values)
107 {
108 StatsManager.DeregisterStat(stat);
109 stat.Dispose();
110 }
111 RegisteredStats.Clear();
112 }
113 }
114
115 private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act)
116 {
117 MakeStat(pName, pDesc, pUnit, pContainer, act, MeasuresOfInterest.None);
118 }
119
120 private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act, MeasuresOfInterest moi)
121 {
122 string desc = pDesc;
123 if (desc == null)
124 desc = pName;
125 Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, moi, act, StatVerbosity.Debug);
126 StatsManager.RegisterStat(stat);
127 RegisteredStats.Add(pName, stat);
128 }
129
130 public void RegisterServerStats()
131 {
132// lastperformanceCounterSampleTime = Util.EnvironmentTickCount();
133 PerformanceCounter tempPC;
134 Stat tempStat;
135 string tempName;
136
137 try
138 {
139 tempName = "CPUPercent";
140 tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total");
141 processorPercentPerfCounter = new PerfCounterControl(tempPC);
142 // A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy.
143 tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor,
144 StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); },
145 StatVerbosity.Info);
146 StatsManager.RegisterStat(tempStat);
147 RegisteredStats.Add(tempName, tempStat);
148
149 MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor,
150 (s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; });
151
152 MakeStat("UserProcessorTime", null, "sec", ContainerProcessor,
153 (s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; });
154
155 MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor,
156 (s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; });
157
158 MakeStat("Threads", null, "threads", ContainerProcessor,
159 (s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
160 }
161 catch (Exception e)
162 {
163 m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e);
164 }
165
166 MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool,
167 s =>
168 {
169 int workerThreads, iocpThreads;
170 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
171 s.Value = workerThreads;
172 });
173
174 MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool,
175 s =>
176 {
177 int workerThreads, iocpThreads;
178 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
179 s.Value = iocpThreads;
180 });
181
182 if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null)
183 {
184 MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads);
185 MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads);
186 MakeStat("STPConcurrency", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems);
187 MakeStat("STPActiveThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads);
188 MakeStat("STPInUseThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads);
189 MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks);
190 }
191
192 MakeStat(
193 "HTTPRequestsMade",
194 "Number of outbound HTTP requests made",
195 "requests",
196 ContainerNetwork,
197 s => s.Value = WebUtil.RequestNumber,
198 MeasuresOfInterest.AverageChangeOverTime);
199
200 try
201 {
202 List<string> okInterfaceTypes = new List<string>(NetworkInterfaceTypes.Split(','));
203
204 IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces();
205 foreach (NetworkInterface nic in nics)
206 {
207 if (nic.OperationalStatus != OperationalStatus.Up)
208 continue;
209
210 string nicInterfaceType = nic.NetworkInterfaceType.ToString();
211 if (!okInterfaceTypes.Contains(nicInterfaceType))
212 {
213 m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.",
214 LogHeader, nic.Name, nicInterfaceType);
215 m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
216 LogHeader, NetworkInterfaceTypes);
217 continue;
218 }
219
220 if (nic.Supports(NetworkInterfaceComponent.IPv4))
221 {
222 IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
223 if (nicStats != null)
224 {
225 MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork,
226 (s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); });
227 MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork,
228 (s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); });
229 MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork,
230 (s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
231 }
232 }
233 // TODO: add IPv6 (it may actually happen someday)
234 }
235 }
236 catch (Exception e)
237 {
238 m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e);
239 }
240
241 MakeStat("ProcessMemory", null, "MB", ContainerMemory,
242 (s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); });
243 MakeStat("HeapMemory", null, "MB", ContainerMemory,
244 (s) => { s.Value = Math.Round(GC.GetTotalMemory(false) / 1024d / 1024d, 3); });
245 MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory,
246 (s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
247 MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory,
248 (s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
249 }
250
251 // Notes on performance counters:
252 // "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx
253 // "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c
254 // "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters
255 private delegate double PerfCounterNextValue();
256 private void GetNextValue(Stat stat, PerfCounterControl perfControl)
257 {
258 GetNextValue(stat, perfControl, 1.0);
259 }
260 private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor)
261 {
262 if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval)
263 {
264 if (perfControl != null && perfControl.perfCounter != null)
265 {
266 try
267 {
268 // Kludge for factor to run double duty. If -1, subtract the value from one
269 if (factor == -1)
270 stat.Value = 1 - perfControl.perfCounter.NextValue();
271 else
272 stat.Value = perfControl.perfCounter.NextValue() / factor;
273 }
274 catch (Exception e)
275 {
276 m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e);
277 }
278 perfControl.lastFetch = Util.EnvironmentTickCount();
279 }
280 }
281 }
282
283 // Lookup the nic that goes with this stat and set the value by using a fetch action.
284 // Not sure about closure with delegates inside delegates.
285 private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
286 private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
287 {
288 // Get the one nic that has the name of this stat
289 IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces().Where(
290 (network) => network.Name == stat.Description);
291 try
292 {
293 foreach (NetworkInterface nic in nics)
294 {
295 IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
296 if (intrStats != null)
297 {
298 double newVal = Math.Round(getter(intrStats) / factor, 3);
299 stat.Value = newVal;
300 }
301 break;
302 }
303 }
304 catch
305 {
306 // There are times interfaces go away so we just won't update the stat for this
307 m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description);
308 }
309 }
310 }
311
312 public class ServerStatsAggregator : Stat
313 {
314 public ServerStatsAggregator(
315 string shortName,
316 string name,
317 string description,
318 string unitName,
319 string category,
320 string container
321 )
322 : base(
323 shortName,
324 name,
325 description,
326 unitName,
327 category,
328 container,
329 StatType.Push,
330 MeasuresOfInterest.None,
331 null,
332 StatVerbosity.Info)
333 {
334 }
335 public override string ToConsoleString()
336 {
337 StringBuilder sb = new StringBuilder();
338
339 return sb.ToString();
340 }
341
342 public override OSDMap ToOSDMap()
343 {
344 OSDMap ret = new OSDMap();
345
346 return ret;
347 }
348 }
349}
diff --git a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
index 6a68322..f6f458d 100644
--- a/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
+++ b/OpenSim/Framework/Monitoring/SimExtraStatsCollector.cs
@@ -27,6 +27,7 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
30using System.Text; 31using System.Text;
31using OpenMetaverse; 32using OpenMetaverse;
32using OpenMetaverse.StructuredData; 33using OpenMetaverse.StructuredData;
@@ -39,8 +40,6 @@ namespace OpenSim.Framework.Monitoring
39 /// </summary> 40 /// </summary>
40 public class SimExtraStatsCollector : BaseStatsCollector 41 public class SimExtraStatsCollector : BaseStatsCollector
41 { 42 {
42 private long abnormalClientThreadTerminations;
43
44// private long assetsInCache; 43// private long assetsInCache;
45// private long texturesInCache; 44// private long texturesInCache;
46// private long assetCacheMemoryUsage; 45// private long assetCacheMemoryUsage;
@@ -73,11 +72,6 @@ namespace OpenSim.Framework.Monitoring
73 private volatile float activeScripts; 72 private volatile float activeScripts;
74 private volatile float scriptLinesPerSecond; 73 private volatile float scriptLinesPerSecond;
75 74
76 /// <summary>
77 /// Number of times that a client thread terminated because of an exception
78 /// </summary>
79 public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } }
80
81// /// <summary> 75// /// <summary>
82// /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the 76// /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the
83// /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these 77// /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these
@@ -166,11 +160,6 @@ namespace OpenSim.Framework.Monitoring
166 private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors 160 private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors
167 = new Dictionary<UUID, PacketQueueStatsCollector>(); 161 = new Dictionary<UUID, PacketQueueStatsCollector>();
168 162
169 public void AddAbnormalClientThreadTermination()
170 {
171 abnormalClientThreadTerminations++;
172 }
173
174// public void AddAsset(AssetBase asset) 163// public void AddAsset(AssetBase asset)
175// { 164// {
176// assetsInCache++; 165// assetsInCache++;
@@ -324,10 +313,12 @@ Asset service request failures: {3}" + Environment.NewLine,
324 sb.Append(Environment.NewLine); 313 sb.Append(Environment.NewLine);
325 sb.Append("CONNECTION STATISTICS"); 314 sb.Append("CONNECTION STATISTICS");
326 sb.Append(Environment.NewLine); 315 sb.Append(Environment.NewLine);
327 sb.Append( 316
328 string.Format( 317 List<Stat> stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives");
329 "Abnormal client thread terminations: {0}" + Environment.NewLine, 318
330 abnormalClientThreadTerminations)); 319 sb.AppendFormat(
320 "Client logouts due to no data receive timeout: {0}\n\n",
321 stats != null ? stats.Sum(s => s.Value).ToString() : "unknown");
331 322
332// sb.Append(Environment.NewLine); 323// sb.Append(Environment.NewLine);
333// sb.Append("INVENTORY STATISTICS"); 324// sb.Append("INVENTORY STATISTICS");
@@ -338,7 +329,7 @@ Asset service request failures: {3}" + Environment.NewLine,
338// InventoryServiceRetrievalFailures)); 329// InventoryServiceRetrievalFailures));
339 330
340 sb.Append(Environment.NewLine); 331 sb.Append(Environment.NewLine);
341 sb.Append("FRAME STATISTICS"); 332 sb.Append("SAMPLE FRAME STATISTICS");
342 sb.Append(Environment.NewLine); 333 sb.Append(Environment.NewLine);
343 sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS"); 334 sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS");
344 sb.Append(Environment.NewLine); 335 sb.Append(Environment.NewLine);
diff --git a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs
index caea30d..318cf1c 100755
--- a/OpenSim/Framework/Monitoring/Stats/CounterStat.cs
+++ b/OpenSim/Framework/Monitoring/Stats/CounterStat.cs
@@ -34,142 +34,6 @@ using OpenMetaverse.StructuredData;
34 34
35namespace OpenSim.Framework.Monitoring 35namespace OpenSim.Framework.Monitoring
36{ 36{
37// Create a time histogram of events. The histogram is built in a wrap-around
38// array of equally distributed buckets.
39// For instance, a minute long histogram of second sized buckets would be:
40// new EventHistogram(60, 1000)
41public class EventHistogram
42{
43 private int m_timeBase;
44 private int m_numBuckets;
45 private int m_bucketMilliseconds;
46 private int m_lastBucket;
47 private int m_totalHistogramMilliseconds;
48 private long[] m_histogram;
49 private object histoLock = new object();
50
51 public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
52 {
53 m_numBuckets = numberOfBuckets;
54 m_bucketMilliseconds = millisecondsPerBucket;
55 m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
56
57 m_histogram = new long[m_numBuckets];
58 Zero();
59 m_lastBucket = 0;
60 m_timeBase = Util.EnvironmentTickCount();
61 }
62
63 public void Event()
64 {
65 this.Event(1);
66 }
67
68 // Record an event at time 'now' in the histogram.
69 public void Event(int cnt)
70 {
71 lock (histoLock)
72 {
73 // The time as displaced from the base of the histogram
74 int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
75
76 // If more than the total time of the histogram, we just start over
77 if (bucketTime > m_totalHistogramMilliseconds)
78 {
79 Zero();
80 m_lastBucket = 0;
81 m_timeBase = Util.EnvironmentTickCount();
82 }
83 else
84 {
85 // To which bucket should we add this event?
86 int bucket = bucketTime / m_bucketMilliseconds;
87
88 // Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
89 while (bucket != m_lastBucket)
90 {
91 // Zero from just after the last bucket to the new bucket or the end
92 for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
93 {
94 m_histogram[jj] = 0;
95 }
96 m_lastBucket = bucket;
97 // If the new bucket is off the end, wrap around to the beginning
98 if (bucket > m_numBuckets)
99 {
100 bucket -= m_numBuckets;
101 m_lastBucket = 0;
102 m_histogram[m_lastBucket] = 0;
103 m_timeBase += m_totalHistogramMilliseconds;
104 }
105 }
106 }
107 m_histogram[m_lastBucket] += cnt;
108 }
109 }
110
111 // Get a copy of the current histogram
112 public long[] GetHistogram()
113 {
114 long[] ret = new long[m_numBuckets];
115 lock (histoLock)
116 {
117 int indx = m_lastBucket + 1;
118 for (int ii = 0; ii < m_numBuckets; ii++, indx++)
119 {
120 if (indx >= m_numBuckets)
121 indx = 0;
122 ret[ii] = m_histogram[indx];
123 }
124 }
125 return ret;
126 }
127
128 public OSDMap GetHistogramAsOSDMap()
129 {
130 OSDMap ret = new OSDMap();
131
132 ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
133 ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
134 ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
135
136 // Compute a number for the first bucket in the histogram.
137 // This will allow readers to know how this histogram relates to any previously read histogram.
138 int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
139 ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
140
141 ret.Add("Values", GetHistogramAsOSDArray());
142
143 return ret;
144 }
145 // Get a copy of the current histogram
146 public OSDArray GetHistogramAsOSDArray()
147 {
148 OSDArray ret = new OSDArray(m_numBuckets);
149 lock (histoLock)
150 {
151 int indx = m_lastBucket + 1;
152 for (int ii = 0; ii < m_numBuckets; ii++, indx++)
153 {
154 if (indx >= m_numBuckets)
155 indx = 0;
156 ret[ii] = OSD.FromLong(m_histogram[indx]);
157 }
158 }
159 return ret;
160 }
161
162 // Zero out the histogram
163 public void Zero()
164 {
165 lock (histoLock)
166 {
167 for (int ii = 0; ii < m_numBuckets; ii++)
168 m_histogram[ii] = 0;
169 }
170 }
171}
172
173// A statistic that wraps a counter. 37// A statistic that wraps a counter.
174// Built this way mostly so histograms and history can be created. 38// Built this way mostly so histograms and history can be created.
175public class CounterStat : Stat 39public class CounterStat : Stat
@@ -224,5 +88,32 @@ public class CounterStat : Stat
224 } 88 }
225 } 89 }
226 } 90 }
91
92 // CounterStat is a basic stat plus histograms
93 public override OSDMap ToOSDMap()
94 {
95 // Get the foundational instance
96 OSDMap map = base.ToOSDMap();
97
98 map["StatType"] = "CounterStat";
99
100 // If there are any histograms, add a new field that is an array of histograms as OSDMaps
101 if (m_histograms.Count > 0)
102 {
103 lock (counterLock)
104 {
105 if (m_histograms.Count > 0)
106 {
107 OSDArray histos = new OSDArray();
108 foreach (EventHistogram histo in m_histograms.Values)
109 {
110 histos.Add(histo.GetHistogramAsOSDMap());
111 }
112 map.Add("Histograms", histos);
113 }
114 }
115 }
116 return map;
117 }
227} 118}
228} 119}
diff --git a/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs
new file mode 100755
index 0000000..f51f322
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/Stats/EventHistogram.cs
@@ -0,0 +1,173 @@
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 OpenSimulator 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
28using System;
29using System.Collections.Generic;
30using System.Linq;
31using System.Text;
32
33using OpenMetaverse.StructuredData;
34
35namespace OpenSim.Framework.Monitoring
36{
37// Create a time histogram of events. The histogram is built in a wrap-around
38// array of equally distributed buckets.
39// For instance, a minute long histogram of second sized buckets would be:
40// new EventHistogram(60, 1000)
41public class EventHistogram
42{
43 private int m_timeBase;
44 private int m_numBuckets;
45 private int m_bucketMilliseconds;
46 private int m_lastBucket;
47 private int m_totalHistogramMilliseconds;
48 private long[] m_histogram;
49 private object histoLock = new object();
50
51 public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
52 {
53 m_numBuckets = numberOfBuckets;
54 m_bucketMilliseconds = millisecondsPerBucket;
55 m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
56
57 m_histogram = new long[m_numBuckets];
58 Zero();
59 m_lastBucket = 0;
60 m_timeBase = Util.EnvironmentTickCount();
61 }
62
63 public void Event()
64 {
65 this.Event(1);
66 }
67
68 // Record an event at time 'now' in the histogram.
69 public void Event(int cnt)
70 {
71 lock (histoLock)
72 {
73 // The time as displaced from the base of the histogram
74 int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
75
76 // If more than the total time of the histogram, we just start over
77 if (bucketTime > m_totalHistogramMilliseconds)
78 {
79 Zero();
80 m_lastBucket = 0;
81 m_timeBase = Util.EnvironmentTickCount();
82 }
83 else
84 {
85 // To which bucket should we add this event?
86 int bucket = bucketTime / m_bucketMilliseconds;
87
88 // Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
89 while (bucket != m_lastBucket)
90 {
91 // Zero from just after the last bucket to the new bucket or the end
92 for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
93 {
94 m_histogram[jj] = 0;
95 }
96 m_lastBucket = bucket;
97 // If the new bucket is off the end, wrap around to the beginning
98 if (bucket > m_numBuckets)
99 {
100 bucket -= m_numBuckets;
101 m_lastBucket = 0;
102 m_histogram[m_lastBucket] = 0;
103 m_timeBase += m_totalHistogramMilliseconds;
104 }
105 }
106 }
107 m_histogram[m_lastBucket] += cnt;
108 }
109 }
110
111 // Get a copy of the current histogram
112 public long[] GetHistogram()
113 {
114 long[] ret = new long[m_numBuckets];
115 lock (histoLock)
116 {
117 int indx = m_lastBucket + 1;
118 for (int ii = 0; ii < m_numBuckets; ii++, indx++)
119 {
120 if (indx >= m_numBuckets)
121 indx = 0;
122 ret[ii] = m_histogram[indx];
123 }
124 }
125 return ret;
126 }
127
128 public OSDMap GetHistogramAsOSDMap()
129 {
130 OSDMap ret = new OSDMap();
131
132 ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
133 ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
134 ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
135
136 // Compute a number for the first bucket in the histogram.
137 // This will allow readers to know how this histogram relates to any previously read histogram.
138 int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
139 ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
140
141 ret.Add("Values", GetHistogramAsOSDArray());
142
143 return ret;
144 }
145 // Get a copy of the current histogram
146 public OSDArray GetHistogramAsOSDArray()
147 {
148 OSDArray ret = new OSDArray(m_numBuckets);
149 lock (histoLock)
150 {
151 int indx = m_lastBucket + 1;
152 for (int ii = 0; ii < m_numBuckets; ii++, indx++)
153 {
154 if (indx >= m_numBuckets)
155 indx = 0;
156 ret[ii] = OSD.FromLong(m_histogram[indx]);
157 }
158 }
159 return ret;
160 }
161
162 // Zero out the histogram
163 public void Zero()
164 {
165 lock (histoLock)
166 {
167 for (int ii = 0; ii < m_numBuckets; ii++)
168 m_histogram[ii] = 0;
169 }
170 }
171}
172
173}
diff --git a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs
index 60bed55..55ddf06 100644
--- a/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs
+++ b/OpenSim/Framework/Monitoring/Stats/PercentageStat.cs
@@ -29,6 +29,8 @@ using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Text; 30using System.Text;
31 31
32using OpenMetaverse.StructuredData;
33
32namespace OpenSim.Framework.Monitoring 34namespace OpenSim.Framework.Monitoring
33{ 35{
34 public class PercentageStat : Stat 36 public class PercentageStat : Stat
@@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring
84 86
85 return sb.ToString(); 87 return sb.ToString();
86 } 88 }
89
90 // PercentageStat is a basic stat plus percent calc
91 public override OSDMap ToOSDMap()
92 {
93 // Get the foundational instance
94 OSDMap map = base.ToOSDMap();
95
96 map["StatType"] = "PercentageStat";
97
98 map.Add("Antecedent", OSD.FromLong(Antecedent));
99 map.Add("Consequent", OSD.FromLong(Consequent));
100
101 return map;
102 }
87 } 103 }
88} \ No newline at end of file 104} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/Stats/Stat.cs b/OpenSim/Framework/Monitoring/Stats/Stat.cs
index 2e7665f..2b34493 100644
--- a/OpenSim/Framework/Monitoring/Stats/Stat.cs
+++ b/OpenSim/Framework/Monitoring/Stats/Stat.cs
@@ -27,8 +27,10 @@
27 27
28using System; 28using System;
29using System.Collections.Generic; 29using System.Collections.Generic;
30using System.Linq;
31using System.Reflection;
30using System.Text; 32using System.Text;
31 33using log4net;
32using OpenMetaverse.StructuredData; 34using OpenMetaverse.StructuredData;
33 35
34namespace OpenSim.Framework.Monitoring 36namespace OpenSim.Framework.Monitoring
@@ -38,6 +40,10 @@ namespace OpenSim.Framework.Monitoring
38 /// </summary> 40 /// </summary>
39 public class Stat : IDisposable 41 public class Stat : IDisposable
40 { 42 {
43// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
44
45 public static readonly char[] DisallowedShortNameCharacters = { '.' };
46
41 /// <summary> 47 /// <summary>
42 /// Category of this stat (e.g. cache, scene, etc). 48 /// Category of this stat (e.g. cache, scene, etc).
43 /// </summary> 49 /// </summary>
@@ -95,7 +101,7 @@ namespace OpenSim.Framework.Monitoring
95 /// <remarks> 101 /// <remarks>
96 /// Will be null if no measures of interest require samples. 102 /// Will be null if no measures of interest require samples.
97 /// </remarks> 103 /// </remarks>
98 private static Queue<double> m_samples; 104 private Queue<double> m_samples;
99 105
100 /// <summary> 106 /// <summary>
101 /// Maximum number of statistical samples. 107 /// Maximum number of statistical samples.
@@ -162,6 +168,12 @@ namespace OpenSim.Framework.Monitoring
162 throw new Exception( 168 throw new Exception(
163 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category)); 169 string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
164 170
171 foreach (char c in DisallowedShortNameCharacters)
172 {
173 if (shortName.IndexOf(c) != -1)
174 throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
175 }
176
165 ShortName = shortName; 177 ShortName = shortName;
166 Name = name; 178 Name = name;
167 Description = description; 179 Description = description;
@@ -204,6 +216,8 @@ namespace OpenSim.Framework.Monitoring
204 if (m_samples.Count >= m_maxSamples) 216 if (m_samples.Count >= m_maxSamples)
205 m_samples.Dequeue(); 217 m_samples.Dequeue();
206 218
219// m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name);
220
207 m_samples.Enqueue(newValue); 221 m_samples.Enqueue(newValue);
208 } 222 }
209 } 223 }
@@ -211,7 +225,13 @@ namespace OpenSim.Framework.Monitoring
211 public virtual string ToConsoleString() 225 public virtual string ToConsoleString()
212 { 226 {
213 StringBuilder sb = new StringBuilder(); 227 StringBuilder sb = new StringBuilder();
214 sb.AppendFormat("{0}.{1}.{2} : {3} {4}", Category, Container, ShortName, Value, UnitName); 228 sb.AppendFormat(
229 "{0}.{1}.{2} : {3}{4}",
230 Category,
231 Container,
232 ShortName,
233 Value,
234 UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName));
215 235
216 AppendMeasuresOfInterest(sb); 236 AppendMeasuresOfInterest(sb);
217 237
@@ -221,6 +241,8 @@ namespace OpenSim.Framework.Monitoring
221 public virtual OSDMap ToOSDMap() 241 public virtual OSDMap ToOSDMap()
222 { 242 {
223 OSDMap ret = new OSDMap(); 243 OSDMap ret = new OSDMap();
244 ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
245
224 ret.Add("Category", OSD.FromString(Category)); 246 ret.Add("Category", OSD.FromString(Category));
225 ret.Add("Container", OSD.FromString(Container)); 247 ret.Add("Container", OSD.FromString(Container));
226 ret.Add("ShortName", OSD.FromString(ShortName)); 248 ret.Add("ShortName", OSD.FromString(ShortName));
@@ -229,31 +251,74 @@ namespace OpenSim.Framework.Monitoring
229 ret.Add("UnitName", OSD.FromString(UnitName)); 251 ret.Add("UnitName", OSD.FromString(UnitName));
230 ret.Add("Value", OSD.FromReal(Value)); 252 ret.Add("Value", OSD.FromReal(Value));
231 253
254 double lastChangeOverTime, averageChangeOverTime;
255 if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
256 {
257 ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime));
258 ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime));
259 }
260
232 return ret; 261 return ret;
233 } 262 }
234 263
235 protected void AppendMeasuresOfInterest(StringBuilder sb) 264 // Compute the averages over time and return same.
265 // Return 'true' if averages were actually computed. 'false' if no average info.
266 public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime)
236 { 267 {
237 if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) 268 bool ret = false;
238 == MeasuresOfInterest.AverageChangeOverTime) 269 lastChangeOverTime = 0;
270 averageChangeOverTime = 0;
271
272 if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
239 { 273 {
240 double totalChange = 0; 274 double totalChange = 0;
275 double? penultimateSample = null;
241 double? lastSample = null; 276 double? lastSample = null;
242 277
243 lock (m_samples) 278 lock (m_samples)
244 { 279 {
280 // m_log.DebugFormat(
281 // "[STAT]: Samples for {0} are {1}",
282 // Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
283
245 foreach (double s in m_samples) 284 foreach (double s in m_samples)
246 { 285 {
247 if (lastSample != null) 286 if (lastSample != null)
248 totalChange += s - (double)lastSample; 287 totalChange += s - (double)lastSample;
249 288
289 penultimateSample = lastSample;
250 lastSample = s; 290 lastSample = s;
251 } 291 }
252 } 292 }
253 293
294 if (lastSample != null && penultimateSample != null)
295 {
296 lastChangeOverTime
297 = ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
298 }
299
254 int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1; 300 int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
255 301
256 sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName); 302 averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
303 ret = true;
304 }
305
306 return ret;
307 }
308
309 protected void AppendMeasuresOfInterest(StringBuilder sb)
310 {
311 double lastChangeOverTime = 0;
312 double averageChangeOverTime = 0;
313
314 if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
315 {
316 sb.AppendFormat(
317 ", {0:0.##}{1}/s, {2:0.##}{3}/s",
318 lastChangeOverTime,
319 UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName),
320 averageChangeOverTime,
321 UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName));
257 } 322 }
258 } 323 }
259 } 324 }
diff --git a/OpenSim/Framework/Monitoring/StatsLogger.cs b/OpenSim/Framework/Monitoring/StatsLogger.cs
new file mode 100644
index 0000000..1e4fa11
--- /dev/null
+++ b/OpenSim/Framework/Monitoring/StatsLogger.cs
@@ -0,0 +1,108 @@
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 OpenSimulator 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
28using System;
29using System.Reflection;
30using System.Timers;
31using log4net;
32
33namespace OpenSim.Framework.Monitoring
34{
35 /// <summary>
36 /// Provides a means to continuously log stats for debugging purposes.
37 /// </summary>
38 public static class StatsLogger
39 {
40 private static readonly ILog m_statsLog = LogManager.GetLogger("special.StatsLogger");
41
42 private static Timer m_loggingTimer;
43 private static int m_statsLogIntervalMs = 5000;
44
45 public static void RegisterConsoleCommands(ICommandConsole console)
46 {
47 console.Commands.AddCommand(
48 "Debug",
49 false,
50 "debug stats record",
51 "debug stats record start|stop",
52 "Control whether stats are being regularly recorded to a separate file.",
53 "For debug purposes. Experimental.",
54 HandleStatsRecordCommand);
55 }
56
57 public static void HandleStatsRecordCommand(string module, string[] cmd)
58 {
59 ICommandConsole con = MainConsole.Instance;
60
61 if (cmd.Length != 4)
62 {
63 con.Output("Usage: debug stats record start|stop");
64 return;
65 }
66
67 if (cmd[3] == "start")
68 {
69 Start();
70 con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs);
71 }
72 else if (cmd[3] == "stop")
73 {
74 Stop();
75 con.Output("Stopped recording stats to file.");
76 }
77 }
78
79 public static void Start()
80 {
81 if (m_loggingTimer != null)
82 Stop();
83
84 m_loggingTimer = new Timer(m_statsLogIntervalMs);
85 m_loggingTimer.AutoReset = false;
86 m_loggingTimer.Elapsed += Log;
87 m_loggingTimer.Start();
88 }
89
90 public static void Stop()
91 {
92 if (m_loggingTimer != null)
93 {
94 m_loggingTimer.Stop();
95 }
96 }
97
98 private static void Log(object sender, ElapsedEventArgs e)
99 {
100 m_statsLog.InfoFormat("*** STATS REPORT AT {0} ***", DateTime.Now);
101
102 foreach (string report in StatsManager.GetAllStatsReports())
103 m_statsLog.Info(report);
104
105 m_loggingTimer.Start();
106 }
107 }
108} \ No newline at end of file
diff --git a/OpenSim/Framework/Monitoring/StatsManager.cs b/OpenSim/Framework/Monitoring/StatsManager.cs
index 24db6d4..05ee4c5 100644
--- a/OpenSim/Framework/Monitoring/StatsManager.cs
+++ b/OpenSim/Framework/Monitoring/StatsManager.cs
@@ -26,15 +26,20 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
29using System.Collections.Generic; 30using System.Collections.Generic;
31using System.Linq;
30using System.Text; 32using System.Text;
31 33
34using OpenSim.Framework;
35using OpenMetaverse.StructuredData;
36
32namespace OpenSim.Framework.Monitoring 37namespace OpenSim.Framework.Monitoring
33{ 38{
34 /// <summary> 39 /// <summary>
35 /// Singleton used to provide access to statistics reporters 40 /// Static class used to register/deregister/fetch statistics
36 /// </summary> 41 /// </summary>
37 public class StatsManager 42 public static class StatsManager
38 { 43 {
39 // Subcommand used to list other stats. 44 // Subcommand used to list other stats.
40 public const string AllSubCommand = "all"; 45 public const string AllSubCommand = "all";
@@ -54,13 +59,13 @@ namespace OpenSim.Framework.Monitoring
54 public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>> RegisteredStats 59 public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>> RegisteredStats
55 = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>>(); 60 = new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>>();
56 61
57 private static AssetStatsCollector assetStats; 62// private static AssetStatsCollector assetStats;
58 private static UserStatsCollector userStats; 63// private static UserStatsCollector userStats;
59 private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector(); 64// private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
60 65
61 public static AssetStatsCollector AssetStats { get { return assetStats; } } 66// public static AssetStatsCollector AssetStats { get { return assetStats; } }
62 public static UserStatsCollector UserStats { get { return userStats; } } 67// public static UserStatsCollector UserStats { get { return userStats; } }
63 public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } } 68 public static SimExtraStatsCollector SimExtraStats { get; set; }
64 69
65 public static void RegisterConsoleCommands(ICommandConsole console) 70 public static void RegisterConsoleCommands(ICommandConsole console)
66 { 71 {
@@ -68,14 +73,18 @@ namespace OpenSim.Framework.Monitoring
68 "General", 73 "General",
69 false, 74 false,
70 "show stats", 75 "show stats",
71 "show stats [list|all|<category>]", 76 "show stats [list|all|(<category>[.<container>])+",
72 "Show statistical information for this server", 77 "Show statistical information for this server",
73 "If no final argument is specified then legacy statistics information is currently shown.\n" 78 "If no final argument is specified then legacy statistics information is currently shown.\n"
74 + "If list is specified then statistic categories are shown.\n" 79 + "'list' argument will show statistic categories.\n"
75 + "If all is specified then all registered statistics are shown.\n" 80 + "'all' will show all statistics.\n"
76 + "If a category name is specified then only statistics from that category are shown.\n" 81 + "A <category> name will show statistics from that category.\n"
82 + "A <category>.<container> name will show statistics from that category in that container.\n"
83 + "More than one name can be given separated by spaces.\n"
77 + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS", 84 + "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
78 HandleShowStatsCommand); 85 HandleShowStatsCommand);
86
87 StatsLogger.RegisterConsoleCommands(console);
79 } 88 }
80 89
81 public static void HandleShowStatsCommand(string module, string[] cmd) 90 public static void HandleShowStatsCommand(string module, string[] cmd)
@@ -84,43 +93,47 @@ namespace OpenSim.Framework.Monitoring
84 93
85 if (cmd.Length > 2) 94 if (cmd.Length > 2)
86 { 95 {
87 var categoryName = cmd[2]; 96 foreach (string name in cmd.Skip(2))
88 var containerName = cmd.Length > 3 ? cmd[3] : String.Empty;
89
90 if (categoryName == AllSubCommand)
91 { 97 {
92 foreach (var category in RegisteredStats.Values) 98 string[] components = name.Split('.');
99
100 string categoryName = components[0];
101 string containerName = components.Length > 1 ? components[1] : null;
102
103 if (categoryName == AllSubCommand)
93 { 104 {
94 OutputCategoryStatsToConsole(con, category); 105 OutputAllStatsToConsole(con);
95 } 106 }
96 } 107 else if (categoryName == ListSubCommand)
97 else if (categoryName == ListSubCommand)
98 {
99 con.Output("Statistic categories available are:");
100 foreach (string category in RegisteredStats.Keys)
101 con.OutputFormat(" {0}", category);
102 }
103 else
104 {
105 SortedDictionary<string, SortedDictionary<string, Stat>> category;
106 if (!RegisteredStats.TryGetValue(categoryName, out category))
107 { 108 {
108 con.OutputFormat("No such category as {0}", categoryName); 109 con.Output("Statistic categories available are:");
110 foreach (string category in RegisteredStats.Keys)
111 con.OutputFormat(" {0}", category);
109 } 112 }
110 else 113 else
111 { 114 {
112 if (String.IsNullOrEmpty(containerName)) 115 SortedDictionary<string, SortedDictionary<string, Stat>> category;
113 OutputCategoryStatsToConsole(con, category); 116 if (!RegisteredStats.TryGetValue(categoryName, out category))
117 {
118 con.OutputFormat("No such category as {0}", categoryName);
119 }
114 else 120 else
115 { 121 {
116 SortedDictionary<string, Stat> container; 122 if (String.IsNullOrEmpty(containerName))
117 if (category.TryGetValue(containerName, out container))
118 { 123 {
119 OutputContainerStatsToConsole(con, container); 124 OutputCategoryStatsToConsole(con, category);
120 } 125 }
121 else 126 else
122 { 127 {
123 con.OutputFormat("No such container {0} in category {1}", containerName, categoryName); 128 SortedDictionary<string, Stat> container;
129 if (category.TryGetValue(containerName, out container))
130 {
131 OutputContainerStatsToConsole(con, container);
132 }
133 else
134 {
135 con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
136 }
124 } 137 }
125 } 138 }
126 } 139 }
@@ -129,51 +142,187 @@ namespace OpenSim.Framework.Monitoring
129 else 142 else
130 { 143 {
131 // Legacy 144 // Legacy
132 con.Output(SimExtraStats.Report()); 145 if (SimExtraStats != null)
146 con.Output(SimExtraStats.Report());
147 else
148 OutputAllStatsToConsole(con);
133 } 149 }
134 } 150 }
135 151
152 public static List<string> GetAllStatsReports()
153 {
154 List<string> reports = new List<string>();
155
156 foreach (var category in RegisteredStats.Values)
157 reports.AddRange(GetCategoryStatsReports(category));
158
159 return reports;
160 }
161
162 private static void OutputAllStatsToConsole(ICommandConsole con)
163 {
164 foreach (string report in GetAllStatsReports())
165 con.Output(report);
166 }
167
168 private static List<string> GetCategoryStatsReports(
169 SortedDictionary<string, SortedDictionary<string, Stat>> category)
170 {
171 List<string> reports = new List<string>();
172
173 foreach (var container in category.Values)
174 reports.AddRange(GetContainerStatsReports(container));
175
176 return reports;
177 }
178
136 private static void OutputCategoryStatsToConsole( 179 private static void OutputCategoryStatsToConsole(
137 ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category) 180 ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category)
138 { 181 {
139 foreach (var container in category.Values) 182 foreach (string report in GetCategoryStatsReports(category))
140 { 183 con.Output(report);
141 OutputContainerStatsToConsole(con, container);
142 }
143 } 184 }
144 185
145 private static void OutputContainerStatsToConsole( ICommandConsole con, SortedDictionary<string, Stat> container) 186 private static List<string> GetContainerStatsReports(SortedDictionary<string, Stat> container)
146 { 187 {
188 List<string> reports = new List<string>();
189
147 foreach (Stat stat in container.Values) 190 foreach (Stat stat in container.Values)
148 { 191 reports.Add(stat.ToConsoleString());
149 con.Output(stat.ToConsoleString()); 192
150 } 193 return reports;
151 } 194 }
152 195
153 /// <summary> 196 private static void OutputContainerStatsToConsole(
154 /// Start collecting statistics related to assets. 197 ICommandConsole con, SortedDictionary<string, Stat> container)
155 /// Should only be called once. 198 {
156 /// </summary> 199 foreach (string report in GetContainerStatsReports(container))
157 public static AssetStatsCollector StartCollectingAssetStats() 200 con.Output(report);
201 }
202
203 // Creates an OSDMap of the format:
204 // { categoryName: {
205 // containerName: {
206 // statName: {
207 // "Name": name,
208 // "ShortName": shortName,
209 // ...
210 // },
211 // statName: {
212 // "Name": name,
213 // "ShortName": shortName,
214 // ...
215 // },
216 // ...
217 // },
218 // containerName: {
219 // ...
220 // },
221 // ...
222 // },
223 // categoryName: {
224 // ...
225 // },
226 // ...
227 // }
228 // The passed in parameters will filter the categories, containers and stats returned. If any of the
229 // parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned.
230 // Case matters.
231 public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName)
158 { 232 {
159 assetStats = new AssetStatsCollector(); 233 OSDMap map = new OSDMap();
234
235 foreach (string catName in RegisteredStats.Keys)
236 {
237 // Do this category if null spec, "all" subcommand or category name matches passed parameter.
238 // Skip category if none of the above.
239 if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName))
240 continue;
160 241
161 return assetStats; 242 OSDMap contMap = new OSDMap();
243 foreach (string contName in RegisteredStats[catName].Keys)
244 {
245 if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName))
246 continue;
247
248 OSDMap statMap = new OSDMap();
249
250 SortedDictionary<string, Stat> theStats = RegisteredStats[catName][contName];
251 foreach (string statName in theStats.Keys)
252 {
253 if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName))
254 continue;
255
256 statMap.Add(statName, theStats[statName].ToOSDMap());
257 }
258
259 contMap.Add(contName, statMap);
260 }
261 map.Add(catName, contMap);
262 }
263
264 return map;
162 } 265 }
163 266
164 /// <summary> 267 public static Hashtable HandleStatsRequest(Hashtable request)
165 /// Start collecting statistics related to users.
166 /// Should only be called once.
167 /// </summary>
168 public static UserStatsCollector StartCollectingUserStats()
169 { 268 {
170 userStats = new UserStatsCollector(); 269 Hashtable responsedata = new Hashtable();
270// string regpath = request["uri"].ToString();
271 int response_code = 200;
272 string contenttype = "text/json";
273
274 string pCategoryName = StatsManager.AllSubCommand;
275 string pContainerName = StatsManager.AllSubCommand;
276 string pStatName = StatsManager.AllSubCommand;
277
278 if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString();
279 if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString();
280 if (request.ContainsKey("stat")) pStatName = request["cat"].ToString();
281
282 string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString();
283
284 // If requestor wants it as a callback function, build response as a function rather than just the JSON string.
285 if (request.ContainsKey("callback"))
286 {
287 strOut = request["callback"].ToString() + "(" + strOut + ");";
288 }
171 289
172 return userStats; 290 // m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}",
291 // LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut);
292
293 responsedata["int_response_code"] = response_code;
294 responsedata["content_type"] = contenttype;
295 responsedata["keepalive"] = false;
296 responsedata["str_response_string"] = strOut;
297 responsedata["access_control_allow_origin"] = "*";
298
299 return responsedata;
173 } 300 }
174 301
302// /// <summary>
303// /// Start collecting statistics related to assets.
304// /// Should only be called once.
305// /// </summary>
306// public static AssetStatsCollector StartCollectingAssetStats()
307// {
308// assetStats = new AssetStatsCollector();
309//
310// return assetStats;
311// }
312//
313// /// <summary>
314// /// Start collecting statistics related to users.
315// /// Should only be called once.
316// /// </summary>
317// public static UserStatsCollector StartCollectingUserStats()
318// {
319// userStats = new UserStatsCollector();
320//
321// return userStats;
322// }
323
175 /// <summary> 324 /// <summary>
176 /// Registers a statistic. 325 /// Register a statistic.
177 /// </summary> 326 /// </summary>
178 /// <param name='stat'></param> 327 /// <param name='stat'></param>
179 /// <returns></returns> 328 /// <returns></returns>
@@ -187,7 +336,7 @@ namespace OpenSim.Framework.Monitoring
187 // Stat name is not unique across category/container/shortname key. 336 // Stat name is not unique across category/container/shortname key.
188 // XXX: For now just return false. This is to avoid problems in regression tests where all tests 337 // XXX: For now just return false. This is to avoid problems in regression tests where all tests
189 // in a class are run in the same instance of the VM. 338 // in a class are run in the same instance of the VM.
190 if (TryGetStat(stat, out category, out container)) 339 if (TryGetStatParents(stat, out category, out container))
191 return false; 340 return false;
192 341
193 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed. 342 // We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
@@ -223,7 +372,7 @@ namespace OpenSim.Framework.Monitoring
223 372
224 lock (RegisteredStats) 373 lock (RegisteredStats)
225 { 374 {
226 if (!TryGetStat(stat, out category, out container)) 375 if (!TryGetStatParents(stat, out category, out container))
227 return false; 376 return false;
228 377
229 newContainer = new SortedDictionary<string, Stat>(container); 378 newContainer = new SortedDictionary<string, Stat>(container);
@@ -239,12 +388,67 @@ namespace OpenSim.Framework.Monitoring
239 } 388 }
240 } 389 }
241 390
242 public static bool TryGetStats(string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats) 391 public static bool TryGetStat(string category, string container, string statShortName, out Stat stat)
243 { 392 {
244 return RegisteredStats.TryGetValue(category, out stats); 393 stat = null;
394 SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
395
396 lock (RegisteredStats)
397 {
398 if (!TryGetStatsForCategory(category, out categoryStats))
399 return false;
400
401 SortedDictionary<string, Stat> containerStats;
402
403 if (!categoryStats.TryGetValue(container, out containerStats))
404 return false;
405
406 return containerStats.TryGetValue(statShortName, out stat);
407 }
408 }
409
410 public static bool TryGetStatsForCategory(
411 string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats)
412 {
413 lock (RegisteredStats)
414 return RegisteredStats.TryGetValue(category, out stats);
415 }
416
417 /// <summary>
418 /// Get the same stat for each container in a given category.
419 /// </summary>
420 /// <returns>
421 /// The stats if there were any to fetch. Otherwise null.
422 /// </returns>
423 /// <param name='category'></param>
424 /// <param name='statShortName'></param>
425 public static List<Stat> GetStatsFromEachContainer(string category, string statShortName)
426 {
427 SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
428
429 lock (RegisteredStats)
430 {
431 if (!RegisteredStats.TryGetValue(category, out categoryStats))
432 return null;
433
434 List<Stat> stats = null;
435
436 foreach (SortedDictionary<string, Stat> containerStats in categoryStats.Values)
437 {
438 if (containerStats.ContainsKey(statShortName))
439 {
440 if (stats == null)
441 stats = new List<Stat>();
442
443 stats.Add(containerStats[statShortName]);
444 }
445 }
446
447 return stats;
448 }
245 } 449 }
246 450
247 public static bool TryGetStat( 451 public static bool TryGetStatParents(
248 Stat stat, 452 Stat stat,
249 out SortedDictionary<string, SortedDictionary<string, Stat>> category, 453 out SortedDictionary<string, SortedDictionary<string, Stat>> category,
250 out SortedDictionary<string, Stat> container) 454 out SortedDictionary<string, Stat> container)
diff --git a/OpenSim/Framework/Monitoring/Watchdog.cs b/OpenSim/Framework/Monitoring/Watchdog.cs
index 69d2db5..32724ec 100644
--- a/OpenSim/Framework/Monitoring/Watchdog.cs
+++ b/OpenSim/Framework/Monitoring/Watchdog.cs
@@ -380,6 +380,7 @@ namespace OpenSim.Framework.Monitoring
380 if (MemoryWatchdog.Enabled) 380 if (MemoryWatchdog.Enabled)
381 MemoryWatchdog.Update(); 381 MemoryWatchdog.Update();
382 382
383 ChecksManager.CheckChecks();
383 StatsManager.RecordStats(); 384 StatsManager.RecordStats();
384 385
385 m_watchdogTimer.Start(); 386 m_watchdogTimer.Start();
diff --git a/OpenSim/Framework/RegionFlags.cs b/OpenSim/Framework/RegionFlags.cs
index a3089b0..7c6569e 100644
--- a/OpenSim/Framework/RegionFlags.cs
+++ b/OpenSim/Framework/RegionFlags.cs
@@ -48,6 +48,7 @@ namespace OpenSim.Framework
48 NoMove = 64, // Don't allow moving this region 48 NoMove = 64, // Don't allow moving this region
49 Reservation = 128, // This is an inactive reservation 49 Reservation = 128, // This is an inactive reservation
50 Authenticate = 256, // Require authentication 50 Authenticate = 256, // Require authentication
51 Hyperlink = 512 // Record represents a HG link 51 Hyperlink = 512, // Record represents a HG link
52 DefaultHGRegion = 1024 // Record represents a default region for hypergrid teleports only.
52 } 53 }
53} \ No newline at end of file 54} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index 6c04c69..bfd67c7 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -86,26 +86,23 @@ namespace OpenSim.Framework.Servers
86 /// </summary> 86 /// </summary>
87 protected virtual void StartupSpecific() 87 protected virtual void StartupSpecific()
88 { 88 {
89 if (m_console == null) 89 StatsManager.SimExtraStats = new SimExtraStatsCollector();
90 return;
91
92 RegisterCommonCommands(); 90 RegisterCommonCommands();
93 91 RegisterCommonComponents(Config);
94 m_console.Commands.AddCommand("General", false, "quit", 92 }
95 "quit", 93
96 "Quit the application", HandleQuit); 94 protected override void ShutdownSpecific()
95 {
96 m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting...");
97
98 RemovePIDFile();
97 99
98 m_console.Commands.AddCommand("General", false, "shutdown", 100 base.ShutdownSpecific();
99 "shutdown", 101
100 "Quit the application", HandleQuit); 102 Environment.Exit(0);
101 } 103 }
102 104
103 /// <summary> 105 /// <summary>
104 /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
105 /// </summary>
106 public virtual void ShutdownSpecific() {}
107
108 /// <summary>
109 /// Provides a list of help topics that are available. Overriding classes should append their topics to the 106 /// Provides a list of help topics that are available. Overriding classes should append their topics to the
110 /// information returned when the base method is called. 107 /// information returned when the base method is called.
111 /// </summary> 108 /// </summary>
@@ -153,25 +150,8 @@ namespace OpenSim.Framework.Servers
153 timeTaken.Minutes, timeTaken.Seconds); 150 timeTaken.Minutes, timeTaken.Seconds);
154 } 151 }
155 152
156 /// <summary> 153 public string osSecret
157 /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
158 /// </summary>
159 public virtual void Shutdown()
160 { 154 {
161 ShutdownSpecific();
162
163 m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting...");
164 RemovePIDFile();
165
166 Environment.Exit(0);
167 }
168
169 private void HandleQuit(string module, string[] args)
170 {
171 Shutdown();
172 }
173
174 public string osSecret {
175 // Secret uuid for the simulator 155 // Secret uuid for the simulator
176 get { return m_osSecret; } 156 get { return m_osSecret; }
177 } 157 }
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
index 97035e3..f4b4156 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseHttpServer.cs
@@ -54,7 +54,6 @@ namespace OpenSim.Framework.Servers.HttpServer
54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 54 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
55 private HttpServerLogWriter httpserverlog = new HttpServerLogWriter(); 55 private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
56 56
57
58 /// <summary> 57 /// <summary>
59 /// This is a pending websocket request before it got an sucessful upgrade response. 58 /// This is a pending websocket request before it got an sucessful upgrade response.
60 /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to 59 /// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to
@@ -81,6 +80,11 @@ namespace OpenSim.Framework.Servers.HttpServer
81 /// </remarks> 80 /// </remarks>
82 public int RequestNumber { get; private set; } 81 public int RequestNumber { get; private set; }
83 82
83 /// <summary>
84 /// Statistic for holding number of requests processed.
85 /// </summary>
86 private Stat m_requestsProcessedStat;
87
84 private volatile int NotSocketErrors = 0; 88 private volatile int NotSocketErrors = 0;
85 public volatile bool HTTPDRunning = false; 89 public volatile bool HTTPDRunning = false;
86 90
@@ -383,6 +387,8 @@ namespace OpenSim.Framework.Servers.HttpServer
383 387
384 if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs)) 388 if (TryGetPollServiceHTTPHandler(request.UriPath.ToString(), out psEvArgs))
385 { 389 {
390 psEvArgs.RequestsReceived++;
391
386 PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request); 392 PollServiceHttpRequest psreq = new PollServiceHttpRequest(psEvArgs, context, request);
387 393
388 if (psEvArgs.Request != null) 394 if (psEvArgs.Request != null)
@@ -437,9 +443,8 @@ namespace OpenSim.Framework.Servers.HttpServer
437 } 443 }
438 } 444 }
439 445
440 public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request) 446 private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
441 { 447 {
442
443 OSHttpRequest req = new OSHttpRequest(context, request); 448 OSHttpRequest req = new OSHttpRequest(context, request);
444 WebSocketRequestDelegate dWebSocketRequestDelegate = null; 449 WebSocketRequestDelegate dWebSocketRequestDelegate = null;
445 lock (m_WebSocketHandlers) 450 lock (m_WebSocketHandlers)
@@ -454,9 +459,8 @@ namespace OpenSim.Framework.Servers.HttpServer
454 } 459 }
455 460
456 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context); 461 OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
457 462 resp.ReuseContext = true;
458 HandleRequest(req, resp); 463 HandleRequest(req, resp);
459
460 464
461 // !!!HACK ALERT!!! 465 // !!!HACK ALERT!!!
462 // There seems to be a bug in the underlying http code that makes subsequent requests 466 // There seems to be a bug in the underlying http code that makes subsequent requests
@@ -687,7 +691,7 @@ namespace OpenSim.Framework.Servers.HttpServer
687 691
688 if (buffer != null) 692 if (buffer != null)
689 { 693 {
690 if (!response.SendChunked) 694 if (!response.SendChunked && response.ContentLength64 <= 0)
691 response.ContentLength64 = buffer.LongLength; 695 response.ContentLength64 = buffer.LongLength;
692 696
693 response.OutputStream.Write(buffer, 0, buffer.Length); 697 response.OutputStream.Write(buffer, 0, buffer.Length);
@@ -1850,8 +1854,8 @@ namespace OpenSim.Framework.Servers.HttpServer
1850 m_httpListener2.Start(64); 1854 m_httpListener2.Start(64);
1851 1855
1852 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events 1856 // Long Poll Service Manager with 3 worker threads a 25 second timeout for no events
1853// m_PollServiceManager = new PollServiceRequestManager(this, 3, 25000);
1854 m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000); 1857 m_PollServiceManager = new PollServiceRequestManager(this, 4, 25000);
1858 m_PollServiceManager.Start();
1855 HTTPDRunning = true; 1859 HTTPDRunning = true;
1856 1860
1857 //HttpListenerContext context; 1861 //HttpListenerContext context;
@@ -1870,6 +1874,21 @@ namespace OpenSim.Framework.Servers.HttpServer
1870 // useful without inbound HTTP. 1874 // useful without inbound HTTP.
1871 throw e; 1875 throw e;
1872 } 1876 }
1877
1878 m_requestsProcessedStat
1879 = new Stat(
1880 "HTTPRequestsServed",
1881 "Number of inbound HTTP requests processed",
1882 "",
1883 "requests",
1884 "httpserver",
1885 Port.ToString(),
1886 StatType.Pull,
1887 MeasuresOfInterest.AverageChangeOverTime,
1888 stat => stat.Value = RequestNumber,
1889 StatVerbosity.Debug);
1890
1891 StatsManager.RegisterStat(m_requestsProcessedStat);
1873 } 1892 }
1874 1893
1875 public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err) 1894 public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err)
@@ -1902,9 +1921,12 @@ namespace OpenSim.Framework.Servers.HttpServer
1902 public void Stop() 1921 public void Stop()
1903 { 1922 {
1904 HTTPDRunning = false; 1923 HTTPDRunning = false;
1924
1925 StatsManager.DeregisterStat(m_requestsProcessedStat);
1926
1905 try 1927 try
1906 { 1928 {
1907// m_PollServiceManager.Stop(); 1929 m_PollServiceManager.Stop();
1908 1930
1909 m_httpListener2.ExceptionThrown -= httpServerException; 1931 m_httpListener2.ExceptionThrown -= httpServerException;
1910 //m_httpListener2.DisconnectHandler = null; 1932 //m_httpListener2.DisconnectHandler = null;
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs
new file mode 100644
index 0000000..72b3065
--- /dev/null
+++ b/OpenSim/Framework/Servers/HttpServer/BaseOutputStreamHandler.cs
@@ -0,0 +1,60 @@
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 OpenSimulator 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
28using System.IO;
29
30namespace OpenSim.Framework.Servers.HttpServer
31{
32 /// <summary>
33 /// Base handler for writing to an output stream
34 /// </summary>
35 /// <remarks>
36 /// Inheriting classes should override ProcessRequest() rather than Handle()
37 /// </remarks>
38 public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler
39 {
40 protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
41
42 protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description)
43 : base(httpMethod, path, name, description) {}
44
45 public virtual void Handle(
46 string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
47 {
48 RequestsReceived++;
49
50 ProcessRequest(path, request, response, httpRequest, httpResponse);
51
52 RequestsHandled++;
53 }
54
55 protected virtual void ProcessRequest(
56 string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
57 {
58 }
59 }
60} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs
index ae7aaf2..bbac699 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseRequestHandler.cs
@@ -31,6 +31,10 @@ namespace OpenSim.Framework.Servers.HttpServer
31{ 31{
32 public abstract class BaseRequestHandler 32 public abstract class BaseRequestHandler
33 { 33 {
34 public int RequestsReceived { get; protected set; }
35
36 public int RequestsHandled { get; protected set; }
37
34 public virtual string ContentType 38 public virtual string ContentType
35 { 39 {
36 get { return "application/xml"; } 40 get { return "application/xml"; }
diff --git a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs
index 6342983..252cc2a 100644
--- a/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BaseStreamHandler.cs
@@ -29,14 +29,35 @@ using System.IO;
29 29
30namespace OpenSim.Framework.Servers.HttpServer 30namespace OpenSim.Framework.Servers.HttpServer
31{ 31{
32 /// <summary>
33 /// Base streamed request handler.
34 /// </summary>
35 /// <remarks>
36 /// Inheriting classes should override ProcessRequest() rather than Handle()
37 /// </remarks>
32 public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler 38 public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler
33 { 39 {
34 public abstract byte[] Handle(string path, Stream request,
35 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse);
36
37 protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {} 40 protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
38 41
39 protected BaseStreamHandler(string httpMethod, string path, string name, string description) 42 protected BaseStreamHandler(string httpMethod, string path, string name, string description)
40 : base(httpMethod, path, name, description) {} 43 : base(httpMethod, path, name, description) {}
44
45 public virtual byte[] Handle(
46 string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
47 {
48 RequestsReceived++;
49
50 byte[] result = ProcessRequest(path, request, httpRequest, httpResponse);
51
52 RequestsHandled++;
53
54 return result;
55 }
56
57 protected virtual byte[] ProcessRequest(
58 string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
59 {
60 return null;
61 }
41 } 62 }
42} \ No newline at end of file 63} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs
index b94bfb4..1b03f54 100644
--- a/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/BinaryStreamHandler.cs
@@ -45,7 +45,7 @@ namespace OpenSim.Framework.Servers.HttpServer
45 m_method = binaryMethod; 45 m_method = binaryMethod;
46 } 46 }
47 47
48 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 48 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
49 { 49 {
50 byte[] data = ReadFully(request); 50 byte[] data = ReadFully(request);
51 string param = GetParam(path); 51 string param = GetParam(path);
diff --git a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs
index cb5cce5..b8541cb 100644
--- a/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/Interfaces/IStreamHandler.cs
@@ -32,7 +32,6 @@ namespace OpenSim.Framework.Servers.HttpServer
32{ 32{
33 public interface IRequestHandler 33 public interface IRequestHandler
34 { 34 {
35
36 /// <summary> 35 /// <summary>
37 /// Name for this handler. 36 /// Name for this handler.
38 /// </summary> 37 /// </summary>
@@ -59,6 +58,19 @@ namespace OpenSim.Framework.Servers.HttpServer
59 58
60 // Return path 59 // Return path
61 string Path { get; } 60 string Path { get; }
61
62 /// <summary>
63 /// Number of requests received by this handler
64 /// </summary>
65 int RequestsReceived { get; }
66
67 /// <summary>
68 /// Number of requests handled.
69 /// </summary>
70 /// <remarks>
71 /// Should be equal to RequestsReceived unless requested are being handled slowly or there is deadlock.
72 /// </remarks>
73 int RequestsHandled { get; }
62 } 74 }
63 75
64 public interface IStreamedRequestHandler : IRequestHandler 76 public interface IStreamedRequestHandler : IRequestHandler
@@ -69,7 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer
69 81
70 public interface IStreamHandler : IRequestHandler 82 public interface IStreamHandler : IRequestHandler
71 { 83 {
72 // Handle request stream, return byte array
73 void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse); 84 void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse);
74 } 85 }
75 86
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
index c19ac32..3fd3bf7 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceEventArgs.cs
@@ -50,25 +50,39 @@ namespace OpenSim.Framework.Servers.HttpServer
50 50
51 public enum EventType : int 51 public enum EventType : int
52 { 52 {
53 Normal = 0, 53 LongPoll = 0,
54 LslHttp = 1, 54 LslHttp = 1,
55 Inventory = 2, 55 Inventory = 2,
56 Texture = 3, 56 Texture = 3,
57 Mesh = 4 57 Mesh = 4
58 } 58 }
59 59
60 public string Url { get; set; }
61
62 /// <summary>
63 /// Number of requests received for this poll service.
64 /// </summary>
65 public int RequestsReceived { get; set; }
66
67 /// <summary>
68 /// Number of requests handled by this poll service.
69 /// </summary>
70 public int RequestsHandled { get; set; }
71
60 public PollServiceEventArgs( 72 public PollServiceEventArgs(
61 RequestMethod pRequest, 73 RequestMethod pRequest,
74 string pUrl,
62 HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents, 75 HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,
63 UUID pId, int pTimeOutms) 76 UUID pId, int pTimeOutms)
64 { 77 {
65 Request = pRequest; 78 Request = pRequest;
79 Url = pUrl;
66 HasEvents = pHasEvents; 80 HasEvents = pHasEvents;
67 GetEvents = pGetEvents; 81 GetEvents = pGetEvents;
68 NoEvents = pNoEvents; 82 NoEvents = pNoEvents;
69 Id = pId; 83 Id = pId;
70 TimeOutms = pTimeOutms; 84 TimeOutms = pTimeOutms;
71 Type = EventType.Normal; 85 Type = EventType.LongPoll;
72 } 86 }
73 } 87 }
74} 88}
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
index 723530a..6aa9479 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceHttpRequest.cs
@@ -26,13 +26,19 @@
26 */ 26 */
27 27
28using System; 28using System;
29using System.Collections;
30using System.Reflection;
31using System.Text;
29using HttpServer; 32using HttpServer;
33using log4net;
30using OpenMetaverse; 34using OpenMetaverse;
31 35
32namespace OpenSim.Framework.Servers.HttpServer 36namespace OpenSim.Framework.Servers.HttpServer
33{ 37{
34 public class PollServiceHttpRequest 38 public class PollServiceHttpRequest
35 { 39 {
40 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
41
36 public readonly PollServiceEventArgs PollServiceArgs; 42 public readonly PollServiceEventArgs PollServiceArgs;
37 public readonly IHttpClientContext HttpContext; 43 public readonly IHttpClientContext HttpContext;
38 public readonly IHttpRequest Request; 44 public readonly IHttpRequest Request;
@@ -48,5 +54,44 @@ namespace OpenSim.Framework.Servers.HttpServer
48 RequestTime = System.Environment.TickCount; 54 RequestTime = System.Environment.TickCount;
49 RequestID = UUID.Random(); 55 RequestID = UUID.Random();
50 } 56 }
57
58 internal void DoHTTPGruntWork(BaseHttpServer server, Hashtable responsedata)
59 {
60 OSHttpResponse response
61 = new OSHttpResponse(new HttpResponse(HttpContext, Request), HttpContext);
62
63 byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
64
65 response.SendChunked = false;
66 response.ContentLength64 = buffer.Length;
67 response.ContentEncoding = Encoding.UTF8;
68
69 try
70 {
71 response.OutputStream.Write(buffer, 0, buffer.Length);
72 }
73 catch (Exception ex)
74 {
75 m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex));
76 }
77 finally
78 {
79 //response.OutputStream.Close();
80 try
81 {
82 response.OutputStream.Flush();
83 response.Send();
84
85 //if (!response.KeepAlive && response.ReuseContext)
86 // response.FreeContext();
87 }
88 catch (Exception e)
89 {
90 m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e));
91 }
92
93 PollServiceArgs.RequestsHandled++;
94 }
95 }
51 } 96 }
52} \ No newline at end of file 97} \ No newline at end of file
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 5406f00..44f7045 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -64,14 +64,17 @@ namespace OpenSim.Framework.Servers.HttpServer
64 m_server = pSrv; 64 m_server = pSrv;
65 m_WorkerThreadCount = pWorkerThreadCount; 65 m_WorkerThreadCount = pWorkerThreadCount;
66 m_workerThreads = new Thread[m_WorkerThreadCount]; 66 m_workerThreads = new Thread[m_WorkerThreadCount];
67 }
67 68
69 public void Start()
70 {
68 //startup worker threads 71 //startup worker threads
69 for (uint i = 0; i < m_WorkerThreadCount; i++) 72 for (uint i = 0; i < m_WorkerThreadCount; i++)
70 { 73 {
71 m_workerThreads[i] 74 m_workerThreads[i]
72 = Watchdog.StartThread( 75 = Watchdog.StartThread(
73 PoolWorkerJob, 76 PoolWorkerJob,
74 String.Format("PollServiceWorkerThread{0}", i), 77 string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port),
75 ThreadPriority.Normal, 78 ThreadPriority.Normal,
76 false, 79 false,
77 false, 80 false,
@@ -81,7 +84,7 @@ namespace OpenSim.Framework.Servers.HttpServer
81 84
82 m_retrysThread = Watchdog.StartThread( 85 m_retrysThread = Watchdog.StartThread(
83 this.CheckRetries, 86 this.CheckRetries,
84 "PollServiceWatcherThread", 87 string.Format("PollServiceWatcherThread:{0}", m_server.Port),
85 ThreadPriority.Normal, 88 ThreadPriority.Normal,
86 false, 89 false,
87 true, 90 true,
@@ -89,7 +92,6 @@ namespace OpenSim.Framework.Servers.HttpServer
89 1000 * 60 * 10); 92 1000 * 60 * 10);
90 } 93 }
91 94
92
93 private void ReQueueEvent(PollServiceHttpRequest req) 95 private void ReQueueEvent(PollServiceHttpRequest req)
94 { 96 {
95 if (m_running) 97 if (m_running)
@@ -103,7 +105,7 @@ namespace OpenSim.Framework.Servers.HttpServer
103 { 105 {
104 if (m_running) 106 if (m_running)
105 { 107 {
106 if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal) 108 if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.LongPoll)
107 { 109 {
108 m_requests.Enqueue(req); 110 m_requests.Enqueue(req);
109 } 111 }
@@ -140,13 +142,13 @@ namespace OpenSim.Framework.Servers.HttpServer
140 } 142 }
141 } 143 }
142 144
143 ~PollServiceRequestManager() 145 public void Stop()
144 { 146 {
145 m_running = false; 147 m_running = false;
146 Thread.Sleep(1000); // let the world move 148 Thread.Sleep(1000); // let the world move
147 149
148 foreach (Thread t in m_workerThreads) 150 foreach (Thread t in m_workerThreads)
149 Watchdog.AbortThread(t.ManagedThreadId); 151 Watchdog.AbortThread(t.ManagedThreadId);
150 152
151 try 153 try
152 { 154 {
@@ -205,7 +207,7 @@ namespace OpenSim.Framework.Servers.HttpServer
205 if (responsedata == null) 207 if (responsedata == null)
206 continue; 208 continue;
207 209
208 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue 210 if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.LongPoll) // This is the event queue
209 { 211 {
210 try 212 try
211 { 213 {
diff --git a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs
index 07082a8..bd55657 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestDeserialiseHandler.cs
@@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers.HttpServer
33{ 33{
34 public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request); 34 public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request);
35 35
36 public class RestDeserialiseHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler 36 public class RestDeserialiseHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
37 where TRequest : new() 37 where TRequest : new()
38 { 38 {
39 private RestDeserialiseMethod<TRequest, TResponse> m_method; 39 private RestDeserialiseMethod<TRequest, TResponse> m_method;
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer
48 m_method = method; 48 m_method = method;
49 } 49 }
50 50
51 public void Handle(string path, Stream request, Stream responseStream, 51 protected override void ProcessRequest(string path, Stream request, Stream responseStream,
52 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 52 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
53 { 53 {
54 TRequest deserial; 54 TRequest deserial;
diff --git a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
index edcd134..83c9848 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestSessionService.cs
@@ -183,7 +183,7 @@ namespace OpenSim.Framework.Servers.HttpServer
183 183
184 public delegate bool CheckIdentityMethod(string sid, string aid); 184 public delegate bool CheckIdentityMethod(string sid, string aid);
185 185
186 public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler 186 public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
187 where TRequest : new() 187 where TRequest : new()
188 { 188 {
189 private static readonly ILog m_log 189 private static readonly ILog m_log
@@ -201,7 +201,7 @@ namespace OpenSim.Framework.Servers.HttpServer
201 m_method = method; 201 m_method = method;
202 } 202 }
203 203
204 public void Handle(string path, Stream request, Stream responseStream, 204 protected override void ProcessRequest(string path, Stream request, Stream responseStream,
205 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 205 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
206 { 206 {
207 RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>); 207 RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>);
@@ -237,7 +237,7 @@ namespace OpenSim.Framework.Servers.HttpServer
237 237
238 public delegate bool CheckTrustedSourceMethod(IPEndPoint peer); 238 public delegate bool CheckTrustedSourceMethod(IPEndPoint peer);
239 239
240 public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler 240 public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
241 where TRequest : new() 241 where TRequest : new()
242 { 242 {
243 private static readonly ILog m_log 243 private static readonly ILog m_log
@@ -260,7 +260,7 @@ namespace OpenSim.Framework.Servers.HttpServer
260 m_method = method; 260 m_method = method;
261 } 261 }
262 262
263 public void Handle(string path, Stream request, Stream responseStream, 263 protected override void ProcessRequest(string path, Stream request, Stream responseStream,
264 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 264 IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
265 { 265 {
266 TRequest deserial = default(TRequest); 266 TRequest deserial = default(TRequest);
@@ -292,6 +292,5 @@ namespace OpenSim.Framework.Servers.HttpServer
292 serializer.Serialize(xmlWriter, response); 292 serializer.Serialize(xmlWriter, response);
293 } 293 }
294 } 294 }
295 } 295 }
296 296} \ No newline at end of file
297}
diff --git a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs
index 1f17fee..0305dee 100644
--- a/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/RestStreamHandler.cs
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer
48 m_restMethod = restMethod; 48 m_restMethod = restMethod;
49 } 49 }
50 50
51 public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse) 51 protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
52 { 52 {
53 Encoding encoding = Encoding.UTF8; 53 Encoding encoding = Encoding.UTF8;
54 StreamReader streamReader = new StreamReader(request, encoding); 54 StreamReader streamReader = new StreamReader(request, encoding);
diff --git a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
index ee96b47..de89e2e 100644
--- a/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
+++ b/OpenSim/Framework/Servers/HttpServer/WebsocketServerHandler.cs
@@ -75,7 +75,7 @@ namespace OpenSim.Framework.Servers.HttpServer
75 /// <summary> 75 /// <summary>
76 /// This is a regular HTTP Request... This may be removed in the future. 76 /// This is a regular HTTP Request... This may be removed in the future.
77 /// </summary> 77 /// </summary>
78 public event RegularHttpRequestDelegate OnRegularHttpRequest; 78// public event RegularHttpRequestDelegate OnRegularHttpRequest;
79 79
80 /// <summary> 80 /// <summary>
81 /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired 81 /// When the upgrade from a HTTP request to a Websocket is completed, this will be fired
@@ -304,15 +304,14 @@ namespace OpenSim.Framework.Servers.HttpServer
304 if (d != null) 304 if (d != null)
305 d(this, new UpgradeCompletedEventArgs()); 305 d(this, new UpgradeCompletedEventArgs());
306 } 306 }
307 catch (IOException fail) 307 catch (IOException)
308 { 308 {
309 Close(string.Empty); 309 Close(string.Empty);
310 } 310 }
311 catch (ObjectDisposedException fail) 311 catch (ObjectDisposedException)
312 { 312 {
313 Close(string.Empty); 313 Close(string.Empty);
314 } 314 }
315
316 } 315 }
317 316
318 /// <summary> 317 /// <summary>
@@ -414,8 +413,6 @@ namespace OpenSim.Framework.Servers.HttpServer
414 _socketState.Header = pheader; 413 _socketState.Header = pheader;
415 } 414 }
416 415
417
418
419 if (_socketState.FrameComplete) 416 if (_socketState.FrameComplete)
420 { 417 {
421 ProcessFrame(_socketState); 418 ProcessFrame(_socketState);
@@ -424,7 +421,6 @@ namespace OpenSim.Framework.Servers.HttpServer
424 _socketState.ExpectedBytes = 0; 421 _socketState.ExpectedBytes = 0;
425 422
426 } 423 }
427
428 } 424 }
429 } 425 }
430 else 426 else
@@ -457,8 +453,7 @@ namespace OpenSim.Framework.Servers.HttpServer
457 _socketState.ReceivedBytes.Clear(); 453 _socketState.ReceivedBytes.Clear();
458 _socketState.ExpectedBytes = 0; 454 _socketState.ExpectedBytes = 0;
459 // do some processing 455 // do some processing
460 } 456 }
461
462 } 457 }
463 } 458 }
464 if (offset > 0) 459 if (offset > 0)
@@ -477,13 +472,12 @@ namespace OpenSim.Framework.Servers.HttpServer
477 { 472 {
478 // We can't read the stream anymore... 473 // We can't read the stream anymore...
479 } 474 }
480
481 } 475 }
482 catch (IOException fail) 476 catch (IOException)
483 { 477 {
484 Close(string.Empty); 478 Close(string.Empty);
485 } 479 }
486 catch (ObjectDisposedException fail) 480 catch (ObjectDisposedException)
487 { 481 {
488 Close(string.Empty); 482 Close(string.Empty);
489 } 483 }
diff --git a/OpenSim/Framework/Servers/MainServer.cs b/OpenSim/Framework/Servers/MainServer.cs
index cfd34bb..57931d4 100644
--- a/OpenSim/Framework/Servers/MainServer.cs
+++ b/OpenSim/Framework/Servers/MainServer.cs
@@ -121,12 +121,14 @@ namespace OpenSim.Framework.Servers
121 + " level >= 2 then long warnings are logged when receiving bad input data.\n" 121 + " level >= 2 then long warnings are logged when receiving bad input data.\n"
122 + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n" 122 + " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
123 + " level >= 4 then the time taken to fulfill the request is logged.\n" 123 + " level >= 4 then the time taken to fulfill the request is logged.\n"
124 + " level >= 5 then a sample from the beginning of the incoming data is logged.\n" 124 + " level >= 5 then a sample from the beginning of the data is logged.\n"
125 + " level >= 6 then the entire incoming data is logged.\n" 125 + " level >= 6 then the entire data is logged.\n"
126 + " no level is specified then the current level is returned.\n\n" 126 + " no level is specified then the current level is returned.\n\n"
127 + "If out or all and\n" 127 + "If out or all and\n"
128 + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n" 128 + " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
129 + " level >= 4 then the time taken to fulfill the request is logged.\n", 129 + " level >= 4 then the time taken to fulfill the request is logged.\n"
130 + " level >= 5 then a sample from the beginning of the data is logged.\n"
131 + " level >= 6 then the entire data is logged.\n",
130 HandleDebugHttpCommand); 132 HandleDebugHttpCommand);
131 } 133 }
132 134
@@ -283,7 +285,12 @@ namespace OpenSim.Framework.Servers
283 public static bool RemoveHttpServer(uint port) 285 public static bool RemoveHttpServer(uint port)
284 { 286 {
285 lock (m_Servers) 287 lock (m_Servers)
288 {
289 if (instance != null && instance.Port == port)
290 instance = null;
291
286 return m_Servers.Remove(port); 292 return m_Servers.Remove(port);
293 }
287 } 294 }
288 295
289 /// <summary> 296 /// <summary>
diff --git a/OpenSim/Framework/Servers/ServerBase.cs b/OpenSim/Framework/Servers/ServerBase.cs
index 1ff8aca..7108314 100644
--- a/OpenSim/Framework/Servers/ServerBase.cs
+++ b/OpenSim/Framework/Servers/ServerBase.cs
@@ -62,6 +62,8 @@ namespace OpenSim.Framework.Servers
62 62
63 protected string m_pidFile = String.Empty; 63 protected string m_pidFile = String.Empty;
64 64
65 protected ServerStatsCollector m_serverStatsCollector;
66
65 /// <summary> 67 /// <summary>
66 /// Server version information. Usually VersionInfo + information about git commit, operating system, etc. 68 /// Server version information. Usually VersionInfo + information about git commit, operating system, etc.
67 /// </summary> 69 /// </summary>
@@ -76,6 +78,11 @@ namespace OpenSim.Framework.Servers
76 78
77 protected void CreatePIDFile(string path) 79 protected void CreatePIDFile(string path)
78 { 80 {
81 if (File.Exists(path))
82 m_log.ErrorFormat(
83 "[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.",
84 path);
85
79 try 86 try
80 { 87 {
81 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString(); 88 string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
@@ -239,7 +246,7 @@ namespace OpenSim.Framework.Servers
239 "Show thread status", HandleShow); 246 "Show thread status", HandleShow);
240 247
241 m_console.Commands.AddCommand( 248 m_console.Commands.AddCommand(
242 "General", false, "threads abort", 249 "Debug", false, "threads abort",
243 "threads abort <thread-id>", 250 "threads abort <thread-id>",
244 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort); 251 "Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
245 252
@@ -249,11 +256,180 @@ namespace OpenSim.Framework.Servers
249 "Show thread status. Synonym for \"show threads\"", 256 "Show thread status. Synonym for \"show threads\"",
250 (string module, string[] args) => Notice(GetThreadsReport())); 257 (string module, string[] args) => Notice(GetThreadsReport()));
251 258
259 m_console.Commands.AddCommand (
260 "Debug", false, "debug comms set",
261 "debug comms set serialosdreq true|false",
262 "Set comms parameters. For debug purposes.",
263 HandleDebugCommsSet);
264
265 m_console.Commands.AddCommand (
266 "Debug", false, "debug comms status",
267 "debug comms status",
268 "Show current debug comms parameters.",
269 HandleDebugCommsStatus);
270
271 m_console.Commands.AddCommand (
272 "Debug", false, "debug threadpool set",
273 "debug threadpool set worker|iocp min|max <n>",
274 "Set threadpool parameters. For debug purposes.",
275 HandleDebugThreadpoolSet);
276
277 m_console.Commands.AddCommand (
278 "Debug", false, "debug threadpool status",
279 "debug threadpool status",
280 "Show current debug threadpool parameters.",
281 HandleDebugThreadpoolStatus);
282
252 m_console.Commands.AddCommand( 283 m_console.Commands.AddCommand(
253 "General", false, "force gc", 284 "Debug", false, "force gc",
254 "force gc", 285 "force gc",
255 "Manually invoke runtime garbage collection. For debugging purposes", 286 "Manually invoke runtime garbage collection. For debugging purposes",
256 HandleForceGc); 287 HandleForceGc);
288
289 m_console.Commands.AddCommand(
290 "General", false, "quit",
291 "quit",
292 "Quit the application", (mod, args) => Shutdown());
293
294 m_console.Commands.AddCommand(
295 "General", false, "shutdown",
296 "shutdown",
297 "Quit the application", (mod, args) => Shutdown());
298
299 ChecksManager.RegisterConsoleCommands(m_console);
300 StatsManager.RegisterConsoleCommands(m_console);
301 }
302
303 public void RegisterCommonComponents(IConfigSource configSource)
304 {
305 IConfig networkConfig = configSource.Configs["Network"];
306
307 if (networkConfig != null)
308 {
309 WebUtil.SerializeOSDRequestsPerEndpoint = networkConfig.GetBoolean("SerializeOSDRequests", false);
310 }
311
312 m_serverStatsCollector = new ServerStatsCollector();
313 m_serverStatsCollector.Initialise(configSource);
314 m_serverStatsCollector.Start();
315 }
316
317 private void HandleDebugCommsStatus(string module, string[] args)
318 {
319 Notice("serialosdreq is {0}", WebUtil.SerializeOSDRequestsPerEndpoint);
320 }
321
322 private void HandleDebugCommsSet(string module, string[] args)
323 {
324 if (args.Length != 5)
325 {
326 Notice("Usage: debug comms set serialosdreq true|false");
327 return;
328 }
329
330 if (args[3] != "serialosdreq")
331 {
332 Notice("Usage: debug comms set serialosdreq true|false");
333 return;
334 }
335
336 bool setSerializeOsdRequests;
337
338 if (!ConsoleUtil.TryParseConsoleBool(m_console, args[4], out setSerializeOsdRequests))
339 return;
340
341 WebUtil.SerializeOSDRequestsPerEndpoint = setSerializeOsdRequests;
342
343 Notice("serialosdreq is now {0}", setSerializeOsdRequests);
344 }
345
346 private void HandleDebugThreadpoolStatus(string module, string[] args)
347 {
348 int workerThreads, iocpThreads;
349
350 ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
351 Notice("Min worker threads: {0}", workerThreads);
352 Notice("Min IOCP threads: {0}", iocpThreads);
353
354 ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
355 Notice("Max worker threads: {0}", workerThreads);
356 Notice("Max IOCP threads: {0}", iocpThreads);
357
358 ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
359 Notice("Available worker threads: {0}", workerThreads);
360 Notice("Available IOCP threads: {0}", iocpThreads);
361 }
362
363 private void HandleDebugThreadpoolSet(string module, string[] args)
364 {
365 if (args.Length != 6)
366 {
367 Notice("Usage: debug threadpool set worker|iocp min|max <n>");
368 return;
369 }
370
371 int newThreads;
372
373 if (!ConsoleUtil.TryParseConsoleInt(m_console, args[5], out newThreads))
374 return;
375
376 string poolType = args[3];
377 string bound = args[4];
378
379 bool fail = false;
380 int workerThreads, iocpThreads;
381
382 if (poolType == "worker")
383 {
384 if (bound == "min")
385 {
386 ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
387
388 if (!ThreadPool.SetMinThreads(newThreads, iocpThreads))
389 fail = true;
390 }
391 else
392 {
393 ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
394
395 if (!ThreadPool.SetMaxThreads(newThreads, iocpThreads))
396 fail = true;
397 }
398 }
399 else
400 {
401 if (bound == "min")
402 {
403 ThreadPool.GetMinThreads(out workerThreads, out iocpThreads);
404
405 if (!ThreadPool.SetMinThreads(workerThreads, newThreads))
406 fail = true;
407 }
408 else
409 {
410 ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
411
412 if (!ThreadPool.SetMaxThreads(workerThreads, newThreads))
413 fail = true;
414 }
415 }
416
417 if (fail)
418 {
419 Notice("ERROR: Could not set {0} {1} threads to {2}", poolType, bound, newThreads);
420 }
421 else
422 {
423 int minWorkerThreads, maxWorkerThreads, minIocpThreads, maxIocpThreads;
424
425 ThreadPool.GetMinThreads(out minWorkerThreads, out minIocpThreads);
426 ThreadPool.GetMaxThreads(out maxWorkerThreads, out maxIocpThreads);
427
428 Notice("Min worker threads now {0}", minWorkerThreads);
429 Notice("Min IOCP threads now {0}", minIocpThreads);
430 Notice("Max worker threads now {0}", maxWorkerThreads);
431 Notice("Max IOCP threads now {0}", maxIocpThreads);
432 }
257 } 433 }
258 434
259 private void HandleForceGc(string module, string[] args) 435 private void HandleForceGc(string module, string[] args)
@@ -641,7 +817,68 @@ namespace OpenSim.Framework.Servers
641 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads); 817 sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
642 818
643 sb.Append("Main threadpool (excluding script engine pools)\n"); 819 sb.Append("Main threadpool (excluding script engine pools)\n");
644 sb.Append(Util.GetThreadPoolReport()); 820 sb.Append(GetThreadPoolReport());
821
822 return sb.ToString();
823 }
824
825 /// <summary>
826 /// Get a thread pool report.
827 /// </summary>
828 /// <returns></returns>
829 public static string GetThreadPoolReport()
830 {
831 string threadPoolUsed = null;
832 int maxThreads = 0;
833 int minThreads = 0;
834 int allocatedThreads = 0;
835 int inUseThreads = 0;
836 int waitingCallbacks = 0;
837 int completionPortThreads = 0;
838
839 StringBuilder sb = new StringBuilder();
840 if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
841 {
842 STPInfo stpi = Util.GetSmartThreadPoolInfo();
843
844 // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
845 if (stpi != null)
846 {
847 threadPoolUsed = "SmartThreadPool";
848 maxThreads = stpi.MaxThreads;
849 minThreads = stpi.MinThreads;
850 inUseThreads = stpi.InUseThreads;
851 allocatedThreads = stpi.ActiveThreads;
852 waitingCallbacks = stpi.WaitingCallbacks;
853 }
854 }
855 else if (
856 Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem
857 || Util.FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem)
858 {
859 threadPoolUsed = "BuiltInThreadPool";
860 ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads);
861 ThreadPool.GetMinThreads(out minThreads, out completionPortThreads);
862 int availableThreads;
863 ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);
864 inUseThreads = maxThreads - availableThreads;
865 allocatedThreads = -1;
866 waitingCallbacks = -1;
867 }
868
869 if (threadPoolUsed != null)
870 {
871 sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed);
872 sb.AppendFormat("Max threads : {0}\n", maxThreads);
873 sb.AppendFormat("Min threads : {0}\n", minThreads);
874 sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString());
875 sb.AppendFormat("In use threads : {0}\n", inUseThreads);
876 sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString());
877 }
878 else
879 {
880 sb.AppendFormat("Thread pool not used\n");
881 }
645 882
646 return sb.ToString(); 883 return sb.ToString();
647 } 884 }
@@ -693,5 +930,16 @@ namespace OpenSim.Framework.Servers
693 if (m_console != null) 930 if (m_console != null)
694 m_console.OutputFormat(format, components); 931 m_console.OutputFormat(format, components);
695 } 932 }
933
934 public virtual void Shutdown()
935 {
936 m_serverStatsCollector.Close();
937 ShutdownSpecific();
938 }
939
940 /// <summary>
941 /// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
942 /// </summary>
943 protected virtual void ShutdownSpecific() {}
696 } 944 }
697} 945}
diff --git a/OpenSim/Framework/Tests/LocationTest.cs b/OpenSim/Framework/Tests/LocationTest.cs
index a56ecb4..3d5d1d2 100644
--- a/OpenSim/Framework/Tests/LocationTest.cs
+++ b/OpenSim/Framework/Tests/LocationTest.cs
@@ -51,21 +51,28 @@ namespace OpenSim.Framework.Tests
51 [Test] 51 [Test]
52 public void locationXYRegionHandle() 52 public void locationXYRegionHandle()
53 { 53 {
54 Location TestLocation1 = new Location(256000,256000); 54 Location TestLocation1 = new Location(255000,256000);
55 Location TestLocation2 = new Location(1099511628032000); 55 Location TestLocation2 = new Location(1095216660736000);
56 Assert.That(TestLocation1 == TestLocation2); 56 Assert.That(TestLocation1 == TestLocation2);
57 57
58 Assert.That(TestLocation2.X == 256000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided"); 58 Assert.That(TestLocation1.X == 255000 && TestLocation1.Y == 256000, "Test xy location doesn't match position in the constructor");
59 Assert.That(TestLocation2.X == 255000 && TestLocation2.Y == 256000, "Test xy location doesn't match regionhandle provided");
59 60
60 Assert.That(TestLocation2.RegionHandle == 1099511628032000, 61 Assert.That(TestLocation2.RegionHandle == 1095216660736000,
61 "Location RegionHandle Property didn't match regionhandle provided in constructor"); 62 "Location RegionHandle Property didn't match regionhandle provided in constructor");
62 63
64 ulong RegionHandle = TestLocation1.RegionHandle;
65 Assert.That(RegionHandle.Equals(1095216660736000), "Equals(regionhandle) failed to match the position in the constructor");
63 66
64 TestLocation1 = new Location(256001, 256001); 67 TestLocation2 = new Location(RegionHandle);
65 TestLocation2 = new Location(1099511628032000); 68 Assert.That(TestLocation2.Equals(255000, 256000), "Decoded regionhandle failed to match the original position in the constructor");
69
70
71 TestLocation1 = new Location(255001, 256001);
72 TestLocation2 = new Location(1095216660736000);
66 Assert.That(TestLocation1 != TestLocation2); 73 Assert.That(TestLocation1 != TestLocation2);
67 74
68 Assert.That(TestLocation1.Equals(256001, 256001), "Equals(x,y) failed to match the position in the constructor"); 75 Assert.That(TestLocation1.Equals(255001, 256001), "Equals(x,y) failed to match the position in the constructor");
69 76
70 Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode"); 77 Assert.That(TestLocation2.GetHashCode() == (TestLocation2.X.GetHashCode() ^ TestLocation2.Y.GetHashCode()), "GetHashCode failed to produce the expected hashcode");
71 78
diff --git a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
index 0fbdaf3..08f2af5 100644
--- a/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
+++ b/OpenSim/Framework/Tests/MundaneFrameworkTests.cs
@@ -100,7 +100,7 @@ namespace OpenSim.Framework.Tests
100 cadu.AVHeight = Size1.Z; 100 cadu.AVHeight = Size1.Z;
101 101
102 AgentPosition position2 = new AgentPosition(); 102 AgentPosition position2 = new AgentPosition();
103 position2.CopyFrom(cadu); 103 position2.CopyFrom(cadu, position1.SessionID);
104 104
105 Assert.IsTrue( 105 Assert.IsTrue(
106 position2.AgentID == position1.AgentID 106 position2.AgentID == position1.AgentID
diff --git a/OpenSim/Framework/Tests/UtilTest.cs b/OpenSim/Framework/Tests/UtilTest.cs
index 11ca068..3b7f252 100644
--- a/OpenSim/Framework/Tests/UtilTest.cs
+++ b/OpenSim/Framework/Tests/UtilTest.cs
@@ -282,5 +282,87 @@ namespace OpenSim.Framework.Tests
282 String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i])); 282 String.Format("Incorrect InventoryType mapped from Content-Type {0}", invcontenttypes[i]));
283 } 283 }
284 } 284 }
285
286 [Test]
287 public void FakeParcelIDTests()
288 {
289 byte[] hexBytes8 = { 0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10 };
290 byte[] hexBytes16 = {
291 0xf0, 0xe1, 0xd2, 0xc3, 0xb4, 0xa5, 0x96, 0x87,
292 0x77, 0x69, 0x5a, 0x4b, 0x3c, 0x2d, 0x1e, 0x0f };
293 UInt64 var64Bit = (UInt64)0xfedcba9876543210;
294
295 //Region handle is for location 255000,256000.
296 ulong regionHandle1 = 1095216660736000;
297 uint x1 = 100;
298 uint y1 = 200;
299 uint z1 = 22;
300 ulong regionHandle2;
301 uint x2, y2, z2;
302 UUID fakeParcelID1, fakeParcelID2, uuid;
303
304 ulong bigInt64 = Util.BytesToUInt64Big(hexBytes8);
305 Assert.AreEqual(var64Bit, bigInt64,
306 "BytesToUint64Bit conversion of 8 bytes to UInt64 failed.");
307
308 //Test building and decoding using some typical input values
309 fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1);
310 Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2);
311 Assert.AreEqual(regionHandle1, regionHandle2,
312 "region handle decoded from FakeParcelID wth X/Y failed.");
313 Assert.AreEqual(x1, x2,
314 "X coordinate decoded from FakeParcelID wth X/Y failed.");
315 Assert.AreEqual(y1, y2,
316 "Y coordinate decoded from FakeParcelID wth X/Y failed.");
317
318 fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1, z1);
319 Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2);
320 Assert.AreEqual(regionHandle1, regionHandle2,
321 "region handle decoded from FakeParcelID with X/Y/Z failed.");
322 Assert.AreEqual(x1, x2,
323 "X coordinate decoded from FakeParcelID with X/Y/Z failed.");
324 Assert.AreEqual(y1, y2,
325 "Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
326 Assert.AreEqual(z1, z2,
327 "Z coordinate decoded from FakeParcelID with X/Y/Z failed.");
328
329 //Do some more extreme tests to check the encoding and decoding
330 x1 = 0x55aa;
331 y1 = 0x9966;
332 z1 = 0x5a96;
333
334 fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1);
335 Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2);
336 Assert.AreEqual(var64Bit, regionHandle2,
337 "region handle decoded from FakeParcelID with X/Y/Z failed.");
338 Assert.AreEqual(x1, x2,
339 "X coordinate decoded from FakeParcelID with X/Y/Z failed.");
340 Assert.AreEqual(y1, y2,
341 "Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
342
343 fakeParcelID1 = Util.BuildFakeParcelID(var64Bit, x1, y1, z1);
344 Util.ParseFakeParcelID(fakeParcelID1, out regionHandle2, out x2, out y2, out z2);
345 Assert.AreEqual(var64Bit, regionHandle2,
346 "region handle decoded from FakeParcelID with X/Y/Z failed.");
347 Assert.AreEqual(x1, x2,
348 "X coordinate decoded from FakeParcelID with X/Y/Z failed.");
349 Assert.AreEqual(y1, y2,
350 "Y coordinate decoded from FakeParcelID with X/Y/Z failed.");
351 Assert.AreEqual(z1, z2,
352 "Z coordinate decoded from FakeParcelID with X/Y/Z failed.");
353
354
355 x1 = 64;
356 y1 = 192;
357 fakeParcelID1 = Util.BuildFakeParcelID(regionHandle1, x1, y1);
358 Util.FakeParcelIDToGlobalPosition(fakeParcelID1, out x2, out y2);
359 Assert.AreEqual(255000+x1, x2,
360 "Global X coordinate decoded from regionHandle failed.");
361 Assert.AreEqual(256000+y1, y2,
362 "Global Y coordinate decoded from regionHandle failed.");
363
364 uuid = new UUID("00dd0700-00d1-0700-3800-000032000000");
365 Util.FakeParcelIDToGlobalPosition(uuid, out x2, out y2);
366 }
285 } 367 }
286} 368}
diff --git a/OpenSim/Framework/UserProfiles.cs b/OpenSim/Framework/UserProfiles.cs
new file mode 100644
index 0000000..6133591
--- /dev/null
+++ b/OpenSim/Framework/UserProfiles.cs
@@ -0,0 +1,117 @@
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 OpenSimulator 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
28using System;
29using OpenMetaverse;
30
31namespace OpenSim.Framework
32{
33 public class UserClassifiedAdd
34 {
35 public UUID ClassifiedId = UUID.Zero;
36 public UUID CreatorId = UUID.Zero;
37 public int CreationDate = 0;
38 public int ExpirationDate = 0;
39 public int Category = 0;
40 public string Name = string.Empty;
41 public string Description = string.Empty;
42 public UUID ParcelId = UUID.Zero;
43 public int ParentEstate = 0;
44 public UUID SnapshotId = UUID.Zero;
45 public string SimName = string.Empty;
46 public string GlobalPos = "<0,0,0>";
47 public string ParcelName = string.Empty;
48 public byte Flags = 0;
49 public int Price = 0;
50 }
51
52 public class UserProfileProperties
53 {
54 public UUID UserId = UUID.Zero;
55 public UUID PartnerId = UUID.Zero;
56 public bool PublishProfile = false;
57 public bool PublishMature = false;
58 public string WebUrl = string.Empty;
59 public int WantToMask = 0;
60 public string WantToText = string.Empty;
61 public int SkillsMask = 0;
62 public string SkillsText = string.Empty;
63 public string Language = string.Empty;
64 public UUID ImageId = UUID.Zero;
65 public string AboutText = string.Empty;
66 public UUID FirstLifeImageId = UUID.Zero;
67 public string FirstLifeText = string.Empty;
68 }
69
70 public class UserProfilePick
71 {
72 public UUID PickId = UUID.Zero;
73 public UUID CreatorId = UUID.Zero;
74 public bool TopPick = false;
75 public string Name = string.Empty;
76 public string OriginalName = string.Empty;
77 public string Desc = string.Empty;
78 public UUID ParcelId = UUID.Zero;
79 public UUID SnapshotId = UUID.Zero;
80 public string User = string.Empty;
81 public string SimName = string.Empty;
82 public string GlobalPos = "<0,0,0>";
83 public int SortOrder = 0;
84 public bool Enabled = false;
85 }
86
87 public class UserProfileNotes
88 {
89 public UUID UserId;
90 public UUID TargetId;
91 public string Notes;
92 }
93
94 public class UserAccountProperties
95 {
96 public string EmailAddress = string.Empty;
97 public string Firstname = string.Empty;
98 public string LastName = string.Empty;
99 public string Password = string.Empty;
100 public string UserId = string.Empty;
101 }
102
103 public class UserAccountAuth
104 {
105 public string UserId = UUID.Zero.ToString();
106 public string Password = string.Empty;
107 }
108
109 public class UserAppData
110 {
111 public string TagId = string.Empty;
112 public string DataKey = string.Empty;
113 public string UserId = UUID.Zero.ToString();
114 public string DataVal = string.Empty;
115 }
116}
117
diff --git a/OpenSim/Framework/Util.cs b/OpenSim/Framework/Util.cs
index 557f38e..7db575b 100644
--- a/OpenSim/Framework/Util.cs
+++ b/OpenSim/Framework/Util.cs
@@ -89,9 +89,30 @@ namespace OpenSim.Framework
89 } 89 }
90 90
91 /// <summary> 91 /// <summary>
92 /// Class for delivering SmartThreadPool statistical information
93 /// </summary>
94 /// <remarks>
95 /// We do it this way so that we do not directly expose STP.
96 /// </remarks>
97 public class STPInfo
98 {
99 public string Name { get; set; }
100 public STPStartInfo STPStartInfo { get; set; }
101 public WIGStartInfo WIGStartInfo { get; set; }
102 public bool IsIdle { get; set; }
103 public bool IsShuttingDown { get; set; }
104 public int MaxThreads { get; set; }
105 public int MinThreads { get; set; }
106 public int InUseThreads { get; set; }
107 public int ActiveThreads { get; set; }
108 public int WaitingCallbacks { get; set; }
109 public int MaxConcurrentWorkItems { get; set; }
110 }
111
112 /// <summary>
92 /// Miscellaneous utility functions 113 /// Miscellaneous utility functions
93 /// </summary> 114 /// </summary>
94 public class Util 115 public static class Util
95 { 116 {
96 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 117 private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
97 118
@@ -109,7 +130,7 @@ namespace OpenSim.Framework
109 private static SmartThreadPool m_ThreadPool; 130 private static SmartThreadPool m_ThreadPool;
110 131
111 // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC. 132 // Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC.
112 private static readonly DateTime unixEpoch = 133 public static readonly DateTime UnixEpoch =
113 DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime(); 134 DateTime.ParseExact("1970-01-01 00:00:00 +0", "yyyy-MM-dd hh:mm:ss z", DateTimeFormatInfo.InvariantInfo).ToUniversalTime();
114 135
115 private static readonly string rawUUIDPattern 136 private static readonly string rawUUIDPattern
@@ -120,6 +141,11 @@ namespace OpenSim.Framework
120 public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool; 141 public static FireAndForgetMethod DefaultFireAndForgetMethod = FireAndForgetMethod.SmartThreadPool;
121 public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod; 142 public static FireAndForgetMethod FireAndForgetMethod = DefaultFireAndForgetMethod;
122 143
144 public static bool IsPlatformMono
145 {
146 get { return Type.GetType("Mono.Runtime") != null; }
147 }
148
123 /// <summary> 149 /// <summary>
124 /// Gets the name of the directory where the current running executable 150 /// Gets the name of the directory where the current running executable
125 /// is located 151 /// is located
@@ -495,20 +521,18 @@ namespace OpenSim.Framework
495 521
496 public static int ToUnixTime(DateTime stamp) 522 public static int ToUnixTime(DateTime stamp)
497 { 523 {
498 TimeSpan t = stamp.ToUniversalTime() - unixEpoch; 524 TimeSpan t = stamp.ToUniversalTime() - UnixEpoch;
499 return (int) t.TotalSeconds; 525 return (int)t.TotalSeconds;
500 } 526 }
501 527
502 public static DateTime ToDateTime(ulong seconds) 528 public static DateTime ToDateTime(ulong seconds)
503 { 529 {
504 DateTime epoch = unixEpoch; 530 return UnixEpoch.AddSeconds(seconds);
505 return epoch.AddSeconds(seconds);
506 } 531 }
507 532
508 public static DateTime ToDateTime(int seconds) 533 public static DateTime ToDateTime(int seconds)
509 { 534 {
510 DateTime epoch = unixEpoch; 535 return UnixEpoch.AddSeconds(seconds);
511 return epoch.AddSeconds(seconds);
512 } 536 }
513 537
514 /// <summary> 538 /// <summary>
@@ -1233,7 +1257,7 @@ namespace OpenSim.Framework
1233 byte[] bytes = 1257 byte[] bytes =
1234 { 1258 {
1235 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), 1259 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1236 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), 1260 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
1237 (byte)x, (byte)(x >> 8), 0, 0, 1261 (byte)x, (byte)(x >> 8), 0, 0,
1238 (byte)y, (byte)(y >> 8), 0, 0 }; 1262 (byte)y, (byte)(y >> 8), 0, 0 };
1239 return new UUID(bytes, 0); 1263 return new UUID(bytes, 0);
@@ -1244,7 +1268,7 @@ namespace OpenSim.Framework
1244 byte[] bytes = 1268 byte[] bytes =
1245 { 1269 {
1246 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24), 1270 (byte)regionHandle, (byte)(regionHandle >> 8), (byte)(regionHandle >> 16), (byte)(regionHandle >> 24),
1247 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle << 56), 1271 (byte)(regionHandle >> 32), (byte)(regionHandle >> 40), (byte)(regionHandle >> 48), (byte)(regionHandle >> 56),
1248 (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8), 1272 (byte)x, (byte)(x >> 8), (byte)z, (byte)(z >> 8),
1249 (byte)y, (byte)(y >> 8), 0, 0 }; 1273 (byte)y, (byte)(y >> 8), 0, 0 };
1250 return new UUID(bytes, 0); 1274 return new UUID(bytes, 0);
@@ -1317,7 +1341,7 @@ namespace OpenSim.Framework
1317 ru = "OSX/Mono"; 1341 ru = "OSX/Mono";
1318 else 1342 else
1319 { 1343 {
1320 if (Type.GetType("Mono.Runtime") != null) 1344 if (IsPlatformMono)
1321 ru = "Win/Mono"; 1345 ru = "Win/Mono";
1322 else 1346 else
1323 ru = "Win/.NET"; 1347 ru = "Win/.NET";
@@ -1765,10 +1789,12 @@ namespace OpenSim.Framework
1765 FireAndForget(callback, null); 1789 FireAndForget(callback, null);
1766 } 1790 }
1767 1791
1768 public static void InitThreadPool(int maxThreads) 1792 public static void InitThreadPool(int minThreads, int maxThreads)
1769 { 1793 {
1770 if (maxThreads < 2) 1794 if (maxThreads < 2)
1771 throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2"); 1795 throw new ArgumentOutOfRangeException("maxThreads", "maxThreads must be greater than 2");
1796 if (minThreads > maxThreads || minThreads < 2)
1797 throw new ArgumentOutOfRangeException("minThreads", "minThreads must be greater than 2 and less than or equal to maxThreads");
1772 if (m_ThreadPool != null) 1798 if (m_ThreadPool != null)
1773 throw new InvalidOperationException("SmartThreadPool is already initialized"); 1799 throw new InvalidOperationException("SmartThreadPool is already initialized");
1774 1800
@@ -1776,7 +1802,7 @@ namespace OpenSim.Framework
1776 startInfo.ThreadPoolName = "Util"; 1802 startInfo.ThreadPoolName = "Util";
1777 startInfo.IdleTimeout = 2000; 1803 startInfo.IdleTimeout = 2000;
1778 startInfo.MaxWorkerThreads = maxThreads; 1804 startInfo.MaxWorkerThreads = maxThreads;
1779 startInfo.MinWorkerThreads = 2; 1805 startInfo.MinWorkerThreads = minThreads;
1780 1806
1781 m_ThreadPool = new SmartThreadPool(startInfo); 1807 m_ThreadPool = new SmartThreadPool(startInfo);
1782 } 1808 }
@@ -1851,8 +1877,8 @@ namespace OpenSim.Framework
1851 break; 1877 break;
1852 case FireAndForgetMethod.SmartThreadPool: 1878 case FireAndForgetMethod.SmartThreadPool:
1853 if (m_ThreadPool == null) 1879 if (m_ThreadPool == null)
1854 InitThreadPool(15); 1880 InitThreadPool(2, 15);
1855 m_ThreadPool.QueueWorkItem(SmartThreadPoolCallback, new object[] { realCallback, obj }); 1881 m_ThreadPool.QueueWorkItem((cb, o) => cb(o), realCallback, obj);
1856 break; 1882 break;
1857 case FireAndForgetMethod.Thread: 1883 case FireAndForgetMethod.Thread:
1858 Thread thread = new Thread(delegate(object o) { realCallback(o); }); 1884 Thread thread = new Thread(delegate(object o) { realCallback(o); });
@@ -1864,72 +1890,29 @@ namespace OpenSim.Framework
1864 } 1890 }
1865 1891
1866 /// <summary> 1892 /// <summary>
1867 /// Get a thread pool report. 1893 /// Get information about the current state of the smart thread pool.
1868 /// </summary> 1894 /// </summary>
1869 /// <returns></returns> 1895 /// <returns>
1870 public static string GetThreadPoolReport() 1896 /// null if this isn't the pool being used for non-scriptengine threads.
1897 /// </returns>
1898 public static STPInfo GetSmartThreadPoolInfo()
1871 { 1899 {
1872 string threadPoolUsed = null; 1900 if (m_ThreadPool == null)
1873 int maxThreads = 0; 1901 return null;
1874 int minThreads = 0;
1875 int allocatedThreads = 0;
1876 int inUseThreads = 0;
1877 int waitingCallbacks = 0;
1878 int completionPortThreads = 0;
1879
1880 StringBuilder sb = new StringBuilder();
1881 if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
1882 {
1883 // ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
1884 if (m_ThreadPool != null)
1885 {
1886 threadPoolUsed = "SmartThreadPool";
1887 maxThreads = m_ThreadPool.MaxThreads;
1888 minThreads = m_ThreadPool.MinThreads;
1889 inUseThreads = m_ThreadPool.InUseThreads;
1890 allocatedThreads = m_ThreadPool.ActiveThreads;
1891 waitingCallbacks = m_ThreadPool.WaitingCallbacks;
1892 }
1893 }
1894 else if (
1895 FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
1896 || FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem)
1897 {
1898 threadPoolUsed = "BuiltInThreadPool";
1899 ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads);
1900 ThreadPool.GetMinThreads(out minThreads, out completionPortThreads);
1901 int availableThreads;
1902 ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);
1903 inUseThreads = maxThreads - availableThreads;
1904 allocatedThreads = -1;
1905 waitingCallbacks = -1;
1906 }
1907
1908 if (threadPoolUsed != null)
1909 {
1910 sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed);
1911 sb.AppendFormat("Max threads : {0}\n", maxThreads);
1912 sb.AppendFormat("Min threads : {0}\n", minThreads);
1913 sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString());
1914 sb.AppendFormat("In use threads : {0}\n", inUseThreads);
1915 sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString());
1916 }
1917 else
1918 {
1919 sb.AppendFormat("Thread pool not used\n");
1920 }
1921
1922 return sb.ToString();
1923 }
1924 1902
1925 private static object SmartThreadPoolCallback(object o) 1903 STPInfo stpi = new STPInfo();
1926 { 1904 stpi.Name = m_ThreadPool.Name;
1927 object[] array = (object[])o; 1905 stpi.STPStartInfo = m_ThreadPool.STPStartInfo;
1928 WaitCallback callback = (WaitCallback)array[0]; 1906 stpi.IsIdle = m_ThreadPool.IsIdle;
1929 object obj = array[1]; 1907 stpi.IsShuttingDown = m_ThreadPool.IsShuttingdown;
1908 stpi.MaxThreads = m_ThreadPool.MaxThreads;
1909 stpi.MinThreads = m_ThreadPool.MinThreads;
1910 stpi.InUseThreads = m_ThreadPool.InUseThreads;
1911 stpi.ActiveThreads = m_ThreadPool.ActiveThreads;
1912 stpi.WaitingCallbacks = m_ThreadPool.WaitingCallbacks;
1913 stpi.MaxConcurrentWorkItems = m_ThreadPool.Concurrency;
1930 1914
1931 callback(obj); 1915 return stpi;
1932 return null;
1933 } 1916 }
1934 1917
1935 #endregion FireAndForget Threading Pattern 1918 #endregion FireAndForget Threading Pattern
@@ -2148,7 +2131,7 @@ namespace OpenSim.Framework
2148 /// <param name="secret">the secret part</param> 2131 /// <param name="secret">the secret part</param>
2149 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret) 2132 public static bool ParseUniversalUserIdentifier(string value, out UUID uuid, out string url, out string firstname, out string lastname, out string secret)
2150 { 2133 {
2151 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "User"; secret = string.Empty; 2134 uuid = UUID.Zero; url = string.Empty; firstname = "Unknown"; lastname = "UserUPUUI"; secret = string.Empty;
2152 2135
2153 string[] parts = value.Split(';'); 2136 string[] parts = value.Split(';');
2154 if (parts.Length >= 1) 2137 if (parts.Length >= 1)
@@ -2282,7 +2265,7 @@ namespace OpenSim.Framework
2282 { 2265 {
2283 lock (m_syncRoot) 2266 lock (m_syncRoot)
2284 { 2267 {
2285 m_lowQueue.Enqueue(data); 2268 q.Enqueue(data);
2286 m_s.WaitOne(0); 2269 m_s.WaitOne(0);
2287 m_s.Release(); 2270 m_s.Release();
2288 } 2271 }
@@ -2322,7 +2305,7 @@ namespace OpenSim.Framework
2322 { 2305 {
2323 if (m_highQueue.Count > 0) 2306 if (m_highQueue.Count > 0)
2324 res = m_highQueue.Dequeue(); 2307 res = m_highQueue.Dequeue();
2325 else 2308 else if (m_lowQueue.Count > 0)
2326 res = m_lowQueue.Dequeue(); 2309 res = m_lowQueue.Dequeue();
2327 2310
2328 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0) 2311 if (m_highQueue.Count == 0 && m_lowQueue.Count == 0)
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index bf57fd4..9fa93ea 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -67,6 +67,11 @@ namespace OpenSim.Framework
67 public static int RequestNumber { get; internal set; } 67 public static int RequestNumber { get; internal set; }
68 68
69 /// <summary> 69 /// <summary>
70 /// Control where OSD requests should be serialized per endpoint.
71 /// </summary>
72 public static bool SerializeOSDRequestsPerEndpoint { get; set; }
73
74 /// <summary>
70 /// this is the header field used to communicate the local request id 75 /// this is the header field used to communicate the local request id
71 /// used for performance and debugging 76 /// used for performance and debugging
72 /// </summary> 77 /// </summary>
@@ -145,10 +150,50 @@ namespace OpenSim.Framework
145 150
146 public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed) 151 public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed)
147 { 152 {
148 lock (EndPointLock(url)) 153 if (SerializeOSDRequestsPerEndpoint)
154 {
155 lock (EndPointLock(url))
156 {
157 return ServiceOSDRequestWorker(url, data, method, timeout, compressed);
158 }
159 }
160 else
161 {
162 return ServiceOSDRequestWorker(url, data, method, timeout, compressed);
163 }
164 }
165
166 public static void LogOutgoingDetail(Stream outputStream)
167 {
168 using (StreamReader reader = new StreamReader(Util.Copy(outputStream), Encoding.UTF8))
169 {
170 string output;
171
172 if (DebugLevel == 5)
173 {
174 const int sampleLength = 80;
175 char[] sampleChars = new char[sampleLength];
176 reader.Read(sampleChars, 0, sampleLength);
177 output = new string(sampleChars);
178 }
179 else
180 {
181 output = reader.ReadToEnd();
182 }
183
184 LogOutgoingDetail(output);
185 }
186 }
187
188 public static void LogOutgoingDetail(string output)
189 {
190 if (DebugLevel == 5)
149 { 191 {
150 return ServiceOSDRequestWorker(url,data,method,timeout,compressed); 192 output = output.Substring(0, 80);
193 output = output + "...";
151 } 194 }
195
196 m_log.DebugFormat("[WEB UTIL]: {0}", output.Replace("\n", @"\n"));
152 } 197 }
153 198
154 private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed) 199 private static OSDMap ServiceOSDRequestWorker(string url, OSDMap data, string method, int timeout, bool compressed)
@@ -178,7 +223,11 @@ namespace OpenSim.Framework
178 // If there is some input, write it into the request 223 // If there is some input, write it into the request
179 if (data != null) 224 if (data != null)
180 { 225 {
181 strBuffer = OSDParser.SerializeJsonString(data); 226 strBuffer = OSDParser.SerializeJsonString(data);
227
228 if (DebugLevel >= 5)
229 LogOutgoingDetail(strBuffer);
230
182 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer); 231 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer);
183 232
184 if (compressed) 233 if (compressed)
@@ -358,6 +407,10 @@ namespace OpenSim.Framework
358 if (data != null) 407 if (data != null)
359 { 408 {
360 queryString = BuildQueryString(data); 409 queryString = BuildQueryString(data);
410
411 if (DebugLevel >= 5)
412 LogOutgoingDetail(queryString);
413
361 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString); 414 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString);
362 415
363 request.ContentLength = buffer.Length; 416 request.ContentLength = buffer.Length;
@@ -769,6 +822,9 @@ namespace OpenSim.Framework
769 int length = (int)buffer.Length; 822 int length = (int)buffer.Length;
770 request.ContentLength = length; 823 request.ContentLength = length;
771 824
825 if (WebUtil.DebugLevel >= 5)
826 WebUtil.LogOutgoingDetail(buffer);
827
772 request.BeginGetRequestStream(delegate(IAsyncResult res) 828 request.BeginGetRequestStream(delegate(IAsyncResult res)
773 { 829 {
774 Stream requestStream = request.EndGetRequestStream(res); 830 Stream requestStream = request.EndGetRequestStream(res);
@@ -928,11 +984,12 @@ namespace OpenSim.Framework
928 /// <param name="verb"></param> 984 /// <param name="verb"></param>
929 /// <param name="requestUrl"></param> 985 /// <param name="requestUrl"></param>
930 /// <param name="obj"> </param> 986 /// <param name="obj"> </param>
987 /// <param name="timeoutsecs"> </param>
931 /// <returns></returns> 988 /// <returns></returns>
932 /// 989 ///
933 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting 990 /// <exception cref="System.Net.WebException">Thrown if we encounter a network issue while posting
934 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception> 991 /// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
935 public static string MakeRequest(string verb, string requestUrl, string obj) 992 public static string MakeRequest(string verb, string requestUrl, string obj, int timeoutsecs)
936 { 993 {
937 int reqnum = WebUtil.RequestNumber++; 994 int reqnum = WebUtil.RequestNumber++;
938 995
@@ -946,6 +1003,8 @@ namespace OpenSim.Framework
946 1003
947 WebRequest request = WebRequest.Create(requestUrl); 1004 WebRequest request = WebRequest.Create(requestUrl);
948 request.Method = verb; 1005 request.Method = verb;
1006 if (timeoutsecs > 0)
1007 request.Timeout = timeoutsecs * 1000;
949 string respstring = String.Empty; 1008 string respstring = String.Empty;
950 1009
951 int tickset = Util.EnvironmentTickCountSubtract(tickstart); 1010 int tickset = Util.EnvironmentTickCountSubtract(tickstart);
@@ -966,6 +1025,9 @@ namespace OpenSim.Framework
966 length = (int)obj.Length; 1025 length = (int)obj.Length;
967 request.ContentLength = length; 1026 request.ContentLength = length;
968 1027
1028 if (WebUtil.DebugLevel >= 5)
1029 WebUtil.LogOutgoingDetail(buffer);
1030
969 Stream requestStream = null; 1031 Stream requestStream = null;
970 try 1032 try
971 { 1033 {
@@ -1039,6 +1101,11 @@ namespace OpenSim.Framework
1039 1101
1040 return respstring; 1102 return respstring;
1041 } 1103 }
1104
1105 public static string MakeRequest(string verb, string requestUrl, string obj)
1106 {
1107 return MakeRequest(verb, requestUrl, obj, -1);
1108 }
1042 } 1109 }
1043 1110
1044 public class SynchronousRestObjectRequester 1111 public class SynchronousRestObjectRequester
@@ -1111,6 +1178,9 @@ namespace OpenSim.Framework
1111 int length = (int)buffer.Length; 1178 int length = (int)buffer.Length;
1112 request.ContentLength = length; 1179 request.ContentLength = length;
1113 1180
1181 if (WebUtil.DebugLevel >= 5)
1182 WebUtil.LogOutgoingDetail(buffer);
1183
1114 Stream requestStream = null; 1184 Stream requestStream = null;
1115 try 1185 try
1116 { 1186 {
@@ -1213,4 +1283,4 @@ namespace OpenSim.Framework
1213 return deserial; 1283 return deserial;
1214 } 1284 }
1215 } 1285 }
1216} 1286} \ No newline at end of file