diff options
-rw-r--r-- | OpenSim/Data/MySQL/MySQLFSAssetData.cs | 379 | ||||
-rw-r--r-- | OpenSim/Services/FSAssetService/FSAssetService.cs | 118 |
2 files changed, 285 insertions, 212 deletions
diff --git a/OpenSim/Data/MySQL/MySQLFSAssetData.cs b/OpenSim/Data/MySQL/MySQLFSAssetData.cs index 19e23b5..40bfd1f 100644 --- a/OpenSim/Data/MySQL/MySQLFSAssetData.cs +++ b/OpenSim/Data/MySQL/MySQLFSAssetData.cs | |||
@@ -41,10 +41,8 @@ namespace OpenSim.Data.MySQL | |||
41 | { | 41 | { |
42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 42 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
43 | 43 | ||
44 | protected MySqlConnection m_Connection = null; | ||
45 | protected string m_ConnectionString; | 44 | protected string m_ConnectionString; |
46 | protected string m_Table; | 45 | protected string m_Table; |
47 | protected Object m_connLock = new Object(); | ||
48 | 46 | ||
49 | /// <summary> | 47 | /// <summary> |
50 | /// Number of days that must pass before we update the access time on an asset when it has been fetched | 48 | /// Number of days that must pass before we update the access time on an asset when it has been fetched |
@@ -75,10 +73,11 @@ namespace OpenSim.Data.MySQL | |||
75 | 73 | ||
76 | try | 74 | try |
77 | { | 75 | { |
78 | OpenDatabase(); | 76 | using (MySqlConnection conn = new MySqlConnection(m_ConnectionString)) |
79 | 77 | { | |
80 | Migration m = new Migration(m_Connection, Assembly, "FSAssetStore"); | 78 | Migration m = new Migration(conn, Assembly, "FSAssetStore"); |
81 | m.Update(); | 79 | m.Update(); |
80 | } | ||
82 | } | 81 | } |
83 | catch (MySqlException e) | 82 | catch (MySqlException e) |
84 | { | 83 | { |
@@ -100,70 +99,33 @@ namespace OpenSim.Data.MySQL | |||
100 | 99 | ||
101 | #endregion | 100 | #endregion |
102 | 101 | ||
103 | private bool OpenDatabase() | 102 | private bool ExecuteNonQuery(MySqlCommand cmd) |
104 | { | ||
105 | try | ||
106 | { | ||
107 | m_Connection = new MySqlConnection(m_ConnectionString); | ||
108 | |||
109 | m_Connection.Open(); | ||
110 | } | ||
111 | catch (MySqlException e) | ||
112 | { | ||
113 | m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}", | ||
114 | e.Message.ToString()); | ||
115 | |||
116 | return false; | ||
117 | } | ||
118 | |||
119 | return true; | ||
120 | } | ||
121 | |||
122 | private IDataReader ExecuteReader(MySqlCommand c) | ||
123 | { | ||
124 | IDataReader r = null; | ||
125 | MySqlConnection connection = (MySqlConnection) ((ICloneable)m_Connection).Clone(); | ||
126 | connection.Open(); | ||
127 | c.Connection = connection; | ||
128 | |||
129 | r = c.ExecuteReader(); | ||
130 | |||
131 | return r; | ||
132 | } | ||
133 | |||
134 | private void ExecuteNonQuery(MySqlCommand c) | ||
135 | { | 103 | { |
136 | lock (m_connLock) | 104 | using (MySqlConnection conn = new MySqlConnection(m_ConnectionString)) |
137 | { | 105 | { |
138 | bool errorSeen = false; | 106 | try |
139 | |||
140 | while (true) | ||
141 | { | 107 | { |
142 | try | 108 | conn.Open(); |
143 | { | 109 | } |
144 | c.ExecuteNonQuery(); | 110 | catch (MySqlException e) |
145 | } | 111 | { |
146 | catch (MySqlException) | 112 | m_log.ErrorFormat("[FSASSETS]: Database open failed with {0}", e.ToString()); |
147 | { | 113 | return false; |
148 | System.Threading.Thread.Sleep(500); | 114 | } |
149 | |||
150 | m_Connection.Close(); | ||
151 | m_Connection = (MySqlConnection) ((ICloneable)m_Connection).Clone(); | ||
152 | m_Connection.Open(); | ||
153 | c.Connection = m_Connection; | ||
154 | |||
155 | if (!errorSeen) | ||
156 | { | ||
157 | errorSeen = true; | ||
158 | continue; | ||
159 | } | ||
160 | m_log.ErrorFormat("[FSASSETS] MySQL command: {0}", c.CommandText); | ||
161 | throw; | ||
162 | } | ||
163 | 115 | ||
164 | break; | 116 | cmd.Connection = conn; |
117 | try | ||
118 | { | ||
119 | cmd.ExecuteNonQuery(); | ||
120 | } | ||
121 | catch (MySqlException e) | ||
122 | { | ||
123 | m_log.ErrorFormat("[FSASSETS]: Query {0} failed with {1}", cmd.CommandText, e.ToString()); | ||
124 | return false; | ||
165 | } | 125 | } |
166 | } | 126 | } |
127 | |||
128 | return true; | ||
167 | } | 129 | } |
168 | 130 | ||
169 | #region IFSAssetDataPlugin Members | 131 | #region IFSAssetDataPlugin Members |
@@ -172,63 +134,78 @@ namespace OpenSim.Data.MySQL | |||
172 | { | 134 | { |
173 | hash = String.Empty; | 135 | hash = String.Empty; |
174 | 136 | ||
175 | MySqlCommand cmd = new MySqlCommand(); | 137 | AssetMetadata meta = new AssetMetadata(); |
176 | |||
177 | cmd.CommandText = String.Format("select id, name, description, type, hash, create_time, access_time, asset_flags from {0} where id = ?id", m_Table); | ||
178 | cmd.Parameters.AddWithValue("?id", id); | ||
179 | |||
180 | IDataReader reader = ExecuteReader(cmd); | ||
181 | 138 | ||
182 | if (!reader.Read()) | 139 | using (MySqlConnection conn = new MySqlConnection(m_ConnectionString)) |
183 | { | 140 | { |
184 | reader.Close(); | 141 | try |
185 | FreeCommand(cmd); | 142 | { |
186 | return null; | 143 | conn.Open(); |
187 | } | 144 | } |
188 | 145 | catch (MySqlException e) | |
189 | AssetMetadata meta = new AssetMetadata(); | 146 | { |
147 | m_log.ErrorFormat("[FSASSETS]: Database open failed with {0}", e.ToString()); | ||
148 | return null; | ||
149 | } | ||
190 | 150 | ||
191 | hash = reader["hash"].ToString(); | 151 | using (MySqlCommand cmd = conn.CreateCommand()) |
152 | { | ||
153 | cmd.CommandText = String.Format("select id, name, description, type, hash, create_time, asset_flags from {0} where id = ?id", m_Table); | ||
154 | cmd.Parameters.AddWithValue("?id", id); | ||
192 | 155 | ||
193 | meta.ID = id; | 156 | using (IDataReader reader = cmd.ExecuteReader()) |
194 | meta.FullID = new UUID(id); | 157 | { |
158 | if (!reader.Read()) | ||
159 | return null; | ||
195 | 160 | ||
196 | meta.Name = reader["name"].ToString(); | 161 | hash = reader["hash"].ToString(); |
197 | meta.Description = reader["description"].ToString(); | ||
198 | meta.Type = (sbyte)Convert.ToInt32(reader["type"]); | ||
199 | meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type); | ||
200 | meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"])); | ||
201 | meta.Flags = (AssetFlags)Convert.ToInt32(reader["asset_flags"]); | ||
202 | 162 | ||
203 | int AccessTime = Convert.ToInt32(reader["access_time"]); | 163 | meta.ID = id; |
164 | meta.FullID = new UUID(id); | ||
204 | 165 | ||
205 | reader.Close(); | 166 | meta.Name = reader["name"].ToString(); |
167 | meta.Description = reader["description"].ToString(); | ||
168 | meta.Type = (sbyte)Convert.ToInt32(reader["type"]); | ||
169 | meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type); | ||
170 | meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"])); | ||
171 | meta.Flags = (AssetFlags)Convert.ToInt32(reader["asset_flags"]); | ||
206 | 172 | ||
207 | UpdateAccessTime(AccessTime, cmd); | 173 | int AccessTime = Convert.ToInt32(reader["access_time"]); |
174 | UpdateAccessTime(AccessTime); | ||
175 | } | ||
176 | } | ||
208 | 177 | ||
209 | FreeCommand(cmd); | 178 | } |
210 | 179 | ||
211 | return meta; | 180 | return meta; |
212 | } | 181 | } |
213 | 182 | ||
214 | private void UpdateAccessTime(int AccessTime, MySqlCommand cmd) | 183 | private void UpdateAccessTime(int AccessTime) |
215 | { | 184 | { |
216 | // Reduce DB work by only updating access time if asset hasn't recently been accessed | 185 | // Reduce DB work by only updating access time if asset hasn't recently been accessed |
217 | // 0 By Default, Config option is "DaysBetweenAccessTimeUpdates" | 186 | // 0 By Default, Config option is "DaysBetweenAccessTimeUpdates" |
218 | if (DaysBetweenAccessTimeUpdates > 0 && (DateTime.UtcNow - Utils.UnixTimeToDateTime(AccessTime)).TotalDays < DaysBetweenAccessTimeUpdates) | 187 | if (DaysBetweenAccessTimeUpdates > 0 && (DateTime.UtcNow - Utils.UnixTimeToDateTime(AccessTime)).TotalDays < DaysBetweenAccessTimeUpdates) |
219 | return; | 188 | return; |
220 | 189 | ||
221 | cmd.CommandText = String.Format("UPDATE {0} SET `access_time` = UNIX_TIMESTAMP() WHERE `id` = ?id", m_Table); | 190 | using (MySqlConnection conn = new MySqlConnection(m_ConnectionString)) |
191 | { | ||
192 | try | ||
193 | { | ||
194 | conn.Open(); | ||
195 | } | ||
196 | catch (MySqlException e) | ||
197 | { | ||
198 | m_log.ErrorFormat("[FSASSETS]: Database open failed with {0}", e.ToString()); | ||
199 | return; | ||
200 | } | ||
222 | 201 | ||
223 | cmd.ExecuteNonQuery(); | 202 | using (MySqlCommand cmd = conn.CreateCommand()) |
224 | } | 203 | { |
204 | cmd.CommandText = String.Format("UPDATE {0} SET `access_time` = UNIX_TIMESTAMP() WHERE `id` = ?id", m_Table); | ||
225 | 205 | ||
226 | protected void FreeCommand(MySqlCommand cmd) | 206 | cmd.ExecuteNonQuery(); |
227 | { | 207 | } |
228 | MySqlConnection c = cmd.Connection; | 208 | } |
229 | cmd.Dispose(); | ||
230 | c.Close(); | ||
231 | c.Dispose(); | ||
232 | } | 209 | } |
233 | 210 | ||
234 | public bool Store(AssetMetadata meta, string hash) | 211 | public bool Store(AssetMetadata meta, string hash) |
@@ -238,37 +215,35 @@ namespace OpenSim.Data.MySQL | |||
238 | string oldhash; | 215 | string oldhash; |
239 | AssetMetadata existingAsset = Get(meta.ID, out oldhash); | 216 | AssetMetadata existingAsset = Get(meta.ID, out oldhash); |
240 | 217 | ||
241 | MySqlCommand cmd = m_Connection.CreateCommand(); | 218 | using (MySqlCommand cmd = new MySqlCommand()) |
242 | |||
243 | cmd.Parameters.AddWithValue("?id", meta.ID); | ||
244 | cmd.Parameters.AddWithValue("?name", meta.Name); | ||
245 | cmd.Parameters.AddWithValue("?description", meta.Description); | ||
246 | cmd.Parameters.AddWithValue("?type", meta.Type.ToString()); | ||
247 | cmd.Parameters.AddWithValue("?hash", hash); | ||
248 | cmd.Parameters.AddWithValue("?asset_flags", meta.Flags); | ||
249 | |||
250 | if (existingAsset == null) | ||
251 | { | 219 | { |
252 | 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); | 220 | cmd.Parameters.AddWithValue("?id", meta.ID); |
253 | 221 | cmd.Parameters.AddWithValue("?name", meta.Name); | |
254 | ExecuteNonQuery(cmd); | 222 | cmd.Parameters.AddWithValue("?description", meta.Description); |
223 | cmd.Parameters.AddWithValue("?type", meta.Type.ToString()); | ||
224 | cmd.Parameters.AddWithValue("?hash", hash); | ||
225 | cmd.Parameters.AddWithValue("?asset_flags", meta.Flags); | ||
226 | |||
227 | if (existingAsset == null) | ||
228 | { | ||
229 | 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); | ||
255 | 230 | ||
256 | cmd.Dispose(); | 231 | ExecuteNonQuery(cmd); |
257 | 232 | ||
258 | return true; | 233 | return true; |
259 | } | 234 | } |
260 | 235 | ||
261 | //cmd.CommandText = String.Format("update {0} set hash = ?hash, access_time = UNIX_TIMESTAMP() where id = ?id", m_Table); | 236 | //cmd.CommandText = String.Format("update {0} set hash = ?hash, access_time = UNIX_TIMESTAMP() where id = ?id", m_Table); |
262 | 237 | ||
263 | //ExecuteNonQuery(cmd); | 238 | //ExecuteNonQuery(cmd); |
264 | 239 | ||
265 | cmd.Dispose(); | 240 | } |
266 | return false; | 241 | return false; |
267 | } | 242 | } |
268 | catch(Exception e) | 243 | catch(Exception e) |
269 | { | 244 | { |
270 | m_log.Error("[FSAssets] Failed to store asset with ID " + meta.ID); | 245 | m_log.Error("[FSAssets] Failed to store asset with ID " + meta.ID); |
271 | m_log.Error(e.ToString()); | 246 | m_log.Error(e.ToString()); |
272 | return false; | 247 | return false; |
273 | } | 248 | } |
274 | } | 249 | } |
@@ -283,26 +258,42 @@ namespace OpenSim.Data.MySQL | |||
283 | if (uuids.Length == 0) | 258 | if (uuids.Length == 0) |
284 | return new bool[0]; | 259 | return new bool[0]; |
285 | 260 | ||
261 | bool[] results = new bool[uuids.Length]; | ||
262 | for (int i = 0; i < uuids.Length; i++) | ||
263 | results[i] = false; | ||
264 | |||
286 | HashSet<UUID> exists = new HashSet<UUID>(); | 265 | HashSet<UUID> exists = new HashSet<UUID>(); |
287 | 266 | ||
288 | string ids = "'" + string.Join("','", uuids) + "'"; | 267 | string ids = "'" + string.Join("','", uuids) + "'"; |
289 | string sql = string.Format("select id from {1} where id in ({0})", ids, m_Table); | 268 | string sql = string.Format("select id from {1} where id in ({0})", ids, m_Table); |
290 | 269 | ||
291 | using (MySqlCommand cmd = m_Connection.CreateCommand()) | 270 | using (MySqlConnection conn = new MySqlConnection(m_ConnectionString)) |
292 | { | 271 | { |
293 | cmd.CommandText = sql; | 272 | try |
273 | { | ||
274 | conn.Open(); | ||
275 | } | ||
276 | catch (MySqlException e) | ||
277 | { | ||
278 | m_log.ErrorFormat("[FSASSETS]: Failed to open database: {0}", e.ToString()); | ||
279 | return results; | ||
280 | } | ||
294 | 281 | ||
295 | using (MySqlDataReader dbReader = cmd.ExecuteReader()) | 282 | using (MySqlCommand cmd = conn.CreateCommand()) |
296 | { | 283 | { |
297 | while (dbReader.Read()) | 284 | cmd.CommandText = sql; |
285 | |||
286 | using (MySqlDataReader dbReader = cmd.ExecuteReader()) | ||
298 | { | 287 | { |
299 | UUID id = DBGuid.FromDB(dbReader["ID"]); | 288 | while (dbReader.Read()) |
300 | exists.Add(id); | 289 | { |
290 | UUID id = DBGuid.FromDB(dbReader["ID"]); | ||
291 | exists.Add(id); | ||
292 | } | ||
301 | } | 293 | } |
302 | } | 294 | } |
303 | } | 295 | } |
304 | 296 | ||
305 | bool[] results = new bool[uuids.Length]; | ||
306 | for (int i = 0; i < uuids.Length; i++) | 297 | for (int i = 0; i < uuids.Length; i++) |
307 | results[i] = exists.Contains(uuids[i]); | 298 | results[i] = exists.Contains(uuids[i]); |
308 | return results; | 299 | return results; |
@@ -310,102 +301,114 @@ namespace OpenSim.Data.MySQL | |||
310 | 301 | ||
311 | public int Count() | 302 | public int Count() |
312 | { | 303 | { |
313 | MySqlCommand cmd = m_Connection.CreateCommand(); | 304 | int count = 0; |
314 | 305 | ||
315 | cmd.CommandText = String.Format("select count(*) as count from {0}", m_Table); | 306 | using (MySqlConnection conn = new MySqlConnection(m_ConnectionString)) |
307 | { | ||
308 | try | ||
309 | { | ||
310 | conn.Open(); | ||
311 | } | ||
312 | catch (MySqlException e) | ||
313 | { | ||
314 | m_log.ErrorFormat("[FSASSETS]: Failed to open database: {0}", e.ToString()); | ||
315 | return 0; | ||
316 | } | ||
316 | 317 | ||
317 | IDataReader reader = ExecuteReader(cmd); | 318 | MySqlCommand cmd = conn.CreateCommand(); |
318 | 319 | ||
319 | reader.Read(); | 320 | cmd.CommandText = String.Format("select count(*) as count from {0}", m_Table); |
320 | 321 | ||
321 | int count = Convert.ToInt32(reader["count"]); | 322 | using (IDataReader reader = cmd.ExecuteReader()) |
323 | { | ||
324 | reader.Read(); | ||
322 | 325 | ||
323 | reader.Close(); | 326 | count = Convert.ToInt32(reader["count"]); |
324 | FreeCommand(cmd); | 327 | } |
328 | } | ||
325 | 329 | ||
326 | return count; | 330 | return count; |
327 | } | 331 | } |
328 | 332 | ||
329 | public bool Delete(string id) | 333 | public bool Delete(string id) |
330 | { | 334 | { |
331 | using (MySqlCommand cmd = m_Connection.CreateCommand()) | 335 | MySqlCommand cmd = new MySqlCommand(); |
332 | { | ||
333 | cmd.CommandText = String.Format("delete from {0} where id = ?id", m_Table); | ||
334 | 336 | ||
335 | cmd.Parameters.AddWithValue("?id", id); | 337 | cmd.CommandText = String.Format("delete from {0} where id = ?id", m_Table); |
336 | 338 | ||
337 | ExecuteNonQuery(cmd); | 339 | cmd.Parameters.AddWithValue("?id", id); |
338 | } | 340 | |
341 | ExecuteNonQuery(cmd); | ||
342 | |||
343 | cmd.Dispose(); | ||
339 | 344 | ||
340 | return true; | 345 | return true; |
341 | } | 346 | } |
342 | 347 | ||
343 | public void Import(string conn, string table, int start, int count, bool force, FSStoreDelegate store) | 348 | public void Import(string conn, string table, int start, int count, bool force, FSStoreDelegate store) |
344 | { | 349 | { |
345 | MySqlConnection importConn; | 350 | int imported = 0; |
346 | |||
347 | try | ||
348 | { | ||
349 | importConn = new MySqlConnection(conn); | ||
350 | 351 | ||
351 | importConn.Open(); | 352 | using (MySqlConnection importConn = new MySqlConnection(conn)) |
352 | } | ||
353 | catch (MySqlException e) | ||
354 | { | 353 | { |
355 | m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}", | 354 | try |
356 | e.Message.ToString()); | 355 | { |
356 | importConn.Open(); | ||
357 | } | ||
358 | catch (MySqlException e) | ||
359 | { | ||
360 | m_log.ErrorFormat("[FSASSETS]: Can't connect to database: {0}", | ||
361 | e.Message.ToString()); | ||
357 | 362 | ||
358 | return; | 363 | return; |
359 | } | 364 | } |
360 | 365 | ||
361 | int imported = 0; | 366 | using (MySqlCommand cmd = importConn.CreateCommand()) |
367 | { | ||
368 | string limit = String.Empty; | ||
369 | if (count != -1) | ||
370 | { | ||
371 | limit = String.Format(" limit {0},{1}", start, count); | ||
372 | } | ||
362 | 373 | ||
363 | MySqlCommand cmd = importConn.CreateCommand(); | 374 | cmd.CommandText = String.Format("select * from {0}{1}", table, limit); |
364 | 375 | ||
365 | string limit = String.Empty; | 376 | MainConsole.Instance.Output("Querying database"); |
366 | if (count != -1) | 377 | using (IDataReader reader = cmd.ExecuteReader()) |
367 | { | 378 | { |
368 | limit = String.Format(" limit {0},{1}", start, count); | 379 | MainConsole.Instance.Output("Reading data"); |
369 | } | ||
370 | |||
371 | cmd.CommandText = String.Format("select * from {0}{1}", table, limit); | ||
372 | 380 | ||
373 | MainConsole.Instance.Output("Querying database"); | 381 | while (reader.Read()) |
374 | IDataReader reader = cmd.ExecuteReader(); | 382 | { |
383 | if ((imported % 100) == 0) | ||
384 | { | ||
385 | MainConsole.Instance.Output(String.Format("{0} assets imported so far", imported)); | ||
386 | } | ||
375 | 387 | ||
376 | MainConsole.Instance.Output("Reading data"); | 388 | AssetBase asset = new AssetBase(); |
389 | AssetMetadata meta = new AssetMetadata(); | ||
377 | 390 | ||
378 | while (reader.Read()) | 391 | meta.ID = reader["id"].ToString(); |
379 | { | 392 | meta.FullID = new UUID(meta.ID); |
380 | if ((imported % 100) == 0) | ||
381 | { | ||
382 | MainConsole.Instance.Output(String.Format("{0} assets imported so far", imported)); | ||
383 | } | ||
384 | |||
385 | AssetBase asset = new AssetBase(); | ||
386 | AssetMetadata meta = new AssetMetadata(); | ||
387 | 393 | ||
388 | meta.ID = reader["id"].ToString(); | 394 | meta.Name = reader["name"].ToString(); |
389 | meta.FullID = new UUID(meta.ID); | 395 | meta.Description = reader["description"].ToString(); |
396 | meta.Type = (sbyte)Convert.ToInt32(reader["assetType"]); | ||
397 | meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type); | ||
398 | meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"])); | ||
390 | 399 | ||
391 | meta.Name = reader["name"].ToString(); | 400 | asset.Metadata = meta; |
392 | meta.Description = reader["description"].ToString(); | 401 | asset.Data = (byte[])reader["data"]; |
393 | meta.Type = (sbyte)Convert.ToInt32(reader["assetType"]); | ||
394 | meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type); | ||
395 | meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"])); | ||
396 | 402 | ||
397 | asset.Metadata = meta; | 403 | store(asset, force); |
398 | asset.Data = (byte[])reader["data"]; | ||
399 | 404 | ||
400 | store(asset, force); | 405 | imported++; |
406 | } | ||
407 | } | ||
401 | 408 | ||
402 | imported++; | 409 | } |
403 | } | 410 | } |
404 | 411 | ||
405 | reader.Close(); | ||
406 | cmd.Dispose(); | ||
407 | importConn.Close(); | ||
408 | |||
409 | MainConsole.Instance.Output(String.Format("Import done, {0} assets imported", imported)); | 412 | MainConsole.Instance.Output(String.Format("Import done, {0} assets imported", imported)); |
410 | } | 413 | } |
411 | 414 | ||
diff --git a/OpenSim/Services/FSAssetService/FSAssetService.cs b/OpenSim/Services/FSAssetService/FSAssetService.cs index 1bab687..bf7ddff 100644 --- a/OpenSim/Services/FSAssetService/FSAssetService.cs +++ b/OpenSim/Services/FSAssetService/FSAssetService.cs | |||
@@ -119,8 +119,8 @@ namespace OpenSim.Services.FSAssetService | |||
119 | 119 | ||
120 | // Get Database Connector from Asset Config (If present) | 120 | // Get Database Connector from Asset Config (If present) |
121 | string dllName = assetConfig.GetString("StorageProvider", string.Empty); | 121 | string dllName = assetConfig.GetString("StorageProvider", string.Empty); |
122 | string m_ConnectionString = assetConfig.GetString("ConnectionString", string.Empty); | 122 | string connectionString = assetConfig.GetString("ConnectionString", string.Empty); |
123 | string m_Realm = assetConfig.GetString("Realm", "fsassets"); | 123 | string realm = assetConfig.GetString("Realm", "fsassets"); |
124 | 124 | ||
125 | int SkipAccessTimeDays = assetConfig.GetInt("DaysBetweenAccessTimeUpdates", 0); | 125 | int SkipAccessTimeDays = assetConfig.GetInt("DaysBetweenAccessTimeUpdates", 0); |
126 | 126 | ||
@@ -132,15 +132,15 @@ namespace OpenSim.Services.FSAssetService | |||
132 | if (dllName == String.Empty) | 132 | if (dllName == String.Empty) |
133 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | 133 | dllName = dbConfig.GetString("StorageProvider", String.Empty); |
134 | 134 | ||
135 | if (m_ConnectionString == String.Empty) | 135 | if (connectionString == String.Empty) |
136 | m_ConnectionString = dbConfig.GetString("ConnectionString", String.Empty); | 136 | connectionString = dbConfig.GetString("ConnectionString", String.Empty); |
137 | } | 137 | } |
138 | 138 | ||
139 | // No databse connection found in either config | 139 | // No databse connection found in either config |
140 | if (dllName.Equals(String.Empty)) | 140 | if (dllName.Equals(String.Empty)) |
141 | throw new Exception("No StorageProvider configured"); | 141 | throw new Exception("No StorageProvider configured"); |
142 | 142 | ||
143 | if (m_ConnectionString.Equals(String.Empty)) | 143 | if (connectionString.Equals(String.Empty)) |
144 | throw new Exception("Missing database connection string"); | 144 | throw new Exception("Missing database connection string"); |
145 | 145 | ||
146 | // Create Storage Provider | 146 | // Create Storage Provider |
@@ -150,7 +150,7 @@ namespace OpenSim.Services.FSAssetService | |||
150 | throw new Exception(string.Format("Could not find a storage interface in the module {0}", dllName)); | 150 | throw new Exception(string.Format("Could not find a storage interface in the module {0}", dllName)); |
151 | 151 | ||
152 | // Initialize DB And perform any migrations required | 152 | // Initialize DB And perform any migrations required |
153 | m_DataConnector.Initialise(m_ConnectionString, m_Realm, SkipAccessTimeDays); | 153 | m_DataConnector.Initialise(connectionString, realm, SkipAccessTimeDays); |
154 | 154 | ||
155 | // Setup Fallback Service | 155 | // Setup Fallback Service |
156 | string str = assetConfig.GetString("FallbackService", string.Empty); | 156 | string str = assetConfig.GetString("FallbackService", string.Empty); |
@@ -232,7 +232,7 @@ namespace OpenSim.Services.FSAssetService | |||
232 | 232 | ||
233 | private void Writer() | 233 | private void Writer() |
234 | { | 234 | { |
235 | m_log.Info("[FSASSETS]: Writer started"); | 235 | m_log.Info("[ASSET]: Writer started"); |
236 | 236 | ||
237 | while (true) | 237 | while (true) |
238 | { | 238 | { |
@@ -246,33 +246,98 @@ namespace OpenSim.Services.FSAssetService | |||
246 | string hash = Path.GetFileNameWithoutExtension(files[i]); | 246 | string hash = Path.GetFileNameWithoutExtension(files[i]); |
247 | string s = HashToFile(hash); | 247 | string s = HashToFile(hash); |
248 | string diskFile = Path.Combine(m_FSBase, s); | 248 | string diskFile = Path.Combine(m_FSBase, s); |
249 | bool pathOk = false; | ||
249 | 250 | ||
250 | Directory.CreateDirectory(Path.GetDirectoryName(diskFile)); | 251 | // The cure for chicken bones! |
251 | try | 252 | while(true) |
252 | { | 253 | { |
253 | byte[] data = File.ReadAllBytes(files[i]); | 254 | try |
254 | |||
255 | using (GZipStream gz = new GZipStream(new FileStream(diskFile + ".gz", FileMode.Create), CompressionMode.Compress)) | ||
256 | { | 255 | { |
257 | gz.Write(data, 0, data.Length); | 256 | // Try to make the directory we need for this file |
258 | gz.Close(); | 257 | Directory.CreateDirectory(Path.GetDirectoryName(diskFile)); |
258 | pathOk = true; | ||
259 | break; | ||
259 | } | 260 | } |
260 | File.Delete(files[i]); | 261 | catch (System.IO.IOException) |
261 | 262 | { | |
262 | //File.Move(files[i], diskFile); | 263 | // Creating the directory failed. This can't happen unless |
264 | // a part of the path already exists as a file. Sadly the | ||
265 | // SRAS data contains such files. | ||
266 | string d = Path.GetDirectoryName(diskFile); | ||
267 | |||
268 | // Test each path component in turn. If we can successfully | ||
269 | // make a directory, the level below must be the chicken bone. | ||
270 | while (d.Length > 0) | ||
271 | { | ||
272 | Console.WriteLine(d); | ||
273 | try | ||
274 | { | ||
275 | Directory.CreateDirectory(Path.GetDirectoryName(d)); | ||
276 | } | ||
277 | catch (System.IO.IOException) | ||
278 | { | ||
279 | d = Path.GetDirectoryName(d); | ||
280 | |||
281 | // We failed making the directory and need to | ||
282 | // go up a bit more | ||
283 | continue; | ||
284 | } | ||
285 | |||
286 | // We succeeded in making the directory and (d) is | ||
287 | // the chicken bone | ||
288 | break; | ||
289 | } | ||
290 | |||
291 | // Is the chicken alive? | ||
292 | if (d.Length > 0) | ||
293 | { | ||
294 | Console.WriteLine(d); | ||
295 | |||
296 | FileAttributes attr = File.GetAttributes(d); | ||
297 | |||
298 | if ((attr & FileAttributes.Directory) == 0) | ||
299 | { | ||
300 | // The chicken bone should be resolved. | ||
301 | // Return to writing the file. | ||
302 | File.Delete(d); | ||
303 | continue; | ||
304 | } | ||
305 | } | ||
306 | } | ||
307 | // Could not resolve, skipping | ||
308 | m_log.ErrorFormat("[ASSET]: Could not resolve path creation error for {0}", diskFile); | ||
309 | break; | ||
263 | } | 310 | } |
264 | catch(System.IO.IOException e) | 311 | |
312 | if (pathOk) | ||
265 | { | 313 | { |
266 | if (e.Message.StartsWith("Win32 IO returned ERROR_ALREADY_EXISTS")) | 314 | try |
315 | { | ||
316 | byte[] data = File.ReadAllBytes(files[i]); | ||
317 | |||
318 | using (GZipStream gz = new GZipStream(new FileStream(diskFile + ".gz", FileMode.Create), CompressionMode.Compress)) | ||
319 | { | ||
320 | gz.Write(data, 0, data.Length); | ||
321 | gz.Close(); | ||
322 | } | ||
267 | File.Delete(files[i]); | 323 | File.Delete(files[i]); |
268 | else | 324 | |
269 | throw; | 325 | //File.Move(files[i], diskFile); |
326 | } | ||
327 | catch(System.IO.IOException e) | ||
328 | { | ||
329 | if (e.Message.StartsWith("Win32 IO returned ERROR_ALREADY_EXISTS")) | ||
330 | File.Delete(files[i]); | ||
331 | else | ||
332 | throw; | ||
333 | } | ||
270 | } | 334 | } |
271 | } | 335 | } |
336 | |||
272 | int totalTicks = System.Environment.TickCount - tickCount; | 337 | int totalTicks = System.Environment.TickCount - tickCount; |
273 | if (totalTicks > 0) // Wrap? | 338 | if (totalTicks > 0) // Wrap? |
274 | { | 339 | { |
275 | m_log.InfoFormat("[FSASSETS]: Write cycle complete, {0} files, {1} ticks, avg {2:F2}", files.Length, totalTicks, (double)totalTicks / (double)files.Length); | 340 | m_log.InfoFormat("[ASSET]: Write cycle complete, {0} files, {1} ticks, avg {2:F2}", files.Length, totalTicks, (double)totalTicks / (double)files.Length); |
276 | } | 341 | } |
277 | } | 342 | } |
278 | 343 | ||
@@ -292,20 +357,25 @@ namespace OpenSim.Services.FSAssetService | |||
292 | if (hash == null || hash.Length < 10) | 357 | if (hash == null || hash.Length < 10) |
293 | return "junkyard"; | 358 | return "junkyard"; |
294 | 359 | ||
360 | /* | ||
361 | * The code below is the OSGrid code. | ||
362 | * This should probably become a config option. | ||
363 | */ | ||
364 | /* | ||
295 | return Path.Combine(hash.Substring(0, 3), | 365 | return Path.Combine(hash.Substring(0, 3), |
296 | Path.Combine(hash.Substring(3, 3))); | 366 | Path.Combine(hash.Substring(3, 3))); |
367 | */ | ||
368 | |||
297 | /* | 369 | /* |
298 | * The below is what core would normally use. | 370 | * The below is what core would normally use. |
299 | * This is modified to work in OSGrid, as seen | 371 | * This is modified to work in OSGrid, as seen |
300 | * above, because the SRAS data is structured | 372 | * above, because the SRAS data is structured |
301 | * that way. | 373 | * that way. |
302 | */ | 374 | */ |
303 | /* | ||
304 | return Path.Combine(hash.Substring(0, 2), | 375 | return Path.Combine(hash.Substring(0, 2), |
305 | Path.Combine(hash.Substring(2, 2), | 376 | Path.Combine(hash.Substring(2, 2), |
306 | Path.Combine(hash.Substring(4, 2), | 377 | Path.Combine(hash.Substring(4, 2), |
307 | hash.Substring(6, 4)))); | 378 | hash.Substring(6, 4)))); |
308 | */ | ||
309 | } | 379 | } |
310 | 380 | ||
311 | private bool AssetExists(string hash) | 381 | private bool AssetExists(string hash) |