OpenSim
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros
MySQLFSAssetData.cs
Go to the documentation of this file.
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 OpenSimulator 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 
28 using System;
29 using System.Reflection;
30 using System.Collections.Generic;
31 using System.Data;
32 using OpenSim.Framework;
33 using OpenSim.Framework.Console;
34 using log4net;
35 using MySql.Data.MySqlClient;
36 using OpenMetaverse;
37 
38 namespace OpenSim.Data.MySQL
39 {
41  {
42  private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
43 
44  protected string m_ConnectionString;
45  protected string m_Table;
46 
51  private int DaysBetweenAccessTimeUpdates = 0;
52 
53  protected virtual Assembly Assembly
54  {
55  get { return GetType().Assembly; }
56  }
57 
59  {
60  }
61 
62  #region IPlugin Members
63 
64  public string Version { get { return "1.0.0.0"; } }
65 
66  // Loads and initialises the MySQL storage plugin and checks for migrations
67  public void Initialise(string connect, string realm, int UpdateAccessTime)
68  {
69  m_ConnectionString = connect;
70  m_Table = realm;
71 
72  DaysBetweenAccessTimeUpdates = UpdateAccessTime;
73 
74  try
75  {
76  using (MySqlConnection conn = new MySqlConnection(m_ConnectionString))
77  {
78  conn.Open();
79  Migration m = new Migration(conn, Assembly, "FSAssetStore");
80  m.Update();
81  }
82  }
83  catch (MySqlException e)
84  {
85  m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}", e.Message.ToString());
86  }
87  }
88 
89  public void Initialise()
90  {
91  throw new NotImplementedException();
92  }
93 
94  public void Dispose() { }
95 
96  public string Name
97  {
98  get { return "MySQL FSAsset storage engine"; }
99  }
100 
101  #endregion
102 
103  private bool ExecuteNonQuery(MySqlCommand cmd)
104  {
105  using (MySqlConnection conn = new MySqlConnection(m_ConnectionString))
106  {
107  try
108  {
109  conn.Open();
110  }
111  catch (MySqlException e)
112  {
113  m_log.ErrorFormat("[FSASSETS]: Database open failed with {0}", e.ToString());
114  return false;
115  }
116 
117  cmd.Connection = conn;
118  try
119  {
120  cmd.ExecuteNonQuery();
121  }
122  catch (MySqlException e)
123  {
124  m_log.ErrorFormat("[FSASSETS]: Query {0} failed with {1}", cmd.CommandText, e.ToString());
125  return false;
126  }
127  }
128 
129  return true;
130  }
131 
132  #region IFSAssetDataPlugin Members
133 
134  public AssetMetadata Get(string id, out string hash)
135  {
136  hash = String.Empty;
137 
138  AssetMetadata meta = new AssetMetadata();
139 
140  using (MySqlConnection conn = new MySqlConnection(m_ConnectionString))
141  {
142  try
143  {
144  conn.Open();
145  }
146  catch (MySqlException e)
147  {
148  m_log.ErrorFormat("[FSASSETS]: Database open failed with {0}", e.ToString());
149  return null;
150  }
151 
152  using (MySqlCommand cmd = conn.CreateCommand())
153  {
154  cmd.CommandText = String.Format("select id, name, description, type, hash, create_time, asset_flags, access_time from {0} where id = ?id", m_Table);
155  cmd.Parameters.AddWithValue("?id", id);
156 
157  using (IDataReader reader = cmd.ExecuteReader())
158  {
159  if (!reader.Read())
160  return null;
161 
162  hash = reader["hash"].ToString();
163 
164  meta.ID = id;
165  meta.FullID = new UUID(id);
166 
167  meta.Name = reader["name"].ToString();
168  meta.Description = reader["description"].ToString();
169  meta.Type = (sbyte)Convert.ToInt32(reader["type"]);
170  meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type);
171  meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"]));
172  meta.Flags = (AssetFlags)Convert.ToInt32(reader["asset_flags"]);
173 
174  int AccessTime = Convert.ToInt32(reader["access_time"]);
175  UpdateAccessTime(AccessTime);
176  }
177  }
178 
179  }
180 
181  return meta;
182  }
183 
184  private void UpdateAccessTime(int AccessTime)
185  {
186  // Reduce DB work by only updating access time if asset hasn't recently been accessed
187  // 0 By Default, Config option is "DaysBetweenAccessTimeUpdates"
188  if (DaysBetweenAccessTimeUpdates > 0 && (DateTime.UtcNow - Utils.UnixTimeToDateTime(AccessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
189  return;
190 
191  using (MySqlConnection conn = new MySqlConnection(m_ConnectionString))
192  {
193  try
194  {
195  conn.Open();
196  }
197  catch (MySqlException e)
198  {
199  m_log.ErrorFormat("[FSASSETS]: Database open failed with {0}", e.ToString());
200  return;
201  }
202 
203  using (MySqlCommand cmd = conn.CreateCommand())
204  {
205  cmd.CommandText = String.Format("UPDATE {0} SET `access_time` = UNIX_TIMESTAMP() WHERE `id` = ?id", m_Table);
206 
207  cmd.ExecuteNonQuery();
208  }
209  }
210  }
211 
212  public bool Store(AssetMetadata meta, string hash)
213  {
214  try
215  {
216  string oldhash;
217  AssetMetadata existingAsset = Get(meta.ID, out oldhash);
218 
219  using (MySqlCommand cmd = new MySqlCommand())
220  {
221  cmd.Parameters.AddWithValue("?id", meta.ID);
222  cmd.Parameters.AddWithValue("?name", meta.Name);
223  cmd.Parameters.AddWithValue("?description", meta.Description);
224  cmd.Parameters.AddWithValue("?type", meta.Type.ToString());
225  cmd.Parameters.AddWithValue("?hash", hash);
226  cmd.Parameters.AddWithValue("?asset_flags", meta.Flags);
227 
228  if (existingAsset == null)
229  {
230  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);
231 
232  ExecuteNonQuery(cmd);
233 
234  return true;
235  }
236 
237  //cmd.CommandText = String.Format("update {0} set hash = ?hash, access_time = UNIX_TIMESTAMP() where id = ?id", m_Table);
238 
239  //ExecuteNonQuery(cmd);
240 
241  }
242  return false;
243  }
244  catch(Exception e)
245  {
246  m_log.Error("[FSAssets] Failed to store asset with ID " + meta.ID);
247  m_log.Error(e.ToString());
248  return false;
249  }
250  }
251 
257  public bool[] AssetsExist(UUID[] uuids)
258  {
259  if (uuids.Length == 0)
260  return new bool[0];
261 
262  bool[] results = new bool[uuids.Length];
263  for (int i = 0; i < uuids.Length; i++)
264  results[i] = false;
265 
266  HashSet<UUID> exists = new HashSet<UUID>();
267 
268  string ids = "'" + string.Join("','", uuids) + "'";
269  string sql = string.Format("select id from {1} where id in ({0})", ids, m_Table);
270 
271  using (MySqlConnection conn = new MySqlConnection(m_ConnectionString))
272  {
273  try
274  {
275  conn.Open();
276  }
277  catch (MySqlException e)
278  {
279  m_log.ErrorFormat("[FSASSETS]: Failed to open database: {0}", e.ToString());
280  return results;
281  }
282 
283  using (MySqlCommand cmd = conn.CreateCommand())
284  {
285  cmd.CommandText = sql;
286 
287  using (MySqlDataReader dbReader = cmd.ExecuteReader())
288  {
289  while (dbReader.Read())
290  {
291  UUID id = DBGuid.FromDB(dbReader["ID"]);
292  exists.Add(id);
293  }
294  }
295  }
296  }
297 
298  for (int i = 0; i < uuids.Length; i++)
299  results[i] = exists.Contains(uuids[i]);
300  return results;
301  }
302 
303  public int Count()
304  {
305  int count = 0;
306 
307  using (MySqlConnection conn = new MySqlConnection(m_ConnectionString))
308  {
309  try
310  {
311  conn.Open();
312  }
313  catch (MySqlException e)
314  {
315  m_log.ErrorFormat("[FSASSETS]: Failed to open database: {0}", e.ToString());
316  return 0;
317  }
318 
319  MySqlCommand cmd = conn.CreateCommand();
320 
321  cmd.CommandText = String.Format("select count(*) as count from {0}", m_Table);
322 
323  using (IDataReader reader = cmd.ExecuteReader())
324  {
325  reader.Read();
326 
327  count = Convert.ToInt32(reader["count"]);
328  }
329  }
330 
331  return count;
332  }
333 
334  public bool Delete(string id)
335  {
336  MySqlCommand cmd = new MySqlCommand();
337 
338  cmd.CommandText = String.Format("delete from {0} where id = ?id", m_Table);
339 
340  cmd.Parameters.AddWithValue("?id", id);
341 
342  ExecuteNonQuery(cmd);
343 
344  cmd.Dispose();
345 
346  return true;
347  }
348 
349  public void Import(string conn, string table, int start, int count, bool force, FSStoreDelegate store)
350  {
351  int imported = 0;
352 
353  using (MySqlConnection importConn = new MySqlConnection(conn))
354  {
355  try
356  {
357  importConn.Open();
358  }
359  catch (MySqlException e)
360  {
361  m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}",
362  e.Message.ToString());
363 
364  return;
365  }
366 
367  using (MySqlCommand cmd = importConn.CreateCommand())
368  {
369  string limit = String.Empty;
370  if (count != -1)
371  {
372  limit = String.Format(" limit {0},{1}", start, count);
373  }
374 
375  cmd.CommandText = String.Format("select * from {0}{1}", table, limit);
376 
377  MainConsole.Instance.Output("Querying database");
378  using (IDataReader reader = cmd.ExecuteReader())
379  {
380  MainConsole.Instance.Output("Reading data");
381 
382  while (reader.Read())
383  {
384  if ((imported % 100) == 0)
385  {
386  MainConsole.Instance.Output(String.Format("{0} assets imported so far", imported));
387  }
388 
389  AssetBase asset = new AssetBase();
390  AssetMetadata meta = new AssetMetadata();
391 
392  meta.ID = reader["id"].ToString();
393  meta.FullID = new UUID(meta.ID);
394 
395  meta.Name = reader["name"].ToString();
396  meta.Description = reader["description"].ToString();
397  meta.Type = (sbyte)Convert.ToInt32(reader["assetType"]);
398  meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type);
399  meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"]));
400 
401  asset.Metadata = meta;
402  asset.Data = (byte[])reader["data"];
403 
404  store(asset, force);
405 
406  imported++;
407  }
408  }
409 
410  }
411  }
412 
413  MainConsole.Instance.Output(String.Format("Import done, {0} assets imported", imported));
414  }
415 
416  #endregion
417  }
418 }
bool Store(AssetMetadata meta, string hash)
delegate string FSStoreDelegate(AssetBase asset, bool force)
OpenSim.Server.Handlers.Simulation.Utils Utils
void Initialise(string connect, string realm, int UpdateAccessTime)
AssetMetadata Get(string id, out string hash)
Asset class. All Assets are reference by this class or a class derived from this class ...
Definition: AssetBase.cs:49
bool[] AssetsExist(UUID[] uuids)
Check if the assets exist in the database.
void Initialise()
Default-initialises the plugin
void Import(string conn, string table, int start, int count, bool force, FSStoreDelegate store)