* Added new MySQLSuperManager support for the grid servers.

* In theory, login and a large number of grid functions should now at least be multithreaded.
0.6.0-stable
Adam Frisby 2008-08-30 19:35:22 +00:00
parent 3faadb3f5c
commit 2133fa56e7
3 changed files with 138 additions and 67 deletions

View File

@ -29,8 +29,6 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Data; using System.Data;
using System.Reflection; using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using libsecondlife; using libsecondlife;
using log4net; using log4net;
using OpenSim.Framework; using OpenSim.Framework;
@ -49,6 +47,45 @@ namespace OpenSim.Data.MySQL
/// </summary> /// </summary>
private MySQLManager database; private MySQLManager database;
/// <summary>
/// Better DB manager. Swap-in replacement too.
/// </summary>
public Dictionary<int, MySQLSuperManager> m_dbconnections = new Dictionary<int, MySQLSuperManager>();
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() override public void Initialise()
{ {
m_log.Info("[MySQLGridData]: " + Name + " cannot be default-initialized!"); m_log.Info("[MySQLGridData]: " + Name + " cannot be default-initialized!");
@ -71,6 +108,16 @@ namespace OpenSim.Data.MySQL
if (connect != String.Empty) if (connect != String.Empty)
{ {
database = new MySQLManager(connect); 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 else
{ {
@ -85,6 +132,16 @@ namespace OpenSim.Data.MySQL
database = new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword, database = new MySQLManager(settingHostname, settingDatabase, settingUsername, settingPassword,
settingPooling, settingPort); 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 // This actually does the roll forward assembly stuff
@ -184,10 +241,10 @@ namespace OpenSim.Data.MySQL
/// <returns>Array of sim profiles</returns> /// <returns>Array of sim profiles</returns>
override public RegionProfileData[] GetProfilesInRange(uint xmin, uint ymin, uint xmax, uint ymax) override public RegionProfileData[] GetProfilesInRange(uint xmin, uint ymin, uint xmax, uint ymax)
{ {
MySQLSuperManager dbm = GetLockedConnection();
try try
{ {
lock (database)
{
Dictionary<string, string> param = new Dictionary<string, string>(); Dictionary<string, string> param = new Dictionary<string, string>();
param["?xmin"] = xmin.ToString(); param["?xmin"] = xmin.ToString();
param["?ymin"] = ymin.ToString(); param["?ymin"] = ymin.ToString();
@ -195,7 +252,7 @@ namespace OpenSim.Data.MySQL
param["?ymax"] = ymax.ToString(); param["?ymax"] = ymax.ToString();
IDbCommand result = IDbCommand result =
database.Query( dbm.Manager.Query(
"SELECT * FROM regions WHERE locX >= ?xmin AND locX <= ?xmax AND locY >= ?ymin AND locY <= ?ymax", "SELECT * FROM regions WHERE locX >= ?xmin AND locX <= ?xmax AND locY >= ?ymin AND locY <= ?ymax",
param); param);
IDataReader reader = result.ExecuteReader(); IDataReader reader = result.ExecuteReader();
@ -204,7 +261,7 @@ namespace OpenSim.Data.MySQL
List<RegionProfileData> rows = new List<RegionProfileData>(); List<RegionProfileData> rows = new List<RegionProfileData>();
while ((row = database.readSimRow(reader)) != null) while ((row = dbm.Manager.readSimRow(reader)) != null)
{ {
rows.Add(row); rows.Add(row);
} }
@ -212,14 +269,17 @@ namespace OpenSim.Data.MySQL
result.Dispose(); result.Dispose();
return rows.ToArray(); return rows.ToArray();
}
} }
catch (Exception e) catch (Exception e)
{ {
database.Reconnect(); dbm.Manager.Reconnect();
m_log.Error(e.ToString()); m_log.Error(e.ToString());
return null; return null;
} }
finally
{
dbm.Release();
}
} }
/// <summary> /// <summary>
@ -229,29 +289,32 @@ namespace OpenSim.Data.MySQL
/// <returns>Sim profile</returns> /// <returns>Sim profile</returns>
override public RegionProfileData GetProfileByHandle(ulong handle) override public RegionProfileData GetProfileByHandle(ulong handle)
{ {
MySQLSuperManager dbm = GetLockedConnection();
try try
{ {
lock (database)
{
Dictionary<string, string> param = new Dictionary<string, string>(); Dictionary<string, string> param = new Dictionary<string, string>();
param["?handle"] = handle.ToString(); 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(); IDataReader reader = result.ExecuteReader();
RegionProfileData row = database.readSimRow(reader); RegionProfileData row = dbm.Manager.readSimRow(reader);
reader.Close(); reader.Close();
result.Dispose(); result.Dispose();
return row; return row;
} }
}
catch (Exception e) catch (Exception e)
{ {
database.Reconnect(); dbm.Manager.Reconnect();
m_log.Error(e.ToString()); m_log.Error(e.ToString());
return null; return null;
} }
finally
{
dbm.Release();
}
} }
/// <summary> /// <summary>
@ -261,70 +324,76 @@ namespace OpenSim.Data.MySQL
/// <returns>The sim profile</returns> /// <returns>The sim profile</returns>
override public RegionProfileData GetProfileByLLUUID(LLUUID uuid) override public RegionProfileData GetProfileByLLUUID(LLUUID uuid)
{ {
MySQLSuperManager dbm = GetLockedConnection();
try try
{ {
lock (database)
{
Dictionary<string, string> param = new Dictionary<string, string>(); Dictionary<string, string> param = new Dictionary<string, string>();
param["?uuid"] = uuid.ToString(); 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(); IDataReader reader = result.ExecuteReader();
RegionProfileData row = database.readSimRow(reader); RegionProfileData row = dbm.Manager.readSimRow(reader);
reader.Close(); reader.Close();
result.Dispose(); result.Dispose();
return row; return row;
} }
}
catch (Exception e) catch (Exception e)
{ {
database.Reconnect(); dbm.Manager.Reconnect();
m_log.Error(e.ToString()); m_log.Error(e.ToString());
return null; return null;
} finally
{
dbm.Release();
} }
} }
/// <summary> /// <summary>
/// Returns a sim profile from it's Region name string /// Returns a sim profile from it's Region name string
/// </summary> /// </summary>
/// <param name="uuid">The region name search query</param>
/// <returns>The sim profile</returns> /// <returns>The sim profile</returns>
override public RegionProfileData GetProfileByString(string regionName) override public RegionProfileData GetProfileByString(string regionName)
{ {
MySQLSuperManager dbm = GetLockedConnection();
if (regionName.Length > 2) if (regionName.Length > 2)
{ {
try try
{ {
lock (database) Dictionary<string, string> param = new Dictionary<string, string>();
{ // Add % because this is a like query.
Dictionary<string, string> param = new Dictionary<string, string>(); param["?regionName"] = regionName + "%";
// Add % because this is a like query. // Order by statement will return shorter matches first. Only returns one record or no record.
param["?regionName"] = regionName + "%"; IDbCommand result =
// Order by statement will return shorter matches first. Only returns one record or no record. dbm.Manager.Query(
IDbCommand result = database.Query("SELECT * FROM regions WHERE regionName like ?regionName order by LENGTH(regionName) asc LIMIT 1", param); "SELECT * FROM regions WHERE regionName like ?regionName order by LENGTH(regionName) asc LIMIT 1",
IDataReader reader = result.ExecuteReader(); param);
IDataReader reader = result.ExecuteReader();
RegionProfileData row = database.readSimRow(reader); RegionProfileData row = dbm.Manager.readSimRow(reader);
reader.Close(); reader.Close();
result.Dispose(); result.Dispose();
return row; return row;
}
} }
catch (Exception e) catch (Exception e)
{ {
database.Reconnect(); dbm.Manager.Reconnect();
m_log.Error(e.ToString()); m_log.Error(e.ToString());
return null; return null;
} }
finally
{
dbm.Release();
}
} }
else dbm.Release();
{ m_log.Error("[GRID DB]: Searched for a Region Name shorter then 3 characters");
m_log.Error("[GRID DB]: Searched for a Region Name shorter then 3 characters"); return null;
return null;
}
} }
/// <summary> /// <summary>
@ -334,16 +403,17 @@ namespace OpenSim.Data.MySQL
/// <returns>Successful?</returns> /// <returns>Successful?</returns>
override public DataResponse AddProfile(RegionProfileData profile) override public DataResponse AddProfile(RegionProfileData profile)
{ {
lock (database) MySQLSuperManager dbm = GetLockedConnection();
{ try {
if (database.insertRegion(profile)) if (dbm.Manager.insertRegion(profile))
{ {
return DataResponse.RESPONSE_OK; 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(RegionProfileData profile)
public DataResponse DeleteProfile(string uuid) public DataResponse DeleteProfile(string uuid)
{ {
lock (database) MySQLSuperManager dbm = GetLockedConnection();
{
if (database.deleteRegion(uuid))
try {
if (dbm.Manager.deleteRegion(uuid))
{ {
return DataResponse.RESPONSE_OK; return DataResponse.RESPONSE_OK;
} }
else return DataResponse.RESPONSE_ERROR;
{ } finally
return DataResponse.RESPONSE_ERROR; {
} dbm.Release();
} }
} }
@ -426,31 +498,33 @@ namespace OpenSim.Data.MySQL
/// <returns></returns> /// <returns></returns>
override public ReservationData GetReservationAtPoint(uint x, uint y) override public ReservationData GetReservationAtPoint(uint x, uint y)
{ {
MySQLSuperManager dbm = GetLockedConnection();
try try
{ {
lock (database)
{
Dictionary<string, string> param = new Dictionary<string, string>(); Dictionary<string, string> param = new Dictionary<string, string>();
param["?x"] = x.ToString(); param["?x"] = x.ToString();
param["?y"] = y.ToString(); param["?y"] = y.ToString();
IDbCommand result = IDbCommand result =
database.Query( dbm.Manager.Query(
"SELECT * FROM reservations WHERE resXMin <= ?x AND resXMax >= ?x AND resYMin <= ?y AND resYMax >= ?y", "SELECT * FROM reservations WHERE resXMin <= ?x AND resXMax >= ?x AND resYMin <= ?y AND resYMax >= ?y",
param); param);
IDataReader reader = result.ExecuteReader(); IDataReader reader = result.ExecuteReader();
ReservationData row = database.readReservationRow(reader); ReservationData row = dbm.Manager.readReservationRow(reader);
reader.Close(); reader.Close();
result.Dispose(); result.Dispose();
return row; return row;
}
} }
catch (Exception e) catch (Exception e)
{ {
database.Reconnect(); dbm.Manager.Reconnect();
m_log.Error(e.ToString()); m_log.Error(e.ToString());
return null; return null;
} finally
{
dbm.Release();
} }
} }
} }

View File

@ -41,7 +41,7 @@ namespace OpenSim.Data.MySQL
/// <summary> /// <summary>
/// A MySQL Database manager /// A MySQL Database manager
/// </summary> /// </summary>
internal class MySQLManager public class MySQLManager
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);

View File

@ -1,14 +1,11 @@
using System; using System.Threading;
using System.Collections.Generic;
using System.Text;
using System.Threading;
namespace OpenSim.Data.MySQL namespace OpenSim.Data.MySQL
{ {
class MySQLSuperManager public class MySQLSuperManager
{ {
public bool Locked; public bool Locked;
private Mutex m_lock = new Mutex(false); private readonly Mutex m_lock = new Mutex(false);
public MySQLManager Manager; public MySQLManager Manager;
public void GetLock() public void GetLock()