Former-commit-id:a02aeb236c
[formerly9f19e3f712
] [formerly06a8b51d6d
[formerly 64fa9254b946eae7e61bbc3f513b7c3696c4f54f]] Former-commit-id:06a8b51d6d
Former-commit-id:3360eb6c5f
315 lines
8.8 KiB
C#
315 lines
8.8 KiB
C#
/*
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*
|
|
*/
|
|
using System;
|
|
using System.Text;
|
|
using log4net;
|
|
using Apache.Qpid.Client.Qms.Failover;
|
|
|
|
namespace Apache.Qpid.Client.Qms
|
|
{
|
|
public class FailoverPolicy
|
|
{
|
|
private static readonly ILog _logger = LogManager.GetLogger(typeof(FailoverPolicy));
|
|
|
|
private const long MINUTE = 60000L;
|
|
|
|
private const long DEFAULT_METHOD_TIMEOUT = 1 * MINUTE;
|
|
private const long DEFAULT_FAILOVER_TIMEOUT = 4 * MINUTE;
|
|
|
|
private IFailoverMethod[] _methods = new IFailoverMethod[1];
|
|
|
|
private int _currentMethod;
|
|
|
|
private int _methodsRetries;
|
|
|
|
private int _currentRetry;
|
|
|
|
private bool _timing;
|
|
|
|
private long _lastMethodTime;
|
|
private long _lastFailTime;
|
|
|
|
public FailoverPolicy(IConnectionInfo connectionInfo)
|
|
{
|
|
IFailoverMethod method;
|
|
|
|
//todo This should be integrated in to the connection url when it supports
|
|
// multiple strategies.
|
|
|
|
_methodsRetries = 0;
|
|
|
|
if (connectionInfo.FailoverMethod == null)
|
|
{
|
|
if (connectionInfo.BrokerCount > 1)
|
|
{
|
|
method = new FailoverRoundRobin(connectionInfo);
|
|
}
|
|
else
|
|
{
|
|
method = new FailoverSingleServer(connectionInfo);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
string failoverMethod = connectionInfo.FailoverMethod;
|
|
|
|
/*
|
|
if (failoverMethod.equals(FailoverMethod.RANDOM))
|
|
{
|
|
//todo write a random connection Failover
|
|
}
|
|
*/
|
|
if (failoverMethod.Equals(FailoverMethodConstants.ROUND_ROBIN))
|
|
{
|
|
method = new FailoverRoundRobin(connectionInfo);
|
|
}
|
|
else
|
|
{
|
|
throw new NotImplementedException("Dynamic loading of FailoverMethods not yet implemented.");
|
|
// try
|
|
// {
|
|
// Type[] constructorSpec = {ConnectionInfo.class};
|
|
// Object [] params = {connectionInfo};
|
|
//
|
|
// method = (FailoverMethod) ClassLoader.getSystemClassLoader().
|
|
// loadClass(failoverMethod).
|
|
// getConstructor(constructorSpec).newInstance(params);
|
|
// }
|
|
// catch (Exception cnfe)
|
|
// {
|
|
// throw new IllegalArgumentException("Unknown failover method:" + failoverMethod);
|
|
// }
|
|
}
|
|
}
|
|
|
|
if (method == null)
|
|
{
|
|
throw new ArgumentException("Unknown failover method specified.");
|
|
}
|
|
|
|
reset();
|
|
|
|
_methods[_currentMethod] = method;
|
|
}
|
|
|
|
public FailoverPolicy(IFailoverMethod method) : this(method, 0)
|
|
{
|
|
}
|
|
|
|
public FailoverPolicy(IFailoverMethod method, int retries)
|
|
{
|
|
_methodsRetries = retries;
|
|
|
|
reset();
|
|
|
|
_methods[_currentMethod] = method;
|
|
}
|
|
|
|
private void reset()
|
|
{
|
|
_currentMethod = 0;
|
|
_currentRetry = 0;
|
|
_timing = false;
|
|
|
|
}
|
|
|
|
public bool FailoverAllowed()
|
|
{
|
|
bool failoverAllowed;
|
|
|
|
if (_timing)
|
|
{
|
|
long now = CurrentTimeMilliseconds();
|
|
|
|
if ((now - _lastMethodTime) >= DEFAULT_METHOD_TIMEOUT)
|
|
{
|
|
_logger.Info("Failover method timeout");
|
|
_lastMethodTime = now;
|
|
|
|
if (!nextMethod())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
|
|
}
|
|
else if ((now - _lastFailTime) >= DEFAULT_FAILOVER_TIMEOUT)
|
|
{
|
|
_logger.Info("Failover timeout");
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
_lastMethodTime = now;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
_timing = true;
|
|
_lastMethodTime = CurrentTimeMilliseconds();
|
|
_lastFailTime = _lastMethodTime;
|
|
}
|
|
|
|
|
|
if (_methods[_currentMethod].FailoverAllowed())
|
|
{
|
|
failoverAllowed = true;
|
|
}
|
|
else
|
|
{
|
|
if (_currentMethod < (_methods.Length - 1))
|
|
{
|
|
nextMethod();
|
|
_logger.Info("Changing method to " + _methods[_currentMethod].MethodName);
|
|
return FailoverAllowed();
|
|
}
|
|
else
|
|
{
|
|
return cycleMethods();
|
|
}
|
|
}
|
|
|
|
return failoverAllowed;
|
|
}
|
|
|
|
private static long CurrentTimeMilliseconds()
|
|
{
|
|
return DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
|
|
}
|
|
|
|
private bool nextMethod()
|
|
{
|
|
if (_currentMethod < (_methods.Length - 1))
|
|
{
|
|
_currentMethod++;
|
|
_methods[_currentMethod].Reset();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return cycleMethods();
|
|
}
|
|
}
|
|
|
|
private bool cycleMethods()
|
|
{
|
|
if (_currentRetry < _methodsRetries)
|
|
{
|
|
_currentRetry++;
|
|
|
|
_currentMethod = 0;
|
|
|
|
_logger.Info("Retrying methods starting with " + _methods[_currentMethod].MethodName);
|
|
_methods[_currentMethod].Reset();
|
|
return FailoverAllowed();
|
|
}
|
|
else
|
|
{
|
|
_logger.Debug("All failover methods exhausted");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Notification that connection was successful.
|
|
*/
|
|
public void attainedConnection()
|
|
{
|
|
_currentRetry = 0;
|
|
|
|
_methods[_currentMethod].AttainedConnection();
|
|
|
|
_timing = false;
|
|
}
|
|
|
|
public IBrokerInfo GetCurrentBrokerInfo()
|
|
{
|
|
return _methods[_currentMethod].GetCurrentBrokerInfo();
|
|
}
|
|
|
|
public IBrokerInfo GetNextBrokerInfo()
|
|
{
|
|
return _methods[_currentMethod].GetNextBrokerDetails();
|
|
}
|
|
|
|
public void setBroker(IBrokerInfo broker)
|
|
{
|
|
_methods[_currentMethod].SetBroker(broker);
|
|
}
|
|
|
|
public void addMethod(IFailoverMethod method)
|
|
{
|
|
int len = _methods.Length + 1;
|
|
IFailoverMethod[] newMethods = new IFailoverMethod[len];
|
|
_methods.CopyTo(newMethods, 0);
|
|
// System.arraycopy(_methods, 0, newMethods, 0, _methods.length);
|
|
int index = len - 1;
|
|
newMethods[index] = method;
|
|
_methods = newMethods;
|
|
}
|
|
|
|
public void setMethodRetries(int retries)
|
|
{
|
|
_methodsRetries = retries;
|
|
}
|
|
|
|
public IFailoverMethod getCurrentMethod()
|
|
{
|
|
if (_currentMethod >= 0 && _currentMethod < (_methods.Length - 1))
|
|
{
|
|
return _methods[_currentMethod];
|
|
}
|
|
else
|
|
{
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public String toString()
|
|
{
|
|
StringBuilder sb = new StringBuilder();
|
|
|
|
sb.Append("Failover Policy:\n");
|
|
|
|
if (FailoverAllowed())
|
|
{
|
|
sb.Append("Failover allowed\n");
|
|
}
|
|
else
|
|
{
|
|
sb.Append("Failover not allowed\n");
|
|
}
|
|
|
|
sb.Append("Failover policy methods\n");
|
|
for (int i = 0; i < _methods.Length; i++)
|
|
{
|
|
|
|
if (i == _currentMethod)
|
|
{
|
|
sb.Append(">");
|
|
}
|
|
sb.Append(_methods[i].ToString());
|
|
}
|
|
|
|
return sb.ToString();
|
|
}
|
|
}
|
|
}
|