aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim
diff options
context:
space:
mode:
authorMelanie Thielker2016-03-05 01:17:42 +0100
committerMelanie Thielker2016-03-05 01:17:42 +0100
commit74c2113bcedb3c55a509b506b15d6ec46607a34e (patch)
tree337a9e3999eefc58c8c5824750afdb57ee43f36f /OpenSim
parentMantis 7833: Fix a condition where email sent from an object that is in (diff)
downloadopensim-SC-74c2113bcedb3c55a509b506b15d6ec46607a34e.zip
opensim-SC-74c2113bcedb3c55a509b506b15d6ec46607a34e.tar.gz
opensim-SC-74c2113bcedb3c55a509b506b15d6ec46607a34e.tar.bz2
opensim-SC-74c2113bcedb3c55a509b506b15d6ec46607a34e.tar.xz
Port the safer database access and the cure for "Chicken Bones" which
are artefacts that can be created by fsck and would make standard FSAssets choke. These refinements were tested on OSGrid.
Diffstat (limited to '')
-rw-r--r--OpenSim/Data/MySQL/MySQLFSAssetData.cs379
-rw-r--r--OpenSim/Services/FSAssetService/FSAssetService.cs118
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)