aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--OpenSim/Data/Tests/AssetTests.cs18
-rw-r--r--OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs206
2 files changed, 128 insertions, 96 deletions
diff --git a/OpenSim/Data/Tests/AssetTests.cs b/OpenSim/Data/Tests/AssetTests.cs
index 5982a09..5d7b169 100644
--- a/OpenSim/Data/Tests/AssetTests.cs
+++ b/OpenSim/Data/Tests/AssetTests.cs
@@ -125,20 +125,14 @@ namespace OpenSim.Data.Tests
125 m_db.StoreAsset(a1); 125 m_db.StoreAsset(a1);
126 m_db.StoreAsset(a2); 126 m_db.StoreAsset(a2);
127 m_db.StoreAsset(a3); 127 m_db.StoreAsset(a3);
128 a1.UploadAttempts = 0;
129 a2.UploadAttempts = 0;
130 a3.UploadAttempts = 0;
131 128
132 AssetBase a1a = m_db.GetAsset(uuid1); 129 AssetBase a1a = m_db.GetAsset(uuid1);
133 a1a.UploadAttempts = 0;
134 Assert.That(a1a, Constraints.PropertyCompareConstraint(a1)); 130 Assert.That(a1a, Constraints.PropertyCompareConstraint(a1));
135 131
136 AssetBase a2a = m_db.GetAsset(uuid2); 132 AssetBase a2a = m_db.GetAsset(uuid2);
137 a2a.UploadAttempts = 0;
138 Assert.That(a2a, Constraints.PropertyCompareConstraint(a2)); 133 Assert.That(a2a, Constraints.PropertyCompareConstraint(a2));
139 134
140 AssetBase a3a = m_db.GetAsset(uuid3); 135 AssetBase a3a = m_db.GetAsset(uuid3);
141 a3a.UploadAttempts = 0;
142 Assert.That(a3a, Constraints.PropertyCompareConstraint(a3)); 136 Assert.That(a3a, Constraints.PropertyCompareConstraint(a3));
143 137
144 scrambler.Scramble(a1a); 138 scrambler.Scramble(a1a);
@@ -148,20 +142,14 @@ namespace OpenSim.Data.Tests
148 m_db.StoreAsset(a1a); 142 m_db.StoreAsset(a1a);
149 m_db.StoreAsset(a2a); 143 m_db.StoreAsset(a2a);
150 m_db.StoreAsset(a3a); 144 m_db.StoreAsset(a3a);
151 a1a.UploadAttempts = 0;
152 a2a.UploadAttempts = 0;
153 a3a.UploadAttempts = 0;
154 145
155 AssetBase a1b = m_db.GetAsset(uuid1); 146 AssetBase a1b = m_db.GetAsset(uuid1);
156 a1b.UploadAttempts = 0;
157 Assert.That(a1b, Constraints.PropertyCompareConstraint(a1a)); 147 Assert.That(a1b, Constraints.PropertyCompareConstraint(a1a));
158 148
159 AssetBase a2b = m_db.GetAsset(uuid2); 149 AssetBase a2b = m_db.GetAsset(uuid2);
160 a2b.UploadAttempts = 0;
161 Assert.That(a2b, Constraints.PropertyCompareConstraint(a2a)); 150 Assert.That(a2b, Constraints.PropertyCompareConstraint(a2a));
162 151
163 AssetBase a3b = m_db.GetAsset(uuid3); 152 AssetBase a3b = m_db.GetAsset(uuid3);
164 a3b.UploadAttempts = 0;
165 Assert.That(a3b, Constraints.PropertyCompareConstraint(a3a)); 153 Assert.That(a3b, Constraints.PropertyCompareConstraint(a3a));
166 154
167 bool[] exist = m_db.AssetsExist(new[] { uuid1, uuid2, uuid3 }); 155 bool[] exist = m_db.AssetsExist(new[] { uuid1, uuid2, uuid3 });
@@ -202,22 +190,16 @@ namespace OpenSim.Data.Tests
202 a3.Data = data1; 190 a3.Data = data1;
203 191
204 m_db.StoreAsset(a1); 192 m_db.StoreAsset(a1);
205 a1.UploadAttempts = 0;
206 m_db.StoreAsset(a2); 193 m_db.StoreAsset(a2);
207 a2.UploadAttempts = 0;
208 m_db.StoreAsset(a3); 194 m_db.StoreAsset(a3);
209 a3.UploadAttempts = 0;
210 195
211 AssetBase a1a = m_db.GetAsset(uuid1); 196 AssetBase a1a = m_db.GetAsset(uuid1);
212 a1a.UploadAttempts = 0;
213 Assert.That(a1a, Constraints.PropertyCompareConstraint(a1)); 197 Assert.That(a1a, Constraints.PropertyCompareConstraint(a1));
214 198
215 AssetBase a2a = m_db.GetAsset(uuid2); 199 AssetBase a2a = m_db.GetAsset(uuid2);
216 a2a.UploadAttempts = 0;
217 Assert.That(a2a, Constraints.PropertyCompareConstraint(a2)); 200 Assert.That(a2a, Constraints.PropertyCompareConstraint(a2));
218 201
219 AssetBase a3a = m_db.GetAsset(uuid3); 202 AssetBase a3a = m_db.GetAsset(uuid3);
220 a3a.UploadAttempts = 0;
221 Assert.That(a3a, Constraints.PropertyCompareConstraint(a3)); 203 Assert.That(a3a, Constraints.PropertyCompareConstraint(a3));
222 } 204 }
223 } 205 }
diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs
index 7ac7917..5e86771 100644
--- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs
+++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs
@@ -46,10 +46,12 @@ namespace OpenSim.Services.Connectors
46 LogManager.GetLogger( 46 LogManager.GetLogger(
47 MethodBase.GetCurrentMethod().DeclaringType); 47 MethodBase.GetCurrentMethod().DeclaringType);
48 48
49// const int MAXSENDRETRIESLEN = 30;
50 const int MAXSENDRETRIESLEN = 2;
49 private string m_ServerURI = String.Empty; 51 private string m_ServerURI = String.Empty;
50 private IImprovedAssetCache m_Cache = null; 52 private IImprovedAssetCache m_Cache = null;
51 private int m_retryCounter; 53 private int m_retryCounter;
52 private Dictionary<int, List<AssetBase>> m_retryQueue = new Dictionary<int, List<AssetBase>>(); 54 private List<AssetBase>[] m_sendRetries = new List<AssetBase>[MAXSENDRETRIESLEN];
53 private System.Timers.Timer m_retryTimer; 55 private System.Timers.Timer m_retryTimer;
54 private int m_maxAssetRequestConcurrency = 30; 56 private int m_maxAssetRequestConcurrency = 30;
55 57
@@ -110,9 +112,9 @@ namespace OpenSim.Services.Connectors
110 throw new Exception("Asset connector init error"); 112 throw new Exception("Asset connector init error");
111 } 113 }
112 114
113
114 m_retryTimer = new System.Timers.Timer(); 115 m_retryTimer = new System.Timers.Timer();
115 m_retryTimer.Elapsed += new ElapsedEventHandler(retryCheck); 116 m_retryTimer.Elapsed += new ElapsedEventHandler(retryCheck);
117 m_retryTimer.AutoReset = false;
116 m_retryTimer.Interval = 60000; 118 m_retryTimer.Interval = 60000;
117 119
118 Uri serverUri = new Uri(m_ServerURI); 120 Uri serverUri = new Uri(m_ServerURI);
@@ -167,47 +169,57 @@ namespace OpenSim.Services.Connectors
167 protected void retryCheck(object source, ElapsedEventArgs e) 169 protected void retryCheck(object source, ElapsedEventArgs e)
168 { 170 {
169 m_retryCounter++; 171 m_retryCounter++;
170 if (m_retryCounter > 60) 172 if(m_retryCounter >= 61 ) // avoid overflow 60 is max in use below
171 m_retryCounter -= 60; 173 m_retryCounter = 1;
172 174
173 List<int> keys = new List<int>(); 175 int inUse = 0;
174 foreach (int a in m_retryQueue.Keys) 176 int nextlevel;
175 { 177 int timefactor;
176 keys.Add(a); 178 List<AssetBase> retrylist;
177 } 179 // we need to go down
178 foreach (int a in keys) 180 for(int i = MAXSENDRETRIESLEN - 1; i >= 0; i--)
179 { 181 {
182 lock(m_sendRetries)
183 retrylist = m_sendRetries[i];
184
185 if(retrylist == null)
186 continue;
187
188 inUse++;
189 nextlevel = i + 1;
190
180 //We exponentially fall back on frequency until we reach one attempt per hour 191 //We exponentially fall back on frequency until we reach one attempt per hour
181 //The net result is that we end up in the queue for roughly 24 hours.. 192 //The net result is that we end up in the queue for roughly 24 hours..
182 //24 hours worth of assets could be a lot, so the hope is that the region admin 193 //24 hours worth of assets could be a lot, so the hope is that the region admin
183 //will have gotten the asset connector back online quickly! 194 //will have gotten the asset connector back online quickly!
184 195 if(i == 0)
185 int timefactor = a ^ 2; 196 timefactor = 1;
186 if (timefactor > 60) 197 else
187 { 198 {
188 timefactor = 60; 199 timefactor = 1 << nextlevel;
200 if (timefactor > 60)
201 timefactor = 60;
189 } 202 }
190 203
191 //First, find out if we care about this timefactor 204 if(m_retryCounter < timefactor)
192 if (timefactor % a == 0) 205 continue; // to update inUse;
193 {
194 //Yes, we do!
195 List<AssetBase> retrylist = m_retryQueue[a];
196 m_retryQueue.Remove(a);
197 206
198 foreach(AssetBase ass in retrylist) 207 if (m_retryCounter % timefactor != 0)
199 { 208 continue;
200 Store(ass); //Store my ass. This function will put it back in the dictionary if it fails 209
201 } 210 // a list to retry
202 } 211 lock(m_sendRetries)
212 m_sendRetries[i] = null;
213
214 // we are the only ones with a copy of this retrylist now
215 foreach(AssetBase ass in retrylist)
216 retryStore(ass, nextlevel);
203 } 217 }
204 218
205 if (m_retryQueue.Count == 0) 219 lock(m_sendRetries)
206 { 220 {
207 //It might only be one tick per minute, but I have 221 if(inUse > 0 && !m_retryTimer.Enabled)
208 //repented and abandoned my wasteful ways 222 m_retryTimer.Start();
209 m_retryCounter = 0;
210 m_retryTimer.Stop();
211 } 223 }
212 } 224 }
213 225
@@ -237,8 +249,9 @@ namespace OpenSim.Services.Connectors
237 249
238 asset = SynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0, m_Auth); 250 asset = SynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0, m_Auth);
239 251
240 if (m_Cache != null) 252
241 m_Cache.Cache(asset); 253 if (asset != null && m_Cache != null)
254 m_Cache.Cache(asset);
242 } 255 }
243 return asset; 256 return asset;
244 } 257 }
@@ -340,25 +353,18 @@ namespace OpenSim.Services.Connectors
340 m_AssetHandlers.Remove(id); 353 m_AssetHandlers.Remove(id);
341 } 354 }
342 355
343 Util.FireAndForget(x => 356 if(handlers != null)
357 {
358 Util.FireAndForget(x =>
344 { 359 {
345
346 foreach (AssetRetrievedEx h in handlers) 360 foreach (AssetRetrievedEx h in handlers)
347 { 361 {
348 // Util.FireAndForget(x =>
349 // {
350 try { h.Invoke(a); } 362 try { h.Invoke(a); }
351 catch { } 363 catch { }
352 // });
353 } 364 }
354 365 handlers.Clear();
355 if (handlers != null)
356 handlers.Clear();
357
358 }); 366 });
359 367 }
360// if (handlers != null)
361// handlers.Clear();
362 success = true; 368 success = true;
363 } 369 }
364 } 370 }
@@ -393,29 +399,24 @@ namespace OpenSim.Services.Connectors
393 { 399 {
394 AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate(AssetBase _asset) { handler(id, sender, _asset); }); 400 AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate(AssetBase _asset) { handler(id, sender, _asset); });
395 401
396// AssetRetrievedEx handlers;
397 List<AssetRetrievedEx> handlers; 402 List<AssetRetrievedEx> handlers;
398 if (m_AssetHandlers.TryGetValue(id, out handlers)) 403 if (m_AssetHandlers.TryGetValue(id, out handlers))
399 { 404 {
400 // Someone else is already loading this asset. It will notify our handler when done. 405 // Someone else is already loading this asset. It will notify our handler when done.
401// handlers += handlerEx;
402 handlers.Add(handlerEx); 406 handlers.Add(handlerEx);
403 return true; 407 return true;
404 } 408 }
405 409
406 // Load the asset ourselves
407// handlers += handlerEx;
408 handlers = new List<AssetRetrievedEx>(); 410 handlers = new List<AssetRetrievedEx>();
409 handlers.Add(handlerEx); 411 handlers.Add(handlerEx);
410 412
411 m_AssetHandlers.Add(id, handlers); 413 m_AssetHandlers.Add(id, handlers);
412 }
413 414
414 QueuedAssetRequest request = new QueuedAssetRequest(); 415 QueuedAssetRequest request = new QueuedAssetRequest();
415 request.id = id; 416 request.id = id;
416 request.uri = uri; 417 request.uri = uri;
417 418 m_requestQueue.Enqueue(request);
418 m_requestQueue.Enqueue(request); 419 }
419 } 420 }
420 else 421 else
421 { 422 {
@@ -495,43 +496,35 @@ namespace OpenSim.Services.Connectors
495 newID = SynchronousRestObjectRequester. 496 newID = SynchronousRestObjectRequester.
496 MakeRequest<AssetBase, string>("POST", uri, asset, 100000, m_Auth); 497 MakeRequest<AssetBase, string>("POST", uri, asset, 100000, m_Auth);
497 } 498 }
498 catch {} 499 catch
500 {
501 newID = null;
502 }
499 503
500 if (newID == null || newID == String.Empty || newID == stringUUIDZero) 504 if (newID == null || newID == String.Empty || newID == stringUUIDZero)
501 { 505 {
502 //The asset upload failed, put it in a queue for later 506 //The asset upload failed, try later
503 asset.UploadAttempts++; 507 lock(m_sendRetries)
504 if (asset.UploadAttempts > 30)
505 {
506 //By this stage we've been in the queue for a good few hours;
507 //We're going to drop the asset.
508 m_log.ErrorFormat("[Assets] Dropping asset {0} - Upload has been in the queue for too long.", asset.ID.ToString());
509 }
510 else
511 { 508 {
512 if (!m_retryQueue.ContainsKey(asset.UploadAttempts)) 509 if (m_sendRetries[0] == null)
513 { 510 m_sendRetries[0] = new List<AssetBase>();
514 m_retryQueue.Add(asset.UploadAttempts, new List<AssetBase>()); 511 List<AssetBase> m_queue = m_sendRetries[0];
515 }
516 List<AssetBase> m_queue = m_retryQueue[asset.UploadAttempts];
517 m_queue.Add(asset); 512 m_queue.Add(asset);
518 m_log.WarnFormat("[Assets] Upload failed: {0} - Requeuing asset for another run.", asset.ID.ToString()); 513 m_log.WarnFormat("[Assets] Upload failed: {0} type {1} will retry later",
519 m_retryTimer.Start(); 514 asset.ID.ToString(), asset.Type.ToString());
515 if(!m_retryTimer.Enabled)
516 m_retryTimer.Start();
520 } 517 }
521 } 518 }
522 else 519 else
523 { 520 {
524 if (asset.UploadAttempts > 0)
525 {
526 m_log.InfoFormat("[Assets] Upload of {0} succeeded after {1} failed attempts", asset.ID.ToString(), asset.UploadAttempts.ToString());
527 }
528 if (newID != asset.ID) 521 if (newID != asset.ID)
529 { 522 {
530 // Placing this here, so that this work with old asset servers that don't send any reply back 523 // Placing this here, so that this work with old asset servers that don't send any reply back
531 // SynchronousRestObjectRequester returns somethins that is not an empty string 524 // SynchronousRestObjectRequester returns somethins that is not an empty string
532 525
533 asset.ID = newID; 526 asset.ID = newID;
534// what about FullID ???? 527
535 if (m_Cache != null) 528 if (m_Cache != null)
536 m_Cache.Cache(asset); 529 m_Cache.Cache(asset);
537 } 530 }
@@ -539,6 +532,62 @@ namespace OpenSim.Services.Connectors
539 return asset.ID; 532 return asset.ID;
540 } 533 }
541 534
535 public void retryStore(AssetBase asset, int nextRetryLevel)
536 {
537/* this may be bad, so excluding
538 if (m_Cache != null && !m_Cache.Check(asset.ID))
539 {
540 m_log.WarnFormat("[Assets] Upload giveup asset bc no longer in local cache: {0}",
541 asset.ID.ToString();
542 return; // if no longer in cache, it was deleted or expired
543 }
544*/
545 string uri = MapServer(asset.FullID.ToString()) + "/assets/";
546
547 string newID = null;
548 try
549 {
550 newID = SynchronousRestObjectRequester.
551 MakeRequest<AssetBase, string>("POST", uri, asset, 100000, m_Auth);
552 }
553 catch
554 {
555 newID = null;
556 }
557
558 if (newID == null || newID == String.Empty || newID == stringUUIDZero)
559 {
560 if(nextRetryLevel >= MAXSENDRETRIESLEN)
561 m_log.WarnFormat("[Assets] Upload giveup after several retries id: {0} type {1}",
562 asset.ID.ToString(), asset.Type.ToString());
563 else
564 {
565 lock(m_sendRetries)
566 {
567 if (m_sendRetries[nextRetryLevel] == null)
568 {
569 m_sendRetries[nextRetryLevel] = new List<AssetBase>();
570 }
571 List<AssetBase> m_queue = m_sendRetries[nextRetryLevel];
572 m_queue.Add(asset);
573 m_log.WarnFormat("[Assets] Upload failed: {0} type {1} will retry later",
574 asset.ID.ToString(), asset.Type.ToString());
575 }
576 }
577 }
578 else
579 {
580 m_log.InfoFormat("[Assets] Upload of {0} succeeded after {1} failed attempts", asset.ID.ToString(), nextRetryLevel.ToString());
581 if (newID != asset.ID)
582 {
583 asset.ID = newID;
584
585 if (m_Cache != null)
586 m_Cache.Cache(asset);
587 }
588 }
589 }
590
542 public bool UpdateContent(string id, byte[] data) 591 public bool UpdateContent(string id, byte[] data)
543 { 592 {
544 AssetBase asset = null; 593 AssetBase asset = null;
@@ -569,6 +618,7 @@ namespace OpenSim.Services.Connectors
569 return false; 618 return false;
570 } 619 }
571 620
621
572 public bool Delete(string id) 622 public bool Delete(string id)
573 { 623 {
574 string uri = MapServer(id) + "/assets/" + id; 624 string uri = MapServer(id) + "/assets/" + id;