From 134f86e8d5c414409631b25b8c6f0ee45fbd8631 Mon Sep 17 00:00:00 2001
From: David Walter Seikel
Date: Thu, 3 Nov 2016 21:44:39 +1000
Subject: Initial update to OpenSim 0.8.2.1 source code.
---
OpenSim/Data/MySQL/MySQLFSAssetData.cs | 414 +++++++++++++++++++++++++++++++++
1 file changed, 414 insertions(+)
create mode 100644 OpenSim/Data/MySQL/MySQLFSAssetData.cs
(limited to 'OpenSim/Data/MySQL/MySQLFSAssetData.cs')
diff --git a/OpenSim/Data/MySQL/MySQLFSAssetData.cs b/OpenSim/Data/MySQL/MySQLFSAssetData.cs
new file mode 100644
index 0000000..19e23b5
--- /dev/null
+++ b/OpenSim/Data/MySQL/MySQLFSAssetData.cs
@@ -0,0 +1,414 @@
+/*
+ * 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.Reflection;
+using System.Collections.Generic;
+using System.Data;
+using OpenSim.Framework;
+using OpenSim.Framework.Console;
+using log4net;
+using MySql.Data.MySqlClient;
+using OpenMetaverse;
+
+namespace OpenSim.Data.MySQL
+{
+ public class MySQLFSAssetData : IFSAssetDataPlugin
+ {
+ private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
+
+ protected MySqlConnection m_Connection = null;
+ protected string m_ConnectionString;
+ protected string m_Table;
+ protected Object m_connLock = new Object();
+
+ ///
+ /// Number of days that must pass before we update the access time on an asset when it has been fetched
+ /// Config option to change this is "DaysBetweenAccessTimeUpdates"
+ ///
+ private int DaysBetweenAccessTimeUpdates = 0;
+
+ protected virtual Assembly Assembly
+ {
+ get { return GetType().Assembly; }
+ }
+
+ public MySQLFSAssetData()
+ {
+ }
+
+ #region IPlugin Members
+
+ public string Version { get { return "1.0.0.0"; } }
+
+ // Loads and initialises the MySQL storage plugin and checks for migrations
+ public void Initialise(string connect, string realm, int UpdateAccessTime)
+ {
+ m_ConnectionString = connect;
+ m_Table = realm;
+
+ DaysBetweenAccessTimeUpdates = UpdateAccessTime;
+
+ try
+ {
+ OpenDatabase();
+
+ Migration m = new Migration(m_Connection, Assembly, "FSAssetStore");
+ m.Update();
+ }
+ catch (MySqlException e)
+ {
+ m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}", e.Message.ToString());
+ }
+ }
+
+ public void Initialise()
+ {
+ throw new NotImplementedException();
+ }
+
+ public void Dispose() { }
+
+ public string Name
+ {
+ get { return "MySQL FSAsset storage engine"; }
+ }
+
+ #endregion
+
+ private bool OpenDatabase()
+ {
+ try
+ {
+ m_Connection = new MySqlConnection(m_ConnectionString);
+
+ m_Connection.Open();
+ }
+ catch (MySqlException e)
+ {
+ m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}",
+ e.Message.ToString());
+
+ return false;
+ }
+
+ return true;
+ }
+
+ private IDataReader ExecuteReader(MySqlCommand c)
+ {
+ IDataReader r = null;
+ MySqlConnection connection = (MySqlConnection) ((ICloneable)m_Connection).Clone();
+ connection.Open();
+ c.Connection = connection;
+
+ r = c.ExecuteReader();
+
+ return r;
+ }
+
+ private void ExecuteNonQuery(MySqlCommand c)
+ {
+ lock (m_connLock)
+ {
+ bool errorSeen = false;
+
+ while (true)
+ {
+ try
+ {
+ c.ExecuteNonQuery();
+ }
+ catch (MySqlException)
+ {
+ System.Threading.Thread.Sleep(500);
+
+ m_Connection.Close();
+ m_Connection = (MySqlConnection) ((ICloneable)m_Connection).Clone();
+ m_Connection.Open();
+ c.Connection = m_Connection;
+
+ if (!errorSeen)
+ {
+ errorSeen = true;
+ continue;
+ }
+ m_log.ErrorFormat("[FSASSETS] MySQL command: {0}", c.CommandText);
+ throw;
+ }
+
+ break;
+ }
+ }
+ }
+
+ #region IFSAssetDataPlugin Members
+
+ public AssetMetadata Get(string id, out string hash)
+ {
+ hash = String.Empty;
+
+ MySqlCommand cmd = new MySqlCommand();
+
+ cmd.CommandText = String.Format("select id, name, description, type, hash, create_time, access_time, asset_flags from {0} where id = ?id", m_Table);
+ cmd.Parameters.AddWithValue("?id", id);
+
+ IDataReader reader = ExecuteReader(cmd);
+
+ if (!reader.Read())
+ {
+ reader.Close();
+ FreeCommand(cmd);
+ return null;
+ }
+
+ AssetMetadata meta = new AssetMetadata();
+
+ hash = reader["hash"].ToString();
+
+ meta.ID = id;
+ meta.FullID = new UUID(id);
+
+ meta.Name = reader["name"].ToString();
+ meta.Description = reader["description"].ToString();
+ meta.Type = (sbyte)Convert.ToInt32(reader["type"]);
+ meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type);
+ meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"]));
+ meta.Flags = (AssetFlags)Convert.ToInt32(reader["asset_flags"]);
+
+ int AccessTime = Convert.ToInt32(reader["access_time"]);
+
+ reader.Close();
+
+ UpdateAccessTime(AccessTime, cmd);
+
+ FreeCommand(cmd);
+
+ return meta;
+ }
+
+ private void UpdateAccessTime(int AccessTime, MySqlCommand cmd)
+ {
+ // Reduce DB work by only updating access time if asset hasn't recently been accessed
+ // 0 By Default, Config option is "DaysBetweenAccessTimeUpdates"
+ if (DaysBetweenAccessTimeUpdates > 0 && (DateTime.UtcNow - Utils.UnixTimeToDateTime(AccessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
+ return;
+
+ cmd.CommandText = String.Format("UPDATE {0} SET `access_time` = UNIX_TIMESTAMP() WHERE `id` = ?id", m_Table);
+
+ cmd.ExecuteNonQuery();
+ }
+
+ protected void FreeCommand(MySqlCommand cmd)
+ {
+ MySqlConnection c = cmd.Connection;
+ cmd.Dispose();
+ c.Close();
+ c.Dispose();
+ }
+
+ public bool Store(AssetMetadata meta, string hash)
+ {
+ try
+ {
+ string oldhash;
+ AssetMetadata existingAsset = Get(meta.ID, out oldhash);
+
+ MySqlCommand cmd = m_Connection.CreateCommand();
+
+ cmd.Parameters.AddWithValue("?id", meta.ID);
+ cmd.Parameters.AddWithValue("?name", meta.Name);
+ cmd.Parameters.AddWithValue("?description", meta.Description);
+ cmd.Parameters.AddWithValue("?type", meta.Type.ToString());
+ cmd.Parameters.AddWithValue("?hash", hash);
+ cmd.Parameters.AddWithValue("?asset_flags", meta.Flags);
+
+ if (existingAsset == null)
+ {
+ cmd.CommandText = String.Format("insert into {0} (id, name, description, type, hash, asset_flags, create_time, access_time) values ( ?id, ?name, ?description, ?type, ?hash, ?asset_flags, UNIX_TIMESTAMP(), UNIX_TIMESTAMP())", m_Table);
+
+ ExecuteNonQuery(cmd);
+
+ cmd.Dispose();
+
+ return true;
+ }
+
+ //cmd.CommandText = String.Format("update {0} set hash = ?hash, access_time = UNIX_TIMESTAMP() where id = ?id", m_Table);
+
+ //ExecuteNonQuery(cmd);
+
+ cmd.Dispose();
+ return false;
+ }
+ catch(Exception e)
+ {
+ m_log.Error("[FSAssets] Failed to store asset with ID " + meta.ID);
+ m_log.Error(e.ToString());
+ return false;
+ }
+ }
+
+ ///
+ /// Check if the assets exist in the database.
+ ///
+ /// The asset UUID's
+ /// For each asset: true if it exists, false otherwise
+ public bool[] AssetsExist(UUID[] uuids)
+ {
+ if (uuids.Length == 0)
+ return new bool[0];
+
+ HashSet exists = new HashSet();
+
+ string ids = "'" + string.Join("','", uuids) + "'";
+ string sql = string.Format("select id from {1} where id in ({0})", ids, m_Table);
+
+ using (MySqlCommand cmd = m_Connection.CreateCommand())
+ {
+ cmd.CommandText = sql;
+
+ using (MySqlDataReader dbReader = cmd.ExecuteReader())
+ {
+ while (dbReader.Read())
+ {
+ UUID id = DBGuid.FromDB(dbReader["ID"]);
+ exists.Add(id);
+ }
+ }
+ }
+
+ bool[] results = new bool[uuids.Length];
+ for (int i = 0; i < uuids.Length; i++)
+ results[i] = exists.Contains(uuids[i]);
+ return results;
+ }
+
+ public int Count()
+ {
+ MySqlCommand cmd = m_Connection.CreateCommand();
+
+ cmd.CommandText = String.Format("select count(*) as count from {0}", m_Table);
+
+ IDataReader reader = ExecuteReader(cmd);
+
+ reader.Read();
+
+ int count = Convert.ToInt32(reader["count"]);
+
+ reader.Close();
+ FreeCommand(cmd);
+
+ return count;
+ }
+
+ public bool Delete(string id)
+ {
+ using (MySqlCommand cmd = m_Connection.CreateCommand())
+ {
+ cmd.CommandText = String.Format("delete from {0} where id = ?id", m_Table);
+
+ cmd.Parameters.AddWithValue("?id", id);
+
+ ExecuteNonQuery(cmd);
+ }
+
+ return true;
+ }
+
+ public void Import(string conn, string table, int start, int count, bool force, FSStoreDelegate store)
+ {
+ MySqlConnection importConn;
+
+ try
+ {
+ importConn = new MySqlConnection(conn);
+
+ importConn.Open();
+ }
+ catch (MySqlException e)
+ {
+ m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}",
+ e.Message.ToString());
+
+ return;
+ }
+
+ int imported = 0;
+
+ MySqlCommand cmd = importConn.CreateCommand();
+
+ string limit = String.Empty;
+ if (count != -1)
+ {
+ limit = String.Format(" limit {0},{1}", start, count);
+ }
+
+ cmd.CommandText = String.Format("select * from {0}{1}", table, limit);
+
+ MainConsole.Instance.Output("Querying database");
+ IDataReader reader = cmd.ExecuteReader();
+
+ MainConsole.Instance.Output("Reading data");
+
+ while (reader.Read())
+ {
+ if ((imported % 100) == 0)
+ {
+ MainConsole.Instance.Output(String.Format("{0} assets imported so far", imported));
+ }
+
+ AssetBase asset = new AssetBase();
+ AssetMetadata meta = new AssetMetadata();
+
+ meta.ID = reader["id"].ToString();
+ meta.FullID = new UUID(meta.ID);
+
+ meta.Name = reader["name"].ToString();
+ meta.Description = reader["description"].ToString();
+ meta.Type = (sbyte)Convert.ToInt32(reader["assetType"]);
+ meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type);
+ meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"]));
+
+ asset.Metadata = meta;
+ asset.Data = (byte[])reader["data"];
+
+ store(asset, force);
+
+ imported++;
+ }
+
+ reader.Close();
+ cmd.Dispose();
+ importConn.Close();
+
+ MainConsole.Instance.Output(String.Format("Import done, {0} assets imported", imported));
+ }
+
+ #endregion
+ }
+}
--
cgit v1.1