// // Copyright (c) ZeroC, Inc. All rights reserved. // namespace IceInternal { using System.Collections.Generic; using System.Diagnostics; public class RetryTask : TimerTask, CancellationHandler { public RetryTask(Instance instance, RetryQueue retryQueue, ProxyOutgoingAsyncBase outAsync) { _instance = instance; _retryQueue = retryQueue; _outAsync = outAsync; } public void runTimerTask() { _outAsync.retry(); // // NOTE: this must be called last, destroy() blocks until all task // are removed to prevent the client thread pool to be destroyed // (we still need the client thread pool at this point to call // exception callbacks with CommunicatorDestroyedException). // _retryQueue.remove(this); } public void asyncRequestCanceled(OutgoingAsyncBase outAsync, Ice.LocalException ex) { Debug.Assert(_outAsync == outAsync); if(_retryQueue.cancel(this)) { if(_instance.traceLevels().retry >= 1) { _instance.initializationData().logger.trace(_instance.traceLevels().retryCat, string.Format("operation retry canceled\n{0}", ex)); } if(_outAsync.exception(ex)) { _outAsync.invokeExceptionAsync(); } } } public void destroy() { try { _outAsync.abort(new Ice.CommunicatorDestroyedException()); } catch(Ice.CommunicatorDestroyedException) { // Abort can throw if there's no callback, just ignore in this case } } private Instance _instance; private RetryQueue _retryQueue; private ProxyOutgoingAsyncBase _outAsync; } public class RetryQueue { public RetryQueue(Instance instance) { _instance = instance; } public void add(ProxyOutgoingAsyncBase outAsync, int interval) { lock(this) { if(_instance == null) { throw new Ice.CommunicatorDestroyedException(); } RetryTask task = new RetryTask(_instance, this, outAsync); outAsync.cancelable(task); // This will throw if the request is canceled. _instance.timer().schedule(task, interval); _requests.Add(task, null); } } public void destroy() { lock(this) { Dictionary keep = new Dictionary(); foreach(RetryTask task in _requests.Keys) { if(_instance.timer().cancel(task)) { task.destroy(); } else { keep.Add(task, null); } } _requests = keep; _instance = null; while(_requests.Count > 0) { System.Threading.Monitor.Wait(this); } } } public void remove(RetryTask task) { lock(this) { if(_requests.Remove(task)) { if(_instance == null && _requests.Count == 0) { // If we are destroying the queue, destroy is probably waiting on the queue to be empty. System.Threading.Monitor.Pulse(this); } } } } public bool cancel(RetryTask task) { lock(this) { if(_requests.Remove(task)) { if(_instance != null) { return _instance.timer().cancel(task); } else if(_requests.Count == 0) { // If we are destroying the queue, destroy is probably waiting on the queue to be empty. System.Threading.Monitor.Pulse(this); } } return false; } } private Instance _instance; private Dictionary _requests = new Dictionary(); } }