blob: 5bafc6014d26a2ffcc80b377c8a2ddc3f53bcaef [file] [log] [blame]
/*
* 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.Collections;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
namespace Apache.Geode.DUnitFramework
{
public delegate object ClientResultAggregator(List<object> objList);
public class ClientGroup : ClientBase
{
#region Public accessors
public bool Managed
{
get
{
return m_managed;
}
set
{
m_managed = value;
}
}
public List<ClientBase> Clients
{
get
{
return m_clients;
}
}
#endregion
#region Public events
public event UnitFnMethod<ClientBase> ClientTaskStarted;
public event UnitFnMethod<ClientBase, Exception> ClientTaskDone;
#endregion
private List<ClientBase> m_clients;
private bool m_managed;
private ClientResultAggregator m_aggregator;
private const int ClientWaitLoopMillis = 100;
public ClientGroup(bool managed)
{
m_clients = new List<ClientBase>();
m_managed = managed;
m_aggregator = null;
}
public static ClientGroup Create(bool managed)
{
return new ClientGroup(managed);
}
public static ClientGroup Create(
UnitFnMethodR<ClientBase> clientCreateDeleg, int num)
{
ClientGroup group = new ClientGroup(true);
group.AddP(clientCreateDeleg, null, num);
return group;
}
public void Add(params ClientBase[] clients)
{
if (clients != null)
{
foreach (ClientBase client in clients)
{
m_clients.Add(client);
}
}
}
public void Add(List<ClientBase> clients)
{
if (clients != null)
{
m_clients.AddRange(clients);
}
}
public void Add(UnitFnMethodR<ClientBase> clientCreateDeleg, int num)
{
AddP(clientCreateDeleg, null, num);
}
public void Add<T1>(UnitFnMethodR<ClientBase, T1> clientCreateDeleg,
int num, T1 param1)
{
AddP(clientCreateDeleg, new object[] { param1 }, num);
}
public void Add<T1, T2>(UnitFnMethodR<ClientBase, T1, T2> clientCreateDeleg,
int num, T1 param1, T2 param2)
{
AddP(clientCreateDeleg, new object[] { param1, param2 }, num);
}
public void Add<T1, T2, T3>(UnitFnMethodR<ClientBase, T1, T2, T3> clientCreateDeleg,
int num, T1 param1, T2 param2, T3 param3)
{
AddP(clientCreateDeleg, new object[] { param1, param2, param3 }, num);
}
public void Add<T1, T2, T3, T4>(UnitFnMethodR<ClientBase, T1, T2, T3, T4> clientCreateDeleg,
int num, T1 param1, T2 param2, T3 param3, T4 param4)
{
AddP(clientCreateDeleg,
new object[] { param1, param2, param3, param4 }, num);
}
public void Add<T1, T2, T3, T4, T5>(UnitFnMethodR<ClientBase, T1, T2, T3, T4, T5> clientCreateDeleg,
int num, T1 param1, T2 param2, T3 param3, T4 param4, T5 param5)
{
AddP(clientCreateDeleg,
new object[] { param1, param2, param3, param4, param5 }, num);
}
public void AddTaskHandlers(UnitFnMethod<ClientBase> taskStartedHandler,
UnitFnMethod<ClientBase, Exception> taskDoneHandler)
{
ClientTaskStarted += taskStartedHandler;
ClientTaskDone += taskDoneHandler;
}
public void RemoveTaskHandlers(UnitFnMethod<ClientBase> taskStartedHandler,
UnitFnMethod<ClientBase, Exception> taskDoneHandler)
{
ClientTaskStarted -= taskStartedHandler;
ClientTaskDone -= taskDoneHandler;
}
public void SetAggregator(ClientResultAggregator aggregator)
{
m_aggregator = aggregator;
}
#region Private methods
private void AddP(Delegate clientCreateDeleg, object[] paramList, int num)
{
lock (((ICollection)m_clients).SyncRoot)
{
for (int i = 1; i <= num; i++)
{
m_clients.Add(
(ClientBase)clientCreateDeleg.DynamicInvoke(paramList));
}
}
}
#endregion
#region ClientBase Members
public override string ID
{
get
{
string baseId = base.ID;
if (baseId != null && baseId.Length > 0) {
return baseId;
}
StringBuilder sb = new StringBuilder();
foreach (ClientBase client in m_clients) {
if (sb.Length > 0) {
sb.Append(',');
}
sb.Append(client.ID);
}
return sb.ToString();
}
set
{
base.ID = value;
}
}
public override void RemoveObjectID(int objectID)
{
foreach (ClientBase client in m_clients)
{
client.RemoveObjectID(objectID);
}
}
public override void CallFn(Delegate deleg, object[] paramList)
{
if (m_clients.Count > 1)
{
UnitFnMethod<Delegate, object[]> invokeDeleg;
IAsyncResult asyncResult;
List<IAsyncResult> invokeList = new List<IAsyncResult>();
List<UnitFnMethod<Delegate, object[]>> invokeDelegList =
new List<UnitFnMethod<Delegate, object[]>>();
foreach (ClientBase client in m_clients)
{
invokeDeleg = client.CallFn;
asyncResult = invokeDeleg.BeginInvoke(deleg, paramList, null, null);
client.IncrementTasksRunning();
if (ClientTaskStarted != null)
{
ClientTaskStarted.Invoke(client);
}
invokeDelegList.Add(invokeDeleg);
invokeList.Add(asyncResult);
}
bool clientsRunning = true;
Dictionary<ClientBase, bool> doneTasks =
new Dictionary<ClientBase, bool>();
while (clientsRunning)
{
clientsRunning = false;
for (int i = 0; i < m_clients.Count; i++)
{
ClientBase client = m_clients[i];
if (!doneTasks.ContainsKey(client))
{
clientsRunning = true;
invokeDeleg = invokeDelegList[i];
asyncResult = invokeList[i];
try
{
if (asyncResult.AsyncWaitHandle.WaitOne(
ClientWaitLoopMillis, false))
{
doneTasks.Add(client, true);
client.DecrementTasksRunning();
invokeDeleg.EndInvoke(asyncResult);
if (ClientTaskDone != null)
{
ClientTaskDone.Invoke(client, null);
}
}
}
catch (Exception ex)
{
if (ClientTaskDone != null)
{
ClientTaskDone.Invoke(client, ex);
}
}
}
}
}
}
else if (m_clients.Count == 1)
{
ClientBase client = m_clients[0];
try
{
client.IncrementTasksRunning();
if (ClientTaskStarted != null)
{
ClientTaskStarted.Invoke(client);
}
client.CallFn(deleg, paramList);
if (ClientTaskDone != null)
{
ClientTaskDone.Invoke(client, null);
}
}
catch (Exception ex)
{
if (ClientTaskDone != null)
{
ClientTaskDone.Invoke(client, ex);
}
}
client.DecrementTasksRunning();
}
}
public override object CallFnR(Delegate deleg, object[] paramList)
{
List<object> resultList = new List<object>();
if (m_clients.Count > 1)
{
UnitFnMethodR<object, Delegate, object[]> invokeDeleg;
IAsyncResult asyncResult;
List<IAsyncResult> invokeList = new List<IAsyncResult>();
List<UnitFnMethodR<object, Delegate, object[]>> invokeDelegList =
new List<UnitFnMethodR<object, Delegate, object[]>>();
foreach (ClientBase client in m_clients)
{
invokeDeleg = client.CallFnR;
asyncResult = invokeDeleg.BeginInvoke(deleg, paramList, null, null);
client.IncrementTasksRunning();
if (ClientTaskStarted != null)
{
ClientTaskStarted.Invoke(client);
}
invokeDelegList.Add(invokeDeleg);
invokeList.Add(asyncResult);
}
bool clientsRunning = true;
Dictionary<ClientBase, bool> doneTasks =
new Dictionary<ClientBase, bool>();
while (clientsRunning)
{
clientsRunning = false;
for (int i = 0; i < m_clients.Count; i++)
{
ClientBase client = m_clients[i];
if (!doneTasks.ContainsKey(client))
{
clientsRunning = true;
invokeDeleg = invokeDelegList[i];
asyncResult = invokeList[i];
try
{
if (asyncResult.AsyncWaitHandle.WaitOne(
ClientWaitLoopMillis, false))
{
doneTasks.Add(client, true);
client.DecrementTasksRunning();
resultList.Add(invokeDeleg.EndInvoke(asyncResult));
if (ClientTaskDone != null)
{
ClientTaskDone.Invoke(client, null);
}
}
}
catch (Exception ex)
{
if (ClientTaskDone != null)
{
ClientTaskDone.Invoke(client, ex);
}
}
}
}
}
}
else if (m_clients.Count == 1)
{
ClientBase client = m_clients[0];
try
{
client.IncrementTasksRunning();
if (ClientTaskStarted != null)
{
ClientTaskStarted.Invoke(client);
}
resultList.Add(client.CallFnR(deleg, paramList));
if (ClientTaskDone != null)
{
ClientTaskDone.Invoke(client, null);
}
}
catch (Exception ex)
{
if (ClientTaskDone != null)
{
ClientTaskDone.Invoke(client, ex);
}
}
client.DecrementTasksRunning();
}
if (m_aggregator != null)
{
return m_aggregator(resultList);
}
else
{
return resultList[0];
}
}
public override string HostName
{
get
{
return "localhost";
}
}
public override void SetLogFile(string logPath)
{
foreach (ClientBase client in m_clients)
{
client.SetLogFile(logPath);
}
}
public override void SetLogLevel(Util.LogLevel logLevel)
{
foreach (ClientBase client in m_clients)
{
client.SetLogLevel(logLevel);
}
}
/// <summary>
/// Dump the stack trace for all the clients that are stuck
/// i.e. a CallFn/CallFnR is executing on them.
/// To get the dump of all the clients use <see cref="DumpStackTraceAll"/>.
/// </summary>
public override void DumpStackTrace()
{
foreach (ClientBase client in m_clients)
{
if (!TaskRunning || client.TaskRunning)
{
client.DumpStackTrace();
}
}
}
public override void ForceKill(int waitMillis)
{
lock (((ICollection)m_clients).SyncRoot)
{
if (waitMillis > 0)
{
UnitFnMethod<int> timeoutDeleg;
IAsyncResult asyncResult;
List<IAsyncResult> timeoutList = new List<IAsyncResult>();
List<UnitFnMethod<int>> timeoutDelegList =
new List<UnitFnMethod<int>>();
foreach (ClientBase client in m_clients)
{
timeoutDeleg = client.ForceKill;
asyncResult = timeoutDeleg.BeginInvoke(waitMillis, null, null);
timeoutDelegList.Add(timeoutDeleg);
timeoutList.Add(asyncResult);
}
for (int i = 0; i < m_clients.Count; i++)
{
timeoutDeleg = timeoutDelegList[i];
asyncResult = timeoutList[i];
try
{
asyncResult.AsyncWaitHandle.WaitOne();
timeoutDeleg.EndInvoke(asyncResult);
}
catch (Exception)
{
// Some exception in invoking the kill -- just ignore.
}
}
}
else
{
foreach (ClientBase client in m_clients)
{
client.ForceKill(0);
}
}
}
}
public override ClientBase CreateNew(string clientId)
{
ClientGroup newGroup = new ClientGroup(true);
foreach (ClientBase client in m_clients)
{
newGroup.m_clients.Add(client.CreateNew(clientId));
}
return newGroup;
}
public override void TestCleanup()
{
lock (((ICollection)m_clients).SyncRoot)
{
if (m_managed)
{
foreach (ClientBase client in m_clients)
{
client.TestCleanup();
}
}
}
}
public override void Exit()
{
lock (((ICollection)m_clients).SyncRoot)
{
if (m_managed)
{
foreach (ClientBase client in m_clients)
{
client.Exit();
}
}
m_clients.Clear();
}
}
#endregion
/// <summary>
/// Dump stack trace for all the clients;
/// the <see cref="DumpStackTrace"/> function only dumps the stacks for
/// clients that are stuck.
/// </summary>
public void DumpStackTraceAll()
{
foreach (ClientBase client in m_clients)
{
client.DumpStackTrace();
}
}
/// <summary>
/// Sets the log file name with client name appended to each file.
/// </summary>
/// <param name="logPath">
/// The path of the log file.
/// The actual log file name shall be of the form {logPath}_{ClientId}.log
/// </param>
public void SetNameLogFile(string logPath)
{
foreach (ClientBase client in m_clients)
{
client.SetLogFile(logPath + '_' + client.ID + ".log");
}
}
}
}