| /* |
| * 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"); |
| } |
| } |
| } |
| } |