MySQLAssetData.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSim Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Data;
  30. using System.Reflection;
  31. using libsecondlife;
  32. using log4net;
  33. using MySql.Data.MySqlClient;
  34. using OpenSim.Framework;
  35. namespace OpenSim.Data.MySQL
  36. {
  37. /// <summary>
  38. /// A MySQL Interface for the Asset Server
  39. /// </summary>
  40. internal class MySQLAssetData : AssetDataBase
  41. {
  42. private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
  43. private MySQLManager _dbConnection;
  44. #region IPlugin Members
  45. /// <summary>
  46. /// <para>Initialises Asset interface</para>
  47. /// <para>
  48. /// <list type="bullet">
  49. /// <item>Loads and initialises the MySQL storage plugin.</item>
  50. /// <item>Warns and uses the obsolete mysql_connection.ini if connect string is empty.</item>
  51. /// <item>Check for migration</item>
  52. /// </list>
  53. /// </para>
  54. /// </summary>
  55. /// <param name="connect">connect string</param>
  56. override public void Initialise(string connect)
  57. {
  58. // TODO: This will let you pass in the connect string in
  59. // the config, though someone will need to write that.
  60. if (connect == String.Empty)
  61. {
  62. // This is old seperate config file
  63. m_log.Warn("no connect string, using old mysql_connection.ini instead");
  64. Initialise();
  65. }
  66. else
  67. {
  68. _dbConnection = new MySQLManager(connect);
  69. }
  70. // This actually does the roll forward assembly stuff
  71. Assembly assem = GetType().Assembly;
  72. Migration m = new Migration(_dbConnection.Connection, assem, "AssetStore");
  73. // TODO: After rev 6000, remove this. People should have
  74. // been rolled onto the new migration code by then.
  75. TestTables(m);
  76. m.Update();
  77. }
  78. /// <summary>
  79. /// <para>Initialises Asset interface</para>
  80. /// <para>
  81. /// <list type="bullet">
  82. /// <item>Loads and initialises the MySQL storage plugin</item>
  83. /// <item>uses the obsolete mysql_connection.ini</item>
  84. /// </list>
  85. /// </para>
  86. /// </summary>
  87. /// <param name="connect">connect string</param>
  88. /// <remarks>Probably DEPRECATED and shouldn't be used</remarks>
  89. override public void Initialise()
  90. {
  91. IniFile GridDataMySqlFile = new IniFile("mysql_connection.ini");
  92. string hostname = GridDataMySqlFile.ParseFileReadValue("hostname");
  93. string database = GridDataMySqlFile.ParseFileReadValue("database");
  94. string username = GridDataMySqlFile.ParseFileReadValue("username");
  95. string password = GridDataMySqlFile.ParseFileReadValue("password");
  96. string pooling = GridDataMySqlFile.ParseFileReadValue("pooling");
  97. string port = GridDataMySqlFile.ParseFileReadValue("port");
  98. _dbConnection = new MySQLManager(hostname, database, username, password, pooling, port);
  99. }
  100. override public void Dispose() { }
  101. #region IAssetProvider Members
  102. /// <summary>
  103. /// <list type="bullet">
  104. /// <item>Execute CreateAssetsTable.sql if oldVersion == null</item>
  105. /// <item>do nothing if oldVersion != null</item>
  106. /// </list>
  107. /// </summary>
  108. /// <param name="oldVersion"></param>
  109. // private void UpgradeAssetsTable(string oldVersion)
  110. // {
  111. // // null as the version, indicates that the table didn't exist
  112. // if (oldVersion == null)
  113. // {
  114. // m_log.Info("[ASSETS DB]: Creating new database tables");
  115. // _dbConnection.ExecuteResourceSql("CreateAssetsTable.sql");
  116. // return;
  117. // }
  118. // }
  119. /// <summary>
  120. /// Ensure that the assets related tables exists and are at the latest version
  121. /// </summary>
  122. /// <param name="m"></param>
  123. private void TestTables(Migration m)
  124. {
  125. Dictionary<string, string> tableList = new Dictionary<string, string>();
  126. tableList["assets"] = null;
  127. _dbConnection.GetTableVersion(tableList);
  128. // if there is no table, return, migrations will handle it.
  129. if (tableList["assets"] == null)
  130. return;
  131. // if there is a table, and we don't have a migration, set it to 1
  132. if (m.Version == 0)
  133. m.Version = 1;
  134. }
  135. /// <summary>
  136. /// Fetch Asset <paramref name="assetID"/> from database
  137. /// </summary>
  138. /// <param name="assetID">Asset UUID to fetch</param>
  139. /// <returns>Return the asset</returns>
  140. /// <remarks>On failure : throw an exception and attempt to reconnect to database</remarks>
  141. override public AssetBase FetchAsset(LLUUID assetID)
  142. {
  143. AssetBase asset = null;
  144. lock (_dbConnection)
  145. {
  146. _dbConnection.CheckConnection();
  147. MySqlCommand cmd =
  148. new MySqlCommand(
  149. "SELECT name, description, assetType, local, temporary, data FROM assets WHERE id=?id",
  150. _dbConnection.Connection);
  151. cmd.Parameters.AddWithValue("?id", assetID.ToString());
  152. try
  153. {
  154. using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
  155. {
  156. if (dbReader.Read())
  157. {
  158. asset = new AssetBase();
  159. asset.Data = (byte[]) dbReader["data"];
  160. asset.Description = (string) dbReader["description"];
  161. asset.FullID = assetID;
  162. asset.Local = ((sbyte) dbReader["local"]) != 0 ? true : false;
  163. asset.Name = (string) dbReader["name"];
  164. asset.Type = (sbyte) dbReader["assetType"];
  165. }
  166. dbReader.Close();
  167. cmd.Dispose();
  168. }
  169. }
  170. catch (Exception e)
  171. {
  172. m_log.ErrorFormat(
  173. "[ASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString()
  174. + Environment.NewLine + "Reconnecting", assetID);
  175. _dbConnection.Reconnect();
  176. }
  177. }
  178. return asset;
  179. }
  180. /// <summary>
  181. /// Create an asset in database, or update it if existing.
  182. /// </summary>
  183. /// <param name="asset">Asset UUID to create</param>
  184. /// <remarks>On failure : Throw an exception and attempt to reconnect to database</remarks>
  185. override public void CreateAsset(AssetBase asset)
  186. {
  187. lock (_dbConnection)
  188. {
  189. //m_log.Info("[ASSET DB]: Creating Asset " + Util.ToRawUuidString(asset.FullID));
  190. if (ExistsAsset(asset.FullID))
  191. {
  192. //m_log.Info("[ASSET DB]: Asset exists already, ignoring.");
  193. return;
  194. }
  195. _dbConnection.CheckConnection();
  196. MySqlCommand cmd =
  197. new MySqlCommand(
  198. "REPLACE INTO assets(id, name, description, assetType, local, temporary, data)" +
  199. "VALUES(?id, ?name, ?description, ?assetType, ?local, ?temporary, ?data)",
  200. _dbConnection.Connection);
  201. // need to ensure we dispose
  202. try
  203. {
  204. using (cmd)
  205. {
  206. cmd.Parameters.AddWithValue("?id", asset.FullID.ToString());
  207. cmd.Parameters.AddWithValue("?name", asset.Name);
  208. cmd.Parameters.AddWithValue("?description", asset.Description);
  209. cmd.Parameters.AddWithValue("?assetType", asset.Type);
  210. cmd.Parameters.AddWithValue("?local", asset.Local);
  211. cmd.Parameters.AddWithValue("?temporary", asset.Temporary);
  212. cmd.Parameters.AddWithValue("?data", asset.Data);
  213. cmd.ExecuteNonQuery();
  214. cmd.Dispose();
  215. }
  216. }
  217. catch (Exception e)
  218. {
  219. m_log.ErrorFormat(
  220. "[ASSETS DB]: " +
  221. "MySql failure creating asset {0} with name {1}" + Environment.NewLine + e.ToString()
  222. + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
  223. _dbConnection.Reconnect();
  224. }
  225. }
  226. }
  227. /// <summary>
  228. /// Update a asset in database, see <see cref="CreateAsset"/>
  229. /// </summary>
  230. /// <param name="asset">Asset UUID to update</param>
  231. override public void UpdateAsset(AssetBase asset)
  232. {
  233. CreateAsset(asset);
  234. }
  235. /// <summary>
  236. /// check if the asset UUID exist in database
  237. /// </summary>
  238. /// <param name="uuid">The asset UUID</param>
  239. /// <returns>true if exist.</returns>
  240. override public bool ExistsAsset(LLUUID uuid)
  241. {
  242. bool assetExists = false;
  243. lock (_dbConnection)
  244. {
  245. _dbConnection.CheckConnection();
  246. MySqlCommand cmd =
  247. new MySqlCommand(
  248. "SELECT id FROM assets WHERE id=?id",
  249. _dbConnection.Connection);
  250. cmd.Parameters.AddWithValue("?id", uuid.ToString());
  251. try
  252. {
  253. using (MySqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
  254. {
  255. if (dbReader.Read())
  256. {
  257. assetExists = true;
  258. }
  259. dbReader.Close();
  260. cmd.Dispose();
  261. }
  262. }
  263. catch (Exception e)
  264. {
  265. m_log.ErrorFormat(
  266. "[ASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString()
  267. + Environment.NewLine + "Attempting reconnection", uuid);
  268. _dbConnection.Reconnect();
  269. }
  270. }
  271. return assetExists;
  272. }
  273. #endregion
  274. /// <summary>
  275. /// Database provider version
  276. /// </summary>
  277. override public string Version
  278. {
  279. get { return _dbConnection.getVersion(); }
  280. }
  281. /// <summary>
  282. /// The name of this DB provider
  283. /// </summary>
  284. override public string Name
  285. {
  286. get { return "MySQL Asset storage engine"; }
  287. }
  288. #endregion
  289. }
  290. }