123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414 |
- /*
- * 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();
- /// <summary>
- /// 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"
- /// </summary>
- 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;
- }
- }
- /// <summary>
- /// Check if the assets exist in the database.
- /// </summary>
- /// <param name="uuids">The asset UUID's</param>
- /// <returns>For each asset: true if it exists, false otherwise</returns>
- public bool[] AssetsExist(UUID[] uuids)
- {
- if (uuids.Length == 0)
- return new bool[0];
- HashSet<UUID> exists = new HashSet<UUID>();
- 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
- }
- }
|