Skip to content
This repository was archived by the owner on Dec 24, 2022. It is now read-only.

Commit c03f10f

Browse files
committed
Add multi-threaded Stress Test example of Hash Collections
1 parent 7b219fd commit c03f10f

File tree

3 files changed

+299
-0
lines changed

3 files changed

+299
-0
lines changed

tests/Console.Tests/Console.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
<Reference Include="System.Xml" />
5757
</ItemGroup>
5858
<ItemGroup>
59+
<Compile Include="HashCollectionStressTests.cs" />
5960
<Compile Include="HashStressTest.cs" />
6061
<Compile Include="LongRunningRedisPubSubServer.cs" />
6162
<Compile Include="Program.cs" />
Lines changed: 297 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,297 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading;
5+
using ServiceStack.Redis;
6+
using ServiceStack.Redis.Generic;
7+
using ServiceStack.Text;
8+
9+
namespace TestRedisConnection
10+
{
11+
public class HashCollectionStressTests
12+
{
13+
private IRedisClientsManager clientsManager;
14+
private int running = 0;
15+
private long writeCount = 0;
16+
private long readCount = 0;
17+
18+
public void Execute(string ipAddress, int noOfThreads = 64)
19+
{
20+
clientsManager = new PooledRedisClientManager(ipAddress);
21+
22+
var StartedAt = DateTime.UtcNow;
23+
Interlocked.Increment(ref running);
24+
25+
"Starting HashCollectionStressTests with {0} threads".Print(noOfThreads);
26+
var threads = new List<Thread>();
27+
for (int i = 0; i < noOfThreads; i++)
28+
{
29+
threads.Add(new Thread(WorkerLoop));
30+
}
31+
threads.ForEach(t => t.Start());
32+
33+
"Press Enter to Stop...".Print();
34+
Console.ReadLine();
35+
36+
Interlocked.Decrement(ref running);
37+
38+
"Writes: {0}, Reads: {1}".Print(writeCount, readCount);
39+
"{0} EndedAt: {1}".Print(GetType().Name, DateTime.UtcNow.ToLongTimeString());
40+
"{0} TimeTaken: {1}s".Print(GetType().Name, (DateTime.UtcNow - StartedAt).TotalSeconds);
41+
42+
"\nPress Enter to Quit...".Print();
43+
Console.ReadLine();
44+
}
45+
46+
public void WorkerLoop()
47+
{
48+
while (Interlocked.CompareExchange(ref running, 0, 0) > 0)
49+
{
50+
var redisCollection = new RedisCachedCollection<string, string>(
51+
clientsManager, "Thread: " + Thread.CurrentThread.ManagedThreadId);
52+
53+
redisCollection.ContainsKey("key");
54+
Interlocked.Increment(ref readCount);
55+
56+
redisCollection["key"] = "value " + readCount;
57+
Interlocked.Increment(ref writeCount);
58+
59+
var value = redisCollection["key"];
60+
Interlocked.Increment(ref readCount);
61+
62+
if (value == null)
63+
Console.WriteLine("value == null");
64+
}
65+
}
66+
}
67+
68+
public class RedisCachedCollection<TKey, TValue> : IEnumerable<TValue>
69+
{
70+
private readonly string collectionKey;
71+
private Func<TValue, TKey> idAction;
72+
private readonly IRedisClientsManager clientsManager;
73+
74+
public RedisCachedCollection(IRedisClientsManager clientsManager, string collectionKey)
75+
{
76+
this.clientsManager = clientsManager;
77+
this.collectionKey = string.Format("urn:{0}:{1}", "XXXXX", collectionKey);
78+
}
79+
80+
public IRedisClient RedisConnection
81+
{
82+
get
83+
{
84+
return clientsManager.GetClient();
85+
}
86+
}
87+
88+
private IRedisHash<TKey, TValue> GetCollection(IRedisClient redis)
89+
{
90+
var _redisTypedClient = redis.As<TValue>();
91+
return _redisTypedClient.GetHash<TKey>(collectionKey);
92+
}
93+
94+
public void Add(TValue obj)
95+
{
96+
TKey Id = GetUniqueIdAction(obj);
97+
98+
RetryAction((redis) =>
99+
{
100+
GetCollection(redis).Add(Id, obj);
101+
});
102+
}
103+
104+
public bool Remove(TValue obj)
105+
{
106+
TKey Id = GetUniqueIdAction(obj);
107+
TKey defaultv = default(TKey);
108+
109+
return RetryAction<bool>((redis) =>
110+
{
111+
if (!Id.Equals(defaultv))
112+
{
113+
{
114+
return GetCollection(redis).Remove(Id);
115+
}
116+
}
117+
return false;
118+
});
119+
120+
}
121+
122+
public TValue this[TKey id]
123+
{
124+
get
125+
{
126+
return RetryAction<TValue>((redis) =>
127+
{
128+
if (GetCollection(redis).ContainsKey(id))
129+
return GetCollection(redis)[id];
130+
return default(TValue);
131+
});
132+
}
133+
set
134+
{
135+
RetryAction((redis) =>
136+
{
137+
GetCollection(redis)[id] = value;
138+
});
139+
}
140+
}
141+
public int Count
142+
{
143+
get
144+
{
145+
return RetryAction<int>((redis) =>
146+
{
147+
return GetCollection(redis).Count;
148+
});
149+
}
150+
}
151+
152+
public IEnumerable<TValue> Where(Func<TValue, bool> predicate)
153+
{
154+
return RetryAction((redis) =>
155+
{
156+
return GetCollection(redis).Values.Where(predicate);
157+
});
158+
}
159+
160+
public bool Any(Func<TValue, bool> predicate)
161+
{
162+
return RetryAction<bool>((redis) =>
163+
{
164+
return GetCollection(redis).Values.Any(predicate);
165+
});
166+
}
167+
168+
169+
public IEnumerator<TValue> GetEnumerator()
170+
{
171+
return RetryAction<IEnumerator<TValue>>((redis) =>
172+
{
173+
return GetCollection(redis).Values.GetEnumerator();
174+
});
175+
}
176+
177+
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
178+
{
179+
return RetryAction(redis =>
180+
{
181+
return ((System.Collections.IEnumerable)GetCollection(redis).Values).GetEnumerator();
182+
});
183+
184+
}
185+
186+
public void Clear()
187+
{
188+
RetryAction((redis) =>
189+
{
190+
GetCollection(redis).Clear();
191+
});
192+
}
193+
194+
public bool Contains(TValue obj)
195+
{
196+
TKey Id = GetUniqueIdAction(obj);
197+
return RetryAction<bool>((redis) =>
198+
{
199+
return GetCollection(redis).ContainsKey(Id);
200+
});
201+
}
202+
203+
public bool ContainsKey(TKey obj)
204+
{
205+
return RetryAction<bool>((redis) =>
206+
{
207+
return GetCollection(redis).ContainsKey(obj);
208+
});
209+
}
210+
211+
public void CopyTo(TValue[] array, int arrayIndex)
212+
{
213+
RetryAction((redis) =>
214+
{
215+
GetCollection(redis).Values.CopyTo(array, arrayIndex);
216+
});
217+
}
218+
219+
public bool IsReadOnly
220+
{
221+
get
222+
{
223+
return RetryAction<bool>((redis) =>
224+
{
225+
return GetCollection(redis).IsReadOnly;
226+
});
227+
}
228+
}
229+
230+
public Func<TValue, TKey> GetUniqueIdAction
231+
{
232+
get
233+
{
234+
return idAction;
235+
}
236+
set
237+
{
238+
idAction = value;
239+
}
240+
}
241+
242+
private void RetryAction(Action<IRedisClient> action)
243+
{
244+
int i = 0;
245+
while (true)
246+
{
247+
try
248+
{
249+
using (var redis = RedisConnection)
250+
{
251+
action(redis);
252+
return;
253+
}
254+
}
255+
catch (Exception ex)
256+
{
257+
Console.WriteLine(ex);
258+
throw;
259+
260+
//if (i++ < 3)
261+
//{
262+
// continue;
263+
//}
264+
//throw;
265+
}
266+
}
267+
}
268+
269+
private TOut RetryAction<TOut>(Func<IRedisClient, TOut> action)
270+
{
271+
int i = 0;
272+
273+
while (true)
274+
{
275+
try
276+
{
277+
using (var redis = RedisConnection)
278+
{
279+
TOut result = action(redis);
280+
return result;
281+
}
282+
}
283+
catch (Exception ex)
284+
{
285+
286+
if (i++ < 3)
287+
{
288+
289+
continue;
290+
}
291+
292+
throw;
293+
}
294+
}
295+
}
296+
}
297+
}

tests/Console.Tests/Program.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ static void Main(string[] args)
1818
//new HashStressTest().Execute("127.0.0.1");
1919
//new HashStressTest().Execute("10.0.0.9");
2020

21+
new HashCollectionStressTests().Execute("10.0.0.9", noOfThreads: 64);
2122
}
2223
}
2324
}

0 commit comments

Comments
 (0)