diff --git a/.nant/local.include b/.nant/local.include
index 4fa3e4df4b..6d3e97228f 100644
--- a/.nant/local.include
+++ b/.nant/local.include
@@ -2,13 +2,37 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/OpenSim/Data/MSSQL/MSSQLFriendsData.cs b/OpenSim/Data/MSSQL/MSSQLFriendsData.cs
index 09dde5e182..fef6978f33 100644
--- a/OpenSim/Data/MSSQL/MSSQLFriendsData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLFriendsData.cs
@@ -89,5 +89,11 @@ namespace OpenSim.Data.MSSQL
return DoQuery(cmd);
}
}
+
+ public FriendsData[] GetFriends(Guid principalID)
+ {
+ return GetFriends(principalID.ToString());
+ }
+
}
}
diff --git a/OpenSim/Data/MSSQL/MSSQLInventoryData.cs b/OpenSim/Data/MSSQL/MSSQLInventoryData.cs
index 4d06377452..961593fc6f 100644
--- a/OpenSim/Data/MSSQL/MSSQLInventoryData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLInventoryData.cs
@@ -813,7 +813,7 @@ namespace OpenSim.Data.MSSQL
{
try
{
- using (SqlCommand command = new SqlCommand("DELETE FROM inventoryfolders WHERE folderID=@folderID", connection))
+ using (SqlCommand command = new SqlCommand("DELETE FROM inventoryfolders WHERE folderID=@folderID and type=-1", connection))
{
command.Parameters.Add(database.CreateParameter("folderID", folderID));
diff --git a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
index e58620a7a0..d9dfe864ec 100644
--- a/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
+++ b/OpenSim/Data/MSSQL/MSSQLSimulationData.cs
@@ -675,7 +675,7 @@ VALUES
cmd.ExecuteNonQuery();
}
- sql = "INSERT INTO [landaccesslist] ([LandUUID],[AccessUUID],[Flags]) VALUES (@LandUUID,@AccessUUID,@Flags)";
+ sql = "INSERT INTO [landaccesslist] ([LandUUID],[AccessUUID],[Flags],[Expires]) VALUES (@LandUUID,@AccessUUID,@Flags,@Expires)";
using (SqlConnection conn = new SqlConnection(m_connectionString))
using (SqlCommand cmd = new SqlCommand(sql, conn))
@@ -1215,6 +1215,8 @@ VALUES
//Store new values
StoreNewRegionSettings(regionSettings);
+ LoadSpawnPoints(regionSettings);
+
return regionSettings;
}
@@ -1252,7 +1254,7 @@ VALUES
,[elevation_1_ne] = @elevation_1_ne ,[elevation_2_ne] = @elevation_2_ne ,[elevation_1_se] = @elevation_1_se ,[elevation_2_se] = @elevation_2_se
,[elevation_1_sw] = @elevation_1_sw ,[elevation_2_sw] = @elevation_2_sw ,[water_height] = @water_height ,[terrain_raise_limit] = @terrain_raise_limit
,[terrain_lower_limit] = @terrain_lower_limit ,[use_estate_sun] = @use_estate_sun ,[fixed_sun] = @fixed_sun ,[sun_position] = @sun_position
-,[covenant] = @covenant ,[covenant_datetime] = @covenant_datetime, [sunvectorx] = @sunvectorx, [sunvectory] = @sunvectory, [sunvectorz] = @sunvectorz, [Sandbox] = @Sandbox, [loaded_creation_datetime] = @loaded_creation_datetime, [loaded_creation_id] = @loaded_creation_id
+,[covenant] = @covenant ,[covenant_datetime] = @covenant_datetime, [sunvectorx] = @sunvectorx, [sunvectory] = @sunvectory, [sunvectorz] = @sunvectorz, [Sandbox] = @Sandbox, [loaded_creation_datetime] = @loaded_creation_datetime, [loaded_creation_id] = @loaded_creation_id, [map_tile_id] = @TerrainImageID, [telehubobject] = @telehubobject, [parcel_tile_id] = @ParcelImageID
WHERE [regionUUID] = @regionUUID";
using (SqlConnection conn = new SqlConnection(m_connectionString))
@@ -1263,6 +1265,7 @@ VALUES
cmd.ExecuteNonQuery();
}
}
+ SaveSpawnPoints(regionSettings);
}
public void Shutdown()
@@ -1367,7 +1370,7 @@ VALUES
newSettings.TerrainRaiseLimit = Convert.ToDouble(row["terrain_raise_limit"]);
newSettings.TerrainLowerLimit = Convert.ToDouble(row["terrain_lower_limit"]);
newSettings.UseEstateSun = Convert.ToBoolean(row["use_estate_sun"]);
- newSettings.Sandbox = Convert.ToBoolean(row["sandbox"]);
+ newSettings.Sandbox = Convert.ToBoolean(row["Sandbox"]);
newSettings.FixedSun = Convert.ToBoolean(row["fixed_sun"]);
newSettings.SunPosition = Convert.ToDouble(row["sun_position"]);
newSettings.SunVector = new Vector3(
@@ -1383,6 +1386,11 @@ VALUES
newSettings.LoadedCreationID = "";
else
newSettings.LoadedCreationID = (String)row["loaded_creation_id"];
+
+ newSettings.TerrainImageID = new UUID((string)row["map_tile_ID"]);
+ newSettings.ParcelImageID = new UUID((Guid)row["parcel_tile_ID"]);
+ newSettings.TelehubObject = new UUID((Guid)row["TelehubObject"]);
+
return newSettings;
}
@@ -1454,6 +1462,13 @@ VALUES
}
newData.ParcelAccessList = new List();
+ newData.MediaDescription = (string)row["MediaDescription"];
+ newData.MediaType = (string)row["MediaType"];
+ newData.MediaWidth = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[0]);
+ newData.MediaHeight = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[1]);
+ newData.MediaLoop = Convert.ToBoolean(row["MediaLoop"]);
+ newData.ObscureMusic = Convert.ToBoolean(row["ObscureMusic"]);
+ newData.ObscureMedia = Convert.ToBoolean(row["ObscureMedia"]);
return newData;
}
@@ -1468,7 +1483,7 @@ VALUES
LandAccessEntry entry = new LandAccessEntry();
entry.AgentID = new UUID((Guid)row["AccessUUID"]);
entry.Flags = (AccessList)Convert.ToInt32(row["Flags"]);
- entry.Expires = 0;
+ entry.Expires = Convert.ToInt32(row["Expires"]);
return entry;
}
@@ -1497,7 +1512,8 @@ VALUES
prim.TouchName = (string)primRow["TouchName"];
// permissions
prim.Flags = (PrimFlags)Convert.ToUInt32(primRow["ObjectFlags"]);
- prim.CreatorID = new UUID((Guid)primRow["CreatorID"]);
+ //prim.CreatorID = new UUID((Guid)primRow["CreatorID"]);
+ prim.CreatorIdentification = (string)primRow["CreatorID"];
prim.OwnerID = new UUID((Guid)primRow["OwnerID"]);
prim.GroupID = new UUID((Guid)primRow["GroupID"]);
prim.LastOwnerID = new UUID((Guid)primRow["LastOwnerID"]);
@@ -1691,7 +1707,8 @@ VALUES
taskItem.Name = (string)inventoryRow["name"];
taskItem.Description = (string)inventoryRow["description"];
taskItem.CreationDate = Convert.ToUInt32(inventoryRow["creationDate"]);
- taskItem.CreatorID = new UUID((Guid)inventoryRow["creatorID"]);
+ //taskItem.CreatorID = new UUID((Guid)inventoryRow["creatorID"]);
+ taskItem.CreatorIdentification = (string)inventoryRow["creatorID"];
taskItem.OwnerID = new UUID((Guid)inventoryRow["ownerID"]);
taskItem.LastOwnerID = new UUID((Guid)inventoryRow["lastOwnerID"]);
taskItem.GroupID = new UUID((Guid)inventoryRow["groupID"]);
@@ -1782,7 +1799,7 @@ VALUES
parameters.Add(_Database.CreateParameter("terrain_raise_limit", settings.TerrainRaiseLimit));
parameters.Add(_Database.CreateParameter("terrain_lower_limit", settings.TerrainLowerLimit));
parameters.Add(_Database.CreateParameter("use_estate_sun", settings.UseEstateSun));
- parameters.Add(_Database.CreateParameter("sandbox", settings.Sandbox));
+ parameters.Add(_Database.CreateParameter("Sandbox", settings.Sandbox));
parameters.Add(_Database.CreateParameter("fixed_sun", settings.FixedSun));
parameters.Add(_Database.CreateParameter("sun_position", settings.SunPosition));
parameters.Add(_Database.CreateParameter("sunvectorx", settings.SunVector.X));
@@ -1792,6 +1809,9 @@ VALUES
parameters.Add(_Database.CreateParameter("covenant_datetime", settings.CovenantChangedDateTime));
parameters.Add(_Database.CreateParameter("Loaded_Creation_DateTime", settings.LoadedCreationDateTime));
parameters.Add(_Database.CreateParameter("Loaded_Creation_ID", settings.LoadedCreationID));
+ parameters.Add(_Database.CreateParameter("TerrainImageID", settings.TerrainImageID));
+ parameters.Add(_Database.CreateParameter("ParcelImageID", settings.ParcelImageID));
+ parameters.Add(_Database.CreateParameter("TelehubObject", settings.TelehubObject));
return parameters.ToArray();
}
@@ -1859,6 +1879,7 @@ VALUES
parameters.Add(_Database.CreateParameter("LandUUID", parcelID));
parameters.Add(_Database.CreateParameter("AccessUUID", parcelAccessEntry.AgentID));
parameters.Add(_Database.CreateParameter("Flags", parcelAccessEntry.Flags));
+ parameters.Add(_Database.CreateParameter("Expires", parcelAccessEntry.Expires));
return parameters.ToArray();
}
@@ -2063,5 +2084,57 @@ VALUES
#endregion
#endregion
+
+ private void LoadSpawnPoints(RegionSettings rs)
+ {
+ rs.ClearSpawnPoints();
+
+ string sql = "SELECT Yaw, Pitch, Distance FROM spawn_points WHERE RegionUUID = @RegionUUID";
+ using (SqlConnection conn = new SqlConnection(m_connectionString))
+ using (SqlCommand cmd = new SqlCommand(sql, conn))
+ {
+ cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID.ToString()));
+ conn.Open();
+ using (SqlDataReader reader = cmd.ExecuteReader())
+ {
+ if (reader.Read())
+ {
+ SpawnPoint sp = new SpawnPoint();
+
+ sp.Yaw = (float)reader["Yaw"];
+ sp.Pitch = (float)reader["Pitch"];
+ sp.Distance = (float)reader["Distance"];
+
+ rs.AddSpawnPoint(sp);
+ }
+ }
+ }
+ }
+
+ private void SaveSpawnPoints(RegionSettings rs)
+ {
+ string sql = "DELETE FROM spawn_points WHERE RegionUUID = @RegionUUID";
+ using (SqlConnection conn = new SqlConnection(m_connectionString))
+ using (SqlCommand cmd = new SqlCommand(sql, conn))
+ {
+ cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID));
+ conn.Open();
+ cmd.ExecuteNonQuery();
+ }
+ foreach (SpawnPoint p in rs.SpawnPoints())
+ {
+ sql = "INSERT INTO spawn_points (RegionUUID, Yaw, Pitch, Distance) VALUES (@RegionUUID, @Yaw, @Pitch, @Distance)";
+ using (SqlConnection conn = new SqlConnection(m_connectionString))
+ using (SqlCommand cmd = new SqlCommand(sql, conn))
+ {
+ cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID));
+ cmd.Parameters.Add(_Database.CreateParameter("@Yaw", p.Yaw));
+ cmd.Parameters.Add(_Database.CreateParameter("@Pitch", p.Pitch));
+ cmd.Parameters.Add(_Database.CreateParameter("@Distance", p.Distance));
+ conn.Open();
+ cmd.ExecuteNonQuery();
+ }
+ }
+ }
}
}
diff --git a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
index a98690affb..d6a3be9282 100644
--- a/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
+++ b/OpenSim/Data/MSSQL/Resources/RegionStore.migrations
@@ -1044,10 +1044,93 @@ ALTER TABLE primitems ALTER COLUMN CreatorID uniqueidentifier NOT NULL
COMMIT
-:VERSION 29 #---------------------
+:VERSION 29 #----------------- Region Covenant changed time
BEGIN TRANSACTION
ALTER TABLE regionsettings ADD covenant_datetime int NOT NULL default 0
COMMIT
+
+:VERSION 30 #------------------Migrate creatorID storage to varchars instead of UUIDs for HG support
+
+BEGIN TRANSACTION
+
+EXECUTE sp_rename N'dbo.prims.creatorid', N'creatoridold', 'COLUMN'
+EXECUTE sp_rename N'dbo.primitems.creatorid', N'creatoridold', 'COLUMN'
+
+COMMIT
+
+:VERSION 31 #---------------------
+
+BEGIN TRANSACTION
+
+ALTER TABLE prims ADD CreatorID varchar(255)
+ALTER TABLE primitems ADD CreatorID varchar(255)
+
+COMMIT
+
+:VERSION 32 #---------------------
+
+BEGIN TRANSACTION
+
+UPDATE prims SET prims.CreatorID = CONVERT(varchar(255), creatoridold)
+UPDATE primitems SET primitems.CreatorID = CONVERT(varchar(255), creatoridold)
+
+COMMIT
+
+:VERSION 33 #---------------------
+
+BEGIN TRANSACTION
+
+ALTER TABLE prims
+ADD CONSTRAINT DF_prims_CreatorIDNew
+DEFAULT '00000000-0000-0000-0000-000000000000'
+FOR CreatorID
+
+ALTER TABLE prims ALTER COLUMN CreatorID varchar(255) NOT NULL
+
+ALTER TABLE primitems
+ADD CONSTRAINT DF_primitems_CreatorIDNew
+DEFAULT '00000000-0000-0000-0000-000000000000'
+FOR CreatorID
+
+ALTER TABLE primitems ALTER COLUMN CreatorID varchar(255) NOT NULL
+
+COMMIT
+
+:VERSION 34 #--------------- Telehub support
+
+BEGIN TRANSACTION
+
+CREATE TABLE [dbo].[Spawn_Points](
+ [RegionUUID] [uniqueidentifier] NOT NULL,
+ [Yaw] [float] NOT NULL,
+ [Pitch] [float] NOT NULL,
+ [Distance] [float] NOT NULL,
+ PRIMARY KEY CLUSTERED
+ (
+ [RegionUUID] ASC
+ )WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
+) ON [PRIMARY]
+
+ALTER TABLE regionsettings ADD TelehubObject uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000';
+
+COMMIT
+
+:VERSION 35 #---------------- Parcels for sale
+
+BEGIN TRANSACTION
+
+ALTER TABLE regionsettings ADD parcel_tile_ID uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000';
+
+COMMIT
+
+:VERSION 36 #---------------- Timed bans/access
+
+BEGIN TRANSACTION
+
+ALTER TABLE landaccesslist ADD Expires integer NOT NULL DEFAULT 0;
+
+COMMIT
+
diff --git a/OpenSim/Data/MySQL/MySQLSimulationData.cs b/OpenSim/Data/MySQL/MySQLSimulationData.cs
index 5dafc0beb3..119754821d 100644
--- a/OpenSim/Data/MySQL/MySQLSimulationData.cs
+++ b/OpenSim/Data/MySQL/MySQLSimulationData.cs
@@ -1315,7 +1315,7 @@ namespace OpenSim.Data.MySQL
newSettings.TerrainRaiseLimit = Convert.ToDouble(row["terrain_raise_limit"]);
newSettings.TerrainLowerLimit = Convert.ToDouble(row["terrain_lower_limit"]);
newSettings.UseEstateSun = Convert.ToBoolean(row["use_estate_sun"]);
- newSettings.Sandbox = Convert.ToBoolean(row["sandbox"]);
+ newSettings.Sandbox = Convert.ToBoolean(row["Sandbox"]);
newSettings.SunVector = new Vector3 (
Convert.ToSingle(row["sunvectorx"]),
Convert.ToSingle(row["sunvectory"]),
diff --git a/OpenSim/Data/MySQL/MySQLXAssetData.cs b/OpenSim/Data/MySQL/MySQLXAssetData.cs
new file mode 100644
index 0000000000..95ef72a09b
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLXAssetData.cs
@@ -0,0 +1,500 @@
+/*
+ * Copyright (c) Contributors, http://opensimulator.org/
+ * See CONTRIBUTORS.TXT for a full list of copyright holders.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * * Neither the name of the OpenSimulator Project nor the
+ * names of its contributors may be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.IO;
+using System.IO.Compression;
+using System.Reflection;
+using System.Security.Cryptography;
+using System.Text;
+using log4net;
+using MySql.Data.MySqlClient;
+using OpenMetaverse;
+using OpenSim.Framework;
+using OpenSim.Data;
+
+namespace OpenSim.Data.MySQL
+{
+ public class MySQLXAssetData : AssetDataBase
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ protected virtual Assembly Assembly
+ {
+ get { return GetType().Assembly; }
+ }
+
+ private bool m_enableCompression = false;
+ private string m_connectionString;
+ private object m_dbLock = new object();
+
+ ///
+ /// We can reuse this for all hashing since all methods are single-threaded through m_dbBLock
+ ///
+ private HashAlgorithm hasher = new SHA256CryptoServiceProvider();
+
+ #region IPlugin Members
+
+ public override string Version { get { return "1.0.0.0"; } }
+
+ ///
+ /// Initialises Asset interface
+ ///
+ ///
+ /// - Loads and initialises the MySQL storage plugin.
+ /// - Warns and uses the obsolete mysql_connection.ini if connect string is empty.
+ /// - Check for migration
+ ///
+ ///
+ ///
+ /// connect string
+ public override void Initialise(string connect)
+ {
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: ***********************************************************");
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: ***********************************************************");
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: ***********************************************************");
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: THIS PLUGIN IS STRICTLY EXPERIMENTAL.");
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: DO NOT USE FOR ANY DATA THAT YOU DO NOT MIND LOSING.");
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: DATABASE TABLES CAN CHANGE AT ANY TIME, CAUSING EXISTING DATA TO BE LOST.");
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: ***********************************************************");
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: ***********************************************************");
+ m_log.ErrorFormat("[MYSQL XASSETDATA]: ***********************************************************");
+
+ m_connectionString = connect;
+
+ using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
+ {
+ dbcon.Open();
+ Migration m = new Migration(dbcon, Assembly, "XAssetStore");
+ m.Update();
+ }
+ }
+
+ public override void Initialise()
+ {
+ throw new NotImplementedException();
+ }
+
+ public override void Dispose() { }
+
+ ///
+ /// The name of this DB provider
+ ///
+ override public string Name
+ {
+ get { return "MySQL XAsset storage engine"; }
+ }
+
+ #endregion
+
+ #region IAssetDataPlugin Members
+
+ ///
+ /// Fetch Asset from database
+ ///
+ /// Asset UUID to fetch
+ /// Return the asset
+ /// On failure : throw an exception and attempt to reconnect to database
+ override public AssetBase GetAsset(UUID assetID)
+ {
+// m_log.DebugFormat("[MYSQL XASSET DATA]: Looking for asset {0}", assetID);
+
+ AssetBase asset = null;
+ lock (m_dbLock)
+ {
+ using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
+ {
+ dbcon.Open();
+
+ using (MySqlCommand cmd = new MySqlCommand(
+ "SELECT name, description, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id",
+ dbcon))
+ {
+ cmd.Parameters.AddWithValue("?id", assetID.ToString());
+
+ try
+ {
+ using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
+ {
+ if (dbReader.Read())
+ {
+ asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["asset_type"], dbReader["creator_id"].ToString());
+ asset.Data = (byte[])dbReader["data"];
+ asset.Description = (string)dbReader["description"];
+
+ string local = dbReader["local"].ToString();
+ if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
+ asset.Local = true;
+ else
+ asset.Local = false;
+
+ asset.Temporary = Convert.ToBoolean(dbReader["temporary"]);
+ asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
+
+ if (m_enableCompression)
+ {
+ using (GZipStream decompressionStream = new GZipStream(new MemoryStream(asset.Data), CompressionMode.Decompress))
+ {
+ MemoryStream outputStream = new MemoryStream();
+ WebUtil.CopyTo(decompressionStream, outputStream, int.MaxValue);
+ // int compressedLength = asset.Data.Length;
+ asset.Data = outputStream.ToArray();
+
+ // m_log.DebugFormat(
+ // "[XASSET DB]: Decompressed {0} {1} to {2} bytes from {3}",
+ // asset.ID, asset.Name, asset.Data.Length, compressedLength);
+ }
+ }
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.Error("[MYSQL XASSET DATA]: MySql failure fetching asset " + assetID + ": " + e.Message);
+ }
+ }
+ }
+ }
+
+ return asset;
+ }
+
+ ///
+ /// Create an asset in database, or update it if existing.
+ ///
+ /// Asset UUID to create
+ /// On failure : Throw an exception and attempt to reconnect to database
+ override public void StoreAsset(AssetBase asset)
+ {
+ lock (m_dbLock)
+ {
+ using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
+ {
+ dbcon.Open();
+
+ using (MySqlTransaction transaction = dbcon.BeginTransaction())
+ {
+ string assetName = asset.Name;
+ if (asset.Name.Length > 64)
+ {
+ assetName = asset.Name.Substring(0, 64);
+ m_log.Warn("[XASSET DB]: Name field truncated from " + asset.Name.Length + " to " + assetName.Length + " characters on add");
+ }
+
+ string assetDescription = asset.Description;
+ if (asset.Description.Length > 64)
+ {
+ assetDescription = asset.Description.Substring(0, 64);
+ m_log.Warn("[XASSET DB]: Description field truncated from " + asset.Description.Length + " to " + assetDescription.Length + " characters on add");
+ }
+
+ if (m_enableCompression)
+ {
+ MemoryStream outputStream = new MemoryStream();
+
+ using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress, false))
+ {
+ // Console.WriteLine(WebUtil.CopyTo(new MemoryStream(asset.Data), compressionStream, int.MaxValue));
+ // We have to close the compression stream in order to make sure it writes everything out to the underlying memory output stream.
+ compressionStream.Close();
+ byte[] compressedData = outputStream.ToArray();
+ asset.Data = compressedData;
+ }
+ }
+
+ byte[] hash = hasher.ComputeHash(asset.Data);
+
+// m_log.DebugFormat(
+// "[XASSET DB]: Compressed data size for {0} {1}, hash {2} is {3}",
+// asset.ID, asset.Name, hash, compressedData.Length);
+
+ try
+ {
+ using (MySqlCommand cmd =
+ new MySqlCommand(
+ "replace INTO xassetsmeta(id, hash, name, description, asset_type, local, temporary, create_time, access_time, asset_flags, creator_id)" +
+ "VALUES(?id, ?hash, ?name, ?description, ?asset_type, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?creator_id)",
+ dbcon))
+ {
+ // create unix epoch time
+ int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
+ cmd.Parameters.AddWithValue("?id", asset.ID);
+ cmd.Parameters.AddWithValue("?hash", hash);
+ cmd.Parameters.AddWithValue("?name", assetName);
+ cmd.Parameters.AddWithValue("?description", assetDescription);
+ cmd.Parameters.AddWithValue("?asset_type", asset.Type);
+ cmd.Parameters.AddWithValue("?local", asset.Local);
+ cmd.Parameters.AddWithValue("?temporary", asset.Temporary);
+ cmd.Parameters.AddWithValue("?create_time", now);
+ cmd.Parameters.AddWithValue("?access_time", now);
+ cmd.Parameters.AddWithValue("?creator_id", asset.Metadata.CreatorID);
+ cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags);
+ cmd.ExecuteNonQuery();
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset metadata {0} with name \"{1}\". Error: {2}",
+ asset.FullID, asset.Name, e.Message);
+
+ transaction.Rollback();
+
+ return;
+ }
+
+ if (!ExistsData(dbcon, transaction, hash))
+ {
+ try
+ {
+ using (MySqlCommand cmd =
+ new MySqlCommand(
+ "INSERT INTO xassetsdata(hash, data) VALUES(?hash, ?data)",
+ dbcon))
+ {
+ cmd.Parameters.AddWithValue("?hash", hash);
+ cmd.Parameters.AddWithValue("?data", asset.Data);
+ cmd.ExecuteNonQuery();
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat("[XASSET DB]: MySQL failure creating asset data {0} with name \"{1}\". Error: {2}",
+ asset.FullID, asset.Name, e.Message);
+
+ transaction.Rollback();
+
+ return;
+ }
+ }
+
+ transaction.Commit();
+ }
+ }
+ }
+ }
+
+// private void UpdateAccessTime(AssetBase asset)
+// {
+// lock (m_dbLock)
+// {
+// using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
+// {
+// dbcon.Open();
+// MySqlCommand cmd =
+// new MySqlCommand("update assets set access_time=?access_time where id=?id",
+// dbcon);
+//
+// // need to ensure we dispose
+// try
+// {
+// using (cmd)
+// {
+// // create unix epoch time
+// int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
+// cmd.Parameters.AddWithValue("?id", asset.ID);
+// cmd.Parameters.AddWithValue("?access_time", now);
+// cmd.ExecuteNonQuery();
+// cmd.Dispose();
+// }
+// }
+// catch (Exception e)
+// {
+// m_log.ErrorFormat(
+// "[ASSETS DB]: " +
+// "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString()
+// + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
+// }
+// }
+// }
+//
+// }
+
+ ///
+ /// We assume we already have the m_dbLock.
+ ///
+ /// TODO: need to actually use the transaction.
+ ///
+ ///
+ ///
+ ///
+ private bool ExistsData(MySqlConnection dbcon, MySqlTransaction transaction, byte[] hash)
+ {
+// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid);
+
+ bool exists = false;
+
+ using (MySqlCommand cmd = new MySqlCommand("SELECT hash FROM xassetsdata WHERE hash=?hash", dbcon))
+ {
+ cmd.Parameters.AddWithValue("?hash", hash);
+
+ try
+ {
+ using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
+ {
+ if (dbReader.Read())
+ {
+// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid);
+ exists = true;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[XASSETS DB]: MySql failure in ExistsData fetching hash {0}. Exception {1}{2}",
+ hash, e.Message, e.StackTrace);
+ }
+ }
+
+ return exists;
+ }
+
+ ///
+ /// Check if the asset exists in the database
+ ///
+ /// The asset UUID
+ /// true if it exists, false otherwise.
+ override public bool ExistsAsset(UUID uuid)
+ {
+// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid);
+
+ bool assetExists = false;
+
+ lock (m_dbLock)
+ {
+ using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
+ {
+ dbcon.Open();
+ using (MySqlCommand cmd = new MySqlCommand("SELECT id FROM xassetsmeta WHERE id=?id", dbcon))
+ {
+ cmd.Parameters.AddWithValue("?id", uuid.ToString());
+
+ try
+ {
+ using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
+ {
+ if (dbReader.Read())
+ {
+// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid);
+ assetExists = true;
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.ErrorFormat(
+ "[XASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid);
+ }
+ }
+ }
+ }
+
+ return assetExists;
+ }
+
+ ///
+ /// Returns a list of AssetMetadata objects. The list is a subset of
+ /// the entire data set offset by containing
+ /// elements.
+ ///
+ /// The number of results to discard from the total data set.
+ /// The number of rows the returned list should contain.
+ /// A list of AssetMetadata objects.
+ public override List FetchAssetMetadataSet(int start, int count)
+ {
+ List retList = new List(count);
+
+ lock (m_dbLock)
+ {
+ using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
+ {
+ dbcon.Open();
+ MySqlCommand cmd = new MySqlCommand("SELECT name,description,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon);
+ cmd.Parameters.AddWithValue("?start", start);
+ cmd.Parameters.AddWithValue("?count", count);
+
+ try
+ {
+ using (MySqlDataReader dbReader = cmd.ExecuteReader())
+ {
+ while (dbReader.Read())
+ {
+ AssetMetadata metadata = new AssetMetadata();
+ metadata.Name = (string)dbReader["name"];
+ metadata.Description = (string)dbReader["description"];
+ metadata.Type = (sbyte)dbReader["asset_type"];
+ metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct.
+ metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
+ metadata.FullID = DBGuid.FromDB(dbReader["id"]);
+ metadata.CreatorID = dbReader["creator_id"].ToString();
+
+ // We'll ignore this for now - it appears unused!
+// metadata.SHA1 = dbReader["hash"]);
+
+ retList.Add(metadata);
+ }
+ }
+ }
+ catch (Exception e)
+ {
+ m_log.Error("[XASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString());
+ }
+ }
+ }
+
+ return retList;
+ }
+
+ public override bool Delete(string id)
+ {
+// m_log.DebugFormat("[XASSETS DB]: Deleting asset {0}", id);
+
+ lock (m_dbLock)
+ {
+ using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
+ {
+ dbcon.Open();
+
+ using (MySqlCommand cmd = new MySqlCommand("delete from xassetsmeta where id=?id", dbcon))
+ {
+ cmd.Parameters.AddWithValue("?id", id);
+ cmd.ExecuteNonQuery();
+ }
+
+ // TODO: How do we deal with data from deleted assets? Probably not easily reapable unless we
+ // keep a reference count (?)
+ }
+ }
+
+ return true;
+ }
+
+ #endregion
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Data/MySQL/Resources/XAssetStore.migrations b/OpenSim/Data/MySQL/Resources/XAssetStore.migrations
new file mode 100644
index 0000000000..d3cca5e884
--- /dev/null
+++ b/OpenSim/Data/MySQL/Resources/XAssetStore.migrations
@@ -0,0 +1,27 @@
+# -----------------
+:VERSION 1
+
+BEGIN;
+
+CREATE TABLE `xassetsmeta` (
+ `id` char(36) NOT NULL,
+ `hash` binary(32) NOT NULL,
+ `name` varchar(64) NOT NULL,
+ `description` varchar(64) NOT NULL,
+ `asset_type` tinyint(4) NOT NULL,
+ `local` tinyint(1) NOT NULL,
+ `temporary` tinyint(1) NOT NULL,
+ `create_time` int(11) NOT NULL,
+ `access_time` int(11) NOT NULL,
+ `asset_flags` int(11) NOT NULL,
+ `creator_id` varchar(128) NOT NULL,
+ PRIMARY KEY (`id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
+
+CREATE TABLE `xassetsdata` (
+ `hash` binary(32) NOT NULL,
+ `data` longblob NOT NULL,
+ PRIMARY KEY (`hash`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
+
+COMMIT;
\ No newline at end of file
diff --git a/OpenSim/Data/SQLite/SQLiteSimulationData.cs b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
index 186a58622d..7e7c08a74f 100644
--- a/OpenSim/Data/SQLite/SQLiteSimulationData.cs
+++ b/OpenSim/Data/SQLite/SQLiteSimulationData.cs
@@ -2157,7 +2157,7 @@ namespace OpenSim.Data.SQLite
row["terrain_raise_limit"] = settings.TerrainRaiseLimit;
row["terrain_lower_limit"] = settings.TerrainLowerLimit;
row["use_estate_sun"] = settings.UseEstateSun;
- row["Sandbox"] = settings.Sandbox; // database uses upper case S for sandbox
+ row["sandbox"] = settings.Sandbox; // unlike other database modules, sqlite uses a lower case s for sandbox!
row["sunvectorx"] = settings.SunVector.X;
row["sunvectory"] = settings.SunVector.Y;
row["sunvectorz"] = settings.SunVector.Z;
diff --git a/OpenSim/Framework/Console/CommandConsole.cs b/OpenSim/Framework/Console/CommandConsole.cs
index 0d6288b5a3..2bb7de1cae 100644
--- a/OpenSim/Framework/Console/CommandConsole.cs
+++ b/OpenSim/Framework/Console/CommandConsole.cs
@@ -29,6 +29,7 @@ using System;
using System.Xml;
using System.Collections.Generic;
using System.Diagnostics;
+using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
@@ -40,6 +41,8 @@ namespace OpenSim.Framework.Console
{
public class Commands : ICommands
{
+// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
///
/// Encapsulates a command that can be invoked from the console
///
@@ -76,12 +79,19 @@ namespace OpenSim.Framework.Console
public List fn;
}
+ public const string GeneralHelpText = "For more information, type 'help - ' where
- is one of the following categories:";
+
///
/// Commands organized by keyword in a tree
///
private Dictionary tree =
new Dictionary();
+ ///
+ /// Commands organized by module
+ ///
+ private Dictionary> m_modulesCommands = new Dictionary>();
+
///
/// Get help for the given help string
///
@@ -98,8 +108,8 @@ namespace OpenSim.Framework.Console
// General help
if (helpParts.Count == 0)
{
- help.AddRange(CollectHelp(tree));
- help.Sort();
+ help.Add(GeneralHelpText);
+ help.AddRange(CollectModulesHelp(tree));
}
else
{
@@ -118,6 +128,13 @@ namespace OpenSim.Framework.Console
{
string originalHelpRequest = string.Join(" ", helpParts.ToArray());
List help = new List();
+
+ // Check modules first to see if we just need to display a list of those commands
+ if (TryCollectModuleHelp(originalHelpRequest, help))
+ {
+ help.Insert(0, GeneralHelpText);
+ return help;
+ }
Dictionary dict = tree;
while (helpParts.Count > 0)
@@ -161,25 +178,61 @@ namespace OpenSim.Framework.Console
return help;
}
- private List CollectHelp(Dictionary dict)
+ ///
+ /// Try to collect help for the given module if that module exists.
+ ///
+ ///
+ /// /param>
+ /// true if there was the module existed, false otherwise.
+ private bool TryCollectModuleHelp(string moduleName, List helpText)
{
- List result = new List();
-
- foreach (KeyValuePair kvp in dict)
+ lock (m_modulesCommands)
{
- if (kvp.Value is Dictionary)
+ if (m_modulesCommands.ContainsKey(moduleName))
{
- result.AddRange(CollectHelp((Dictionary)kvp.Value));
+ List commands = m_modulesCommands[moduleName];
+ var ourHelpText = commands.ConvertAll(c => string.Format("{0} - {1}", c.help_text, c.long_help));
+ ourHelpText.Sort();
+ helpText.AddRange(ourHelpText);
+
+ return true;
}
else
{
- if (((CommandInfo)kvp.Value).long_help != String.Empty)
- result.Add(((CommandInfo)kvp.Value).help_text+" - "+
- ((CommandInfo)kvp.Value).long_help);
+ return false;
}
}
- return result;
}
+
+ private List CollectModulesHelp(Dictionary dict)
+ {
+ lock (m_modulesCommands)
+ {
+ List helpText = new List(m_modulesCommands.Keys);
+ helpText.Sort();
+ return helpText;
+ }
+ }
+
+// private List CollectHelp(Dictionary dict)
+// {
+// List result = new List();
+//
+// foreach (KeyValuePair kvp in dict)
+// {
+// if (kvp.Value is Dictionary)
+// {
+// result.AddRange(CollectHelp((Dictionary)kvp.Value));
+// }
+// else
+// {
+// if (((CommandInfo)kvp.Value).long_help != String.Empty)
+// result.Add(((CommandInfo)kvp.Value).help_text+" - "+
+// ((CommandInfo)kvp.Value).long_help);
+// }
+// }
+// return result;
+// }
///
/// Add a command to those which can be invoked from the console.
@@ -212,21 +265,19 @@ namespace OpenSim.Framework.Console
Dictionary current = tree;
- foreach (string s in parts)
+ foreach (string part in parts)
{
- if (current.ContainsKey(s))
+ if (current.ContainsKey(part))
{
- if (current[s] is Dictionary)
- {
- current = (Dictionary)current[s];
- }
+ if (current[part] is Dictionary)
+ current = (Dictionary)current[part];
else
return;
}
else
{
- current[s] = new Dictionary();
- current = (Dictionary)current[s];
+ current[part] = new Dictionary();
+ current = (Dictionary)current[part];
}
}
@@ -250,6 +301,24 @@ namespace OpenSim.Framework.Console
info.fn = new List();
info.fn.Add(fn);
current[String.Empty] = info;
+
+ // Now add command to modules dictionary
+ lock (m_modulesCommands)
+ {
+ List commands;
+ if (m_modulesCommands.ContainsKey(module))
+ {
+ commands = m_modulesCommands[module];
+ }
+ else
+ {
+ commands = new List();
+ m_modulesCommands[module] = commands;
+ }
+
+// m_log.DebugFormat("[COMMAND CONSOLE]: Adding to category {0} command {1}", module, command);
+ commands.Add(info);
+ }
}
public string[] FindNextOption(string[] cmd, bool term)
@@ -607,8 +676,9 @@ namespace OpenSim.Framework.Console
{
Commands = new Commands();
- Commands.AddCommand("console", false, "help", "help []",
- "Get general command list or more detailed help on a specific command", Help);
+ Commands.AddCommand(
+ "Help", false, "help", "help [
- ]",
+ "Display help on a particular command or on a list of commands in a category", Help);
}
private void Help(string module, string[] cmd)
diff --git a/OpenSim/Framework/Console/MockConsole.cs b/OpenSim/Framework/Console/MockConsole.cs
index a29b370857..4d8751f5f6 100644
--- a/OpenSim/Framework/Console/MockConsole.cs
+++ b/OpenSim/Framework/Console/MockConsole.cs
@@ -29,6 +29,7 @@ using System;
using System.Threading;
using System.Collections.Generic;
using System.Text;
+using System.Xml;
namespace OpenSim.Framework.Console
{
@@ -37,28 +38,42 @@ namespace OpenSim.Framework.Console
/// Don't use this except for Unit Testing or you're in for a world of hurt when the
/// sim gets to ReadLine
///
- public class MockConsole : CommandConsole
+ public class MockConsole : ICommandConsole
{
- public MockConsole(string defaultPrompt) : base(defaultPrompt)
- {
- }
- public override void Output(string text)
- {
- }
- public override void Output(string text, string level)
- {
- }
+ private MockCommands m_commands = new MockCommands();
- public override string ReadLine(string p, bool isCommand, bool e)
- {
- //Thread.CurrentThread.Join(1000);
- return string.Empty;
- }
- public override void UnlockOutput()
- {
- }
- public override void LockOutput()
- {
- }
+ public ICommands Commands { get { return m_commands; } }
+
+ public void Prompt() {}
+
+ public void RunCommand(string cmd) {}
+
+ public string ReadLine(string p, bool isCommand, bool e) { return ""; }
+
+ public object ConsoleScene { get { return null; } }
+
+ public void Output(string text, string level) {}
+ public void Output(string text) {}
+ public void OutputFormat(string format, params object[] components) {}
+
+ public string CmdPrompt(string p) { return ""; }
+ public string CmdPrompt(string p, string def) { return ""; }
+ public string CmdPrompt(string p, List excludedCharacters) { return ""; }
+ public string CmdPrompt(string p, string def, List excludedCharacters) { return ""; }
+
+ public string CmdPrompt(string prompt, string defaultresponse, List options) { return ""; }
+
+ public string PasswdPrompt(string p) { return ""; }
}
-}
+
+ public class MockCommands : ICommands
+ {
+ public void FromXml(XmlElement root, CommandDelegate fn) {}
+ public List GetHelp(string[] cmd) { return null; }
+ public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) {}
+ public void AddCommand(string module, bool shared, string command, string help, string longhelp, string descriptivehelp, CommandDelegate fn) {}
+ public string[] FindNextOption(string[] cmd, bool term) { return null; }
+ public string[] Resolve(string[] cmd) { return null; }
+ public XmlElement GetXml(XmlDocument doc) { return null; }
+ }
+}
\ No newline at end of file
diff --git a/OpenSim/Framework/ICommandConsole.cs b/OpenSim/Framework/ICommandConsole.cs
index d33b9b5772..ca0ff936ca 100644
--- a/OpenSim/Framework/ICommandConsole.cs
+++ b/OpenSim/Framework/ICommandConsole.cs
@@ -40,7 +40,7 @@ namespace OpenSim.Framework
///
/// Get help for the given help string
///
- /// Parsed parts of the help string. If empty then general help is returned.
+ /// Parsed parts of the help string. If empty then general help is returned.
///
List GetHelp(string[] cmd);
diff --git a/OpenSim/Framework/Servers/BaseOpenSimServer.cs b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
index 586cde6482..f4d541e922 100644
--- a/OpenSim/Framework/Servers/BaseOpenSimServer.cs
+++ b/OpenSim/Framework/Servers/BaseOpenSimServer.cs
@@ -161,43 +161,43 @@ namespace OpenSim.Framework.Servers
Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold));
}
- m_console.Commands.AddCommand("base", false, "quit",
+ m_console.Commands.AddCommand("General", false, "quit",
"quit",
"Quit the application", HandleQuit);
- m_console.Commands.AddCommand("base", false, "shutdown",
+ m_console.Commands.AddCommand("General", false, "shutdown",
"shutdown",
"Quit the application", HandleQuit);
- m_console.Commands.AddCommand("base", false, "set log level",
+ m_console.Commands.AddCommand("General", false, "set log level",
"set log level ",
"Set the console logging level", HandleLogLevel);
- m_console.Commands.AddCommand("base", false, "show info",
+ m_console.Commands.AddCommand("General", false, "show info",
"show info",
"Show general information about the server", HandleShow);
- m_console.Commands.AddCommand("base", false, "show stats",
+ m_console.Commands.AddCommand("General", false, "show stats",
"show stats",
"Show statistics", HandleShow);
- m_console.Commands.AddCommand("base", false, "show threads",
+ m_console.Commands.AddCommand("General", false, "show threads",
"show threads",
"Show thread status", HandleShow);
- m_console.Commands.AddCommand("base", false, "show uptime",
+ m_console.Commands.AddCommand("General", false, "show uptime",
"show uptime",
"Show server uptime", HandleShow);
- m_console.Commands.AddCommand("base", false, "show version",
+ m_console.Commands.AddCommand("General", false, "show version",
"show version",
"Show server version", HandleShow);
- m_console.Commands.AddCommand("base", false, "threads abort",
+ m_console.Commands.AddCommand("General", false, "threads abort",
"threads abort ",
"Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
- m_console.Commands.AddCommand("base", false, "threads show",
+ m_console.Commands.AddCommand("General", false, "threads show",
"threads show",
"Show thread status. Synonym for \"show threads\"",
(string module, string[] args) => Notice(GetThreadsReport()));
@@ -247,7 +247,7 @@ namespace OpenSim.Framework.Servers
string reportFormat = "{0,6} {1,35} {2,16} {3,13} {4,10} {5,30}";
StringBuilder sb = new StringBuilder();
- Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreads();
+ Watchdog.ThreadWatchdogInfo[] threads = Watchdog.GetThreadsInfo();
sb.Append(threads.Length + " threads are being tracked:" + Environment.NewLine);
diff --git a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
index 2206febdb1..0062d4ef15 100644
--- a/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
+++ b/OpenSim/Framework/Servers/HttpServer/PollServiceRequestManager.cs
@@ -65,6 +65,7 @@ namespace OpenSim.Framework.Servers.HttpServer
String.Format("PollServiceWorkerThread{0}", i),
ThreadPriority.Normal,
false,
+ true,
int.MaxValue);
}
@@ -73,6 +74,7 @@ namespace OpenSim.Framework.Servers.HttpServer
"PollServiceWatcherThread",
ThreadPriority.Normal,
false,
+ true,
1000 * 60 * 10);
}
diff --git a/OpenSim/Framework/Servers/VersionInfo.cs b/OpenSim/Framework/Servers/VersionInfo.cs
index b2bb96268f..63ec257c40 100644
--- a/OpenSim/Framework/Servers/VersionInfo.cs
+++ b/OpenSim/Framework/Servers/VersionInfo.cs
@@ -29,7 +29,7 @@ namespace OpenSim
{
public class VersionInfo
{
- private const string VERSION_NUMBER = "0.7.3CM";
+ private const string VERSION_NUMBER = "0.7.4CM";
private const Flavour VERSION_FLAVOUR = Flavour.Dev;
public enum Flavour
diff --git a/OpenSim/Framework/Watchdog.cs b/OpenSim/Framework/Watchdog.cs
index fa94109af1..881b6aadaa 100644
--- a/OpenSim/Framework/Watchdog.cs
+++ b/OpenSim/Framework/Watchdog.cs
@@ -72,6 +72,11 @@ namespace OpenSim.Framework
///
public bool IsTimedOut { get; set; }
+ ///
+ /// Will this thread trigger the alarm function if it has timed out?
+ ///
+ public bool AlarmIfTimeout { get; set; }
+
public ThreadWatchdogInfo(Thread thread, int timeout)
{
Thread = thread;
@@ -112,12 +117,13 @@ namespace OpenSim.Framework
/// The method that will be executed in a new thread
/// A name to give to the new thread
/// Priority to run the thread at
- /// True to run this thread as a background
- /// thread, otherwise false
+ /// True to run this thread as a background thread, otherwise false
+ /// Trigger an alarm function is we have timed out
/// The newly created Thread object
- public static Thread StartThread(ThreadStart start, string name, ThreadPriority priority, bool isBackground)
+ public static Thread StartThread(
+ ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout)
{
- return StartThread(start, name, priority, isBackground, WATCHDOG_TIMEOUT_MS);
+ return StartThread(start, name, priority, isBackground, alarmIfTimeout, WATCHDOG_TIMEOUT_MS);
}
///
@@ -128,21 +134,21 @@ namespace OpenSim.Framework
/// Priority to run the thread at
/// True to run this thread as a background
/// thread, otherwise false
- ///
- /// Number of milliseconds to wait until we issue a warning about timeout.
- ///
+ /// Trigger an alarm function is we have timed out
+ /// Number of milliseconds to wait until we issue a warning about timeout.
/// The newly created Thread object
public static Thread StartThread(
- ThreadStart start, string name, ThreadPriority priority, bool isBackground, int timeout)
+ ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout, int timeout)
{
Thread thread = new Thread(start);
thread.Name = name;
thread.Priority = priority;
thread.IsBackground = isBackground;
- ThreadWatchdogInfo twi = new ThreadWatchdogInfo(thread, timeout);
+ ThreadWatchdogInfo twi = new ThreadWatchdogInfo(thread, timeout) { AlarmIfTimeout = alarmIfTimeout };
- m_log.Debug("[WATCHDOG]: Started tracking thread \"" + twi.Thread.Name + "\" (ID " + twi.Thread.ManagedThreadId + ")");
+ m_log.DebugFormat(
+ "[WATCHDOG]: Started tracking thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
lock (m_threads)
m_threads.Add(twi.Thread.ManagedThreadId, twi);
@@ -224,19 +230,39 @@ namespace OpenSim.Framework
/// Get currently watched threads for diagnostic purposes
///
///
- public static ThreadWatchdogInfo[] GetThreads()
+ public static ThreadWatchdogInfo[] GetThreadsInfo()
{
lock (m_threads)
return m_threads.Values.ToArray();
}
+ ///
+ /// Return the current thread's watchdog info.
+ ///
+ /// The watchdog info. null if the thread isn't being monitored.
+ public static ThreadWatchdogInfo GetCurrentThreadInfo()
+ {
+ lock (m_threads)
+ {
+ if (m_threads.ContainsKey(Thread.CurrentThread.ManagedThreadId))
+ return m_threads[Thread.CurrentThread.ManagedThreadId];
+ }
+
+ return null;
+ }
+
+ ///
+ /// Check watched threads. Fire alarm if appropriate.
+ ///
+ ///
+ ///
private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
WatchdogTimeout callback = OnWatchdogTimeout;
if (callback != null)
{
- ThreadWatchdogInfo timedOut = null;
+ List callbackInfos = null;
lock (m_threads)
{
@@ -246,21 +272,31 @@ namespace OpenSim.Framework
{
if (threadInfo.Thread.ThreadState == ThreadState.Stopped)
{
- timedOut = threadInfo;
RemoveThread(threadInfo.Thread.ManagedThreadId);
- break;
+
+ if (callbackInfos == null)
+ callbackInfos = new List();
+
+ callbackInfos.Add(threadInfo);
}
else if (!threadInfo.IsTimedOut && now - threadInfo.LastTick >= threadInfo.Timeout)
{
threadInfo.IsTimedOut = true;
- timedOut = threadInfo;
- break;
+
+ if (threadInfo.AlarmIfTimeout)
+ {
+ if (callbackInfos == null)
+ callbackInfos = new List();
+
+ callbackInfos.Add(threadInfo);
+ }
}
}
}
- if (timedOut != null)
- callback(timedOut.Thread, timedOut.LastTick);
+ if (callbackInfos != null)
+ foreach (ThreadWatchdogInfo callbackInfo in callbackInfos)
+ callback(callbackInfo.Thread, callbackInfo.LastTick);
}
m_watchdogTimer.Start();
diff --git a/OpenSim/Framework/WebUtil.cs b/OpenSim/Framework/WebUtil.cs
index 854f3106c3..f90df124ca 100644
--- a/OpenSim/Framework/WebUtil.cs
+++ b/OpenSim/Framework/WebUtil.cs
@@ -63,77 +63,7 @@ namespace OpenSim.Framework
// a "long" call for warning & debugging purposes
public const int LongCallTime = 500;
-// ///
-// /// Send LLSD to an HTTP client in application/llsd+json form
-// ///
-// /// HTTP response to send the data in
-// /// LLSD to send to the client
-// public static void SendJSONResponse(OSHttpResponse response, OSDMap body)
-// {
-// byte[] responseData = Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(body));
-//
-// response.ContentEncoding = Encoding.UTF8;
-// response.ContentLength = responseData.Length;
-// response.ContentType = "application/llsd+json";
-// response.Body.Write(responseData, 0, responseData.Length);
-// }
-//
-// ///
-// /// Send LLSD to an HTTP client in application/llsd+xml form
-// ///
-// /// HTTP response to send the data in
-// /// LLSD to send to the client
-// public static void SendXMLResponse(OSHttpResponse response, OSDMap body)
-// {
-// byte[] responseData = OSDParser.SerializeLLSDXmlBytes(body);
-//
-// response.ContentEncoding = Encoding.UTF8;
-// response.ContentLength = responseData.Length;
-// response.ContentType = "application/llsd+xml";
-// response.Body.Write(responseData, 0, responseData.Length);
-// }
-
- ///
- /// Make a GET or GET-like request to a web service that returns LLSD
- /// or JSON data
- ///
- public static OSDMap ServiceRequest(string url, string httpVerb)
- {
- string errorMessage;
-
- try
- {
- HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
- request.Method = httpVerb;
-
- using (WebResponse response = request.GetResponse())
- {
- using (Stream responseStream = response.GetResponseStream())
- {
- try
- {
- string responseStr = responseStream.GetStreamString();
- OSD responseOSD = OSDParser.Deserialize(responseStr);
- if (responseOSD.Type == OSDType.Map)
- return (OSDMap)responseOSD;
- else
- errorMessage = "Response format was invalid.";
- }
- catch
- {
- errorMessage = "Failed to parse the response.";
- }
- }
- }
- }
- catch (Exception ex)
- {
- m_log.Warn(httpVerb + " on URL " + url + " failed: " + ex.Message);
- errorMessage = ex.Message;
- }
-
- return new OSDMap { { "Message", OSD.FromString("Service request failed. " + errorMessage) } };
- }
+ #region JSONRequest
///
/// PUT JSON-encoded data to a web service that returns LLSD or
@@ -304,6 +234,10 @@ namespace OpenSim.Framework
return result;
}
+ #endregion JSONRequest
+
+ #region FormRequest
+
///
/// POST URL-encoded form data to a web service that returns LLSD or
/// JSON data
@@ -398,6 +332,8 @@ namespace OpenSim.Framework
result["Message"] = OSD.FromString("Service request failed: " + msg);
return result;
}
+
+ #endregion FormRequest
#region Uri
diff --git a/OpenSim/Region/Application/OpenSim.cs b/OpenSim/Region/Application/OpenSim.cs
index 7a40751062..aad73a3283 100644
--- a/OpenSim/Region/Application/OpenSim.cs
+++ b/OpenSim/Region/Application/OpenSim.cs
@@ -225,12 +225,12 @@ namespace OpenSim
///
private void RegisterConsoleCommands()
{
- m_console.Commands.AddCommand("region", false, "force update",
+ m_console.Commands.AddCommand("Regions", false, "force update",
"force update",
"Force the update of all objects on clients",
HandleForceUpdate);
- m_console.Commands.AddCommand("region", false, "debug packet",
+ m_console.Commands.AddCommand("Comms", false, "debug packet",
"debug packet [ ]",
"Turn on packet debugging",
"If level > 255 then all incoming and outgoing packets are logged.\n"
@@ -242,7 +242,7 @@ namespace OpenSim
+ "If an avatar name is given then only packets from that avatar are logged",
Debug);
- m_console.Commands.AddCommand("region", false, "debug http",
+ m_console.Commands.AddCommand("Comms", false, "debug http",
"debug http ",
"Turn on inbound http request debugging for everything except the event queue (see debug eq).",
"If level >= 2 then the handler used to service the request is logged.\n"
@@ -250,37 +250,37 @@ namespace OpenSim
+ "If level <= 0 then no extra http logging is done.\n",
Debug);
- m_console.Commands.AddCommand("region", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
+ m_console.Commands.AddCommand("Comms", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
- m_console.Commands.AddCommand("region", false, "debug scene",
+ m_console.Commands.AddCommand("Regions", false, "debug scene",
"debug scene ",
"Turn on scene debugging", Debug);
- m_console.Commands.AddCommand("region", false, "change region",
+ m_console.Commands.AddCommand("General", false, "change region",
"change region ",
"Change current console region", ChangeSelectedRegion);
- m_console.Commands.AddCommand("region", false, "save xml",
+ m_console.Commands.AddCommand("Archiving", false, "save xml",
"save xml",
"Save a region's data in XML format", SaveXml);
- m_console.Commands.AddCommand("region", false, "save xml2",
+ m_console.Commands.AddCommand("Archiving", false, "save xml2",
"save xml2",
"Save a region's data in XML2 format", SaveXml2);
- m_console.Commands.AddCommand("region", false, "load xml",
+ m_console.Commands.AddCommand("Archiving", false, "load xml",
"load xml [-newIDs [ ]]",
"Load a region's data from XML format", LoadXml);
- m_console.Commands.AddCommand("region", false, "load xml2",
+ m_console.Commands.AddCommand("Archiving", false, "load xml2",
"load xml2",
"Load a region's data from XML2 format", LoadXml2);
- m_console.Commands.AddCommand("region", false, "save prims xml2",
+ m_console.Commands.AddCommand("Archiving", false, "save prims xml2",
"save prims xml2 [ ]",
"Save named prim to XML2", SavePrimsXml2);
- m_console.Commands.AddCommand("region", false, "load oar",
+ m_console.Commands.AddCommand("Archiving", false, "load oar",
"load oar [--merge] [--skip-assets] []",
"Load a region's data from an OAR archive.",
"--merge will merge the OAR with the existing scene." + Environment.NewLine
@@ -289,7 +289,7 @@ namespace OpenSim
+ " If this is not given then the command looks for an OAR named region.oar in the current directory.",
LoadOar);
- m_console.Commands.AddCommand("region", false, "save oar",
+ m_console.Commands.AddCommand("Archiving", false, "save oar",
//"save oar [-v|--version=] [-p|--profile=] []",
"save oar [-h|--home=] [--noassets] [--publish] [--perm=] []",
"Save a region's data to an OAR archive.",
@@ -306,54 +306,54 @@ namespace OpenSim
+ " If this is not given then the oar is saved to region.oar in the current directory.",
SaveOar);
- m_console.Commands.AddCommand("region", false, "edit scale",
+ m_console.Commands.AddCommand("Regions", false, "edit scale",
"edit scale ",
"Change the scale of a named prim", HandleEditScale);
- m_console.Commands.AddCommand("region", false, "kick user",
+ m_console.Commands.AddCommand("Users", false, "kick user",
"kick user [message]",
"Kick a user off the simulator", KickUserCommand);
- m_console.Commands.AddCommand("region", false, "show users",
+ m_console.Commands.AddCommand("Users", false, "show users",
"show users [full]",
"Show user data for users currently on the region",
"Without the 'full' option, only users actually on the region are shown."
+ " With the 'full' option child agents of users in neighbouring regions are also shown.",
HandleShow);
- m_console.Commands.AddCommand("region", false, "show connections",
+ m_console.Commands.AddCommand("Comms", false, "show connections",
"show connections",
"Show connection data", HandleShow);
- m_console.Commands.AddCommand("region", false, "show circuits",
+ m_console.Commands.AddCommand("Comms", false, "show circuits",
"show circuits",
"Show agent circuit data", HandleShow);
- m_console.Commands.AddCommand("region", false, "show http-handlers",
+ m_console.Commands.AddCommand("Comms", false, "show http-handlers",
"show http-handlers",
"Show all registered http handlers", HandleShow);
- m_console.Commands.AddCommand("region", false, "show pending-objects",
+ m_console.Commands.AddCommand("Comms", false, "show pending-objects",
"show pending-objects",
"Show # of objects on the pending queues of all scene viewers", HandleShow);
- m_console.Commands.AddCommand("region", false, "show modules",
+ m_console.Commands.AddCommand("General", false, "show modules",
"show modules",
"Show module data", HandleShow);
- m_console.Commands.AddCommand("region", false, "show regions",
+ m_console.Commands.AddCommand("Regions", false, "show regions",
"show regions",
"Show region data", HandleShow);
- m_console.Commands.AddCommand("region", false, "show ratings",
+ m_console.Commands.AddCommand("Regions", false, "show ratings",
"show ratings",
"Show rating data", HandleShow);
- m_console.Commands.AddCommand("region", false, "backup",
+ m_console.Commands.AddCommand("Regions", false, "backup",
"backup",
"Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", RunCommand);
- m_console.Commands.AddCommand("region", false, "create region",
+ m_console.Commands.AddCommand("Regions", false, "create region",
"create region [\"region name\"] ",
"Create a new region.",
"The settings for \"region name\" are read from . Paths specified with are relative to your Regions directory, unless an absolute path is given."
@@ -362,62 +362,57 @@ namespace OpenSim
+ "If does not exist, it will be created.",
HandleCreateRegion);
- m_console.Commands.AddCommand("region", false, "restart",
+ m_console.Commands.AddCommand("Regions", false, "restart",
"restart",
"Restart all sims in this instance", RunCommand);
- m_console.Commands.AddCommand("region", false, "config set",
+ m_console.Commands.AddCommand("General", false, "config set",
"config set ",
"Set a config option. In most cases this is not useful since changed parameters are not dynamically reloaded. Neither do changed parameters persist - you will have to change a config file manually and restart.", HandleConfig);
- m_console.Commands.AddCommand("region", false, "config get",
+ m_console.Commands.AddCommand("General", false, "config get",
"config get [] []",
"Synonym for config show",
HandleConfig);
- m_console.Commands.AddCommand("region", false, "config show",
+ m_console.Commands.AddCommand("General", false, "config show",
"config show [] []",
"Show config information",
"If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine
+ "If a section is given but not a field, then all fields in that section are printed.",
HandleConfig);
- m_console.Commands.AddCommand("region", false, "config save",
+ m_console.Commands.AddCommand("General", false, "config save",
"config save ",
"Save current configuration to a file at the given path", HandleConfig);
- m_console.Commands.AddCommand("region", false, "command-script",
+ m_console.Commands.AddCommand("General", false, "command-script",
"command-script