diff --git a/OpenSim/Data/MySQL/MySQLGridData.cs b/OpenSim/Data/MySQL/MySQLGridData.cs index fcbceb8b82..9dc3d1867a 100644 --- a/OpenSim/Data/MySQL/MySQLGridData.cs +++ b/OpenSim/Data/MySQL/MySQLGridData.cs @@ -29,8 +29,6 @@ using System; using System.Collections.Generic; using System.Data; using System.Reflection; -using System.Security.Cryptography; -using System.Text; using libsecondlife; using log4net; using OpenSim.Framework; @@ -49,6 +47,45 @@ namespace OpenSim.Data.MySQL /// private MySQLManager database; + + /// + /// Better DB manager. Swap-in replacement too. + /// + public Dictionary m_dbconnections = new Dictionary(); + + public int m_maxConnections = 10; + public int m_lastConnect; + + public MySQLSuperManager GetLockedConnection() + { + int lockedCons = 0; + while (true) + { + m_lastConnect++; + + // Overflow protection + if (m_lastConnect == int.MaxValue) + m_lastConnect = 0; + + MySQLSuperManager x = m_dbconnections[m_lastConnect % m_maxConnections]; + if (!x.Locked) + { + x.GetLock(); + return x; + } + + lockedCons++; + if (lockedCons > m_maxConnections) + { + lockedCons = 0; + System.Threading.Thread.Sleep(1000); // Wait some time before searching them again. + m_log.Debug( + "WARNING: All threads are in use. Probable cause: Something didnt release a mutex properly, or high volume of requests inbound."); + } + } + } + + override public void Initialise() { m_log.Info("[MySQLGridData]: " + Name + " cannot be default-initialized!"); @@ -71,6 +108,16 @@ namespace OpenSim.Data.MySQL if (connect != String.Empty) { database = new MySQLManager(connect); + + m_log.Info("Creating " + m_maxConnections + " DB connections..."); + for (int i = 0; i < m_maxConnections; i++) + { + m_log.Info("Connecting to DB... [" + i + "]"); + MySQLSuperManager msm = new MySQLSuperManager(); + msm.Manager = new MySQLManager(connect); + m_dbconnections.Add(i, msm); + } + } else { @@ -85,6 +132,16 @@ namespace OpenSim.Data.MySQL database = new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword, settingPooling, settingPort); + + m_log.Info("Creating " + m_maxConnections + " DB connections..."); + for (int i = 0; i < m_maxConnections; i++) + { + m_log.Info("Connecting to DB... [" + i + "]"); + MySQLSuperManager msm = new MySQLSuperManager(); + msm.Manager = new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword, + settingPooling, settingPort); + m_dbconnections.Add(i, msm); + } } // This actually does the roll forward assembly stuff @@ -184,10 +241,10 @@ namespace OpenSim.Data.MySQL /// Array of sim profiles override public RegionProfileData[] GetProfilesInRange(uint xmin, uint ymin, uint xmax, uint ymax) { + MySQLSuperManager dbm = GetLockedConnection(); + try { - lock (database) - { Dictionary param = new Dictionary(); param["?xmin"] = xmin.ToString(); param["?ymin"] = ymin.ToString(); @@ -195,7 +252,7 @@ namespace OpenSim.Data.MySQL param["?ymax"] = ymax.ToString(); IDbCommand result = - database.Query( + dbm.Manager.Query( "SELECT * FROM regions WHERE locX >= ?xmin AND locX <= ?xmax AND locY >= ?ymin AND locY <= ?ymax", param); IDataReader reader = result.ExecuteReader(); @@ -204,7 +261,7 @@ namespace OpenSim.Data.MySQL List rows = new List(); - while ((row = database.readSimRow(reader)) != null) + while ((row = dbm.Manager.readSimRow(reader)) != null) { rows.Add(row); } @@ -212,14 +269,17 @@ namespace OpenSim.Data.MySQL result.Dispose(); return rows.ToArray(); - } } catch (Exception e) { - database.Reconnect(); + dbm.Manager.Reconnect(); m_log.Error(e.ToString()); return null; } + finally + { + dbm.Release(); + } } /// @@ -229,29 +289,32 @@ namespace OpenSim.Data.MySQL /// Sim profile override public RegionProfileData GetProfileByHandle(ulong handle) { + MySQLSuperManager dbm = GetLockedConnection(); + try { - lock (database) - { Dictionary param = new Dictionary(); param["?handle"] = handle.ToString(); - IDbCommand result = database.Query("SELECT * FROM regions WHERE regionHandle = ?handle", param); + IDbCommand result = dbm.Manager.Query("SELECT * FROM regions WHERE regionHandle = ?handle", param); IDataReader reader = result.ExecuteReader(); - RegionProfileData row = database.readSimRow(reader); + RegionProfileData row = dbm.Manager.readSimRow(reader); reader.Close(); result.Dispose(); return row; } - } catch (Exception e) { - database.Reconnect(); + dbm.Manager.Reconnect(); m_log.Error(e.ToString()); return null; } + finally + { + dbm.Release(); + } } /// @@ -261,70 +324,76 @@ namespace OpenSim.Data.MySQL /// The sim profile override public RegionProfileData GetProfileByLLUUID(LLUUID uuid) { + MySQLSuperManager dbm = GetLockedConnection(); + try { - lock (database) - { Dictionary param = new Dictionary(); param["?uuid"] = uuid.ToString(); - IDbCommand result = database.Query("SELECT * FROM regions WHERE uuid = ?uuid", param); + IDbCommand result = dbm.Manager.Query("SELECT * FROM regions WHERE uuid = ?uuid", param); IDataReader reader = result.ExecuteReader(); - RegionProfileData row = database.readSimRow(reader); + RegionProfileData row = dbm.Manager.readSimRow(reader); reader.Close(); result.Dispose(); return row; } - } catch (Exception e) { - database.Reconnect(); + dbm.Manager.Reconnect(); m_log.Error(e.ToString()); return null; + } finally + { + dbm.Release(); } } /// /// Returns a sim profile from it's Region name string /// - /// The region name search query /// The sim profile override public RegionProfileData GetProfileByString(string regionName) { + MySQLSuperManager dbm = GetLockedConnection(); + if (regionName.Length > 2) { try { - lock (database) - { - Dictionary param = new Dictionary(); - // Add % because this is a like query. - param["?regionName"] = regionName + "%"; - // Order by statement will return shorter matches first. Only returns one record or no record. - IDbCommand result = database.Query("SELECT * FROM regions WHERE regionName like ?regionName order by LENGTH(regionName) asc LIMIT 1", param); - IDataReader reader = result.ExecuteReader(); + Dictionary param = new Dictionary(); + // Add % because this is a like query. + param["?regionName"] = regionName + "%"; + // Order by statement will return shorter matches first. Only returns one record or no record. + IDbCommand result = + dbm.Manager.Query( + "SELECT * FROM regions WHERE regionName like ?regionName order by LENGTH(regionName) asc LIMIT 1", + param); + IDataReader reader = result.ExecuteReader(); - RegionProfileData row = database.readSimRow(reader); - reader.Close(); - result.Dispose(); + RegionProfileData row = dbm.Manager.readSimRow(reader); + reader.Close(); + result.Dispose(); - return row; - } + return row; } catch (Exception e) { - database.Reconnect(); + dbm.Manager.Reconnect(); m_log.Error(e.ToString()); return null; } + finally + { + dbm.Release(); + + } } - else - { - m_log.Error("[GRID DB]: Searched for a Region Name shorter then 3 characters"); - return null; - } + dbm.Release(); + m_log.Error("[GRID DB]: Searched for a Region Name shorter then 3 characters"); + return null; } /// @@ -334,16 +403,17 @@ namespace OpenSim.Data.MySQL /// Successful? override public DataResponse AddProfile(RegionProfileData profile) { - lock (database) - { - if (database.insertRegion(profile)) + MySQLSuperManager dbm = GetLockedConnection(); + try { + if (dbm.Manager.insertRegion(profile)) { return DataResponse.RESPONSE_OK; } - else - { - return DataResponse.RESPONSE_ERROR; - } + return DataResponse.RESPONSE_ERROR; + } + finally + { + dbm.Release(); } } @@ -366,16 +436,18 @@ namespace OpenSim.Data.MySQL //public DataResponse DeleteProfile(RegionProfileData profile) public DataResponse DeleteProfile(string uuid) { - lock (database) - { - if (database.deleteRegion(uuid)) + MySQLSuperManager dbm = GetLockedConnection(); + + + try { + if (dbm.Manager.deleteRegion(uuid)) { return DataResponse.RESPONSE_OK; } - else - { - return DataResponse.RESPONSE_ERROR; - } + return DataResponse.RESPONSE_ERROR; + } finally + { + dbm.Release(); } } @@ -426,31 +498,33 @@ namespace OpenSim.Data.MySQL /// override public ReservationData GetReservationAtPoint(uint x, uint y) { + MySQLSuperManager dbm = GetLockedConnection(); + try { - lock (database) - { Dictionary param = new Dictionary(); param["?x"] = x.ToString(); param["?y"] = y.ToString(); IDbCommand result = - database.Query( + dbm.Manager.Query( "SELECT * FROM reservations WHERE resXMin <= ?x AND resXMax >= ?x AND resYMin <= ?y AND resYMax >= ?y", param); IDataReader reader = result.ExecuteReader(); - ReservationData row = database.readReservationRow(reader); + ReservationData row = dbm.Manager.readReservationRow(reader); reader.Close(); result.Dispose(); return row; - } } catch (Exception e) { - database.Reconnect(); + dbm.Manager.Reconnect(); m_log.Error(e.ToString()); return null; + } finally + { + dbm.Release(); } } } diff --git a/OpenSim/Data/MySQL/MySQLManager.cs b/OpenSim/Data/MySQL/MySQLManager.cs index d193c72625..15bdf443ff 100644 --- a/OpenSim/Data/MySQL/MySQLManager.cs +++ b/OpenSim/Data/MySQL/MySQLManager.cs @@ -41,7 +41,7 @@ namespace OpenSim.Data.MySQL /// /// A MySQL Database manager /// - internal class MySQLManager + public class MySQLManager { private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); diff --git a/OpenSim/Data/MySQL/MySQLSuperManager.cs b/OpenSim/Data/MySQL/MySQLSuperManager.cs index effdac75c5..4a9c7fa82b 100644 --- a/OpenSim/Data/MySQL/MySQLSuperManager.cs +++ b/OpenSim/Data/MySQL/MySQLSuperManager.cs @@ -1,14 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Text; -using System.Threading; +using System.Threading; namespace OpenSim.Data.MySQL { - class MySQLSuperManager + public class MySQLSuperManager { public bool Locked; - private Mutex m_lock = new Mutex(false); + private readonly Mutex m_lock = new Mutex(false); public MySQLManager Manager; public void GetLock()