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

Commit d92a471

Browse files
committed
Localize locks and synchronize RedisSentinelWorker using internal oLock
1 parent 31dc386 commit d92a471

File tree

2 files changed

+75
-55
lines changed

2 files changed

+75
-55
lines changed

src/ServiceStack.Redis/RedisSentinel.cs

Lines changed: 35 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public class RedisSentinel : IRedisSentinel
2323
public static string DefaultMasterName = "mymaster";
2424
public static string DefaultAddress = "127.0.0.1:26379";
2525

26-
private object oLock = new object();
26+
private readonly object oLock = new object();
2727
private bool isDisposed = false;
2828

2929
private readonly string masterName;
@@ -308,6 +308,7 @@ private RedisSentinelWorker GetValidSentinelWorker()
308308
{
309309
this.worker = GetNextSentinel();
310310
GetRedisManager();
311+
311312
this.worker.BeginListeningForConfigurationChanges();
312313
this.failures = 0; //reset
313314
return this.worker;
@@ -332,29 +333,23 @@ private RedisSentinelWorker GetValidSentinelWorker()
332333
public RedisEndpoint GetMaster()
333334
{
334335
var sentinelWorker = GetValidSentinelWorker();
335-
lock (sentinelWorker)
336-
{
337-
var host = sentinelWorker.GetMasterHost(masterName);
336+
var host = sentinelWorker.GetMasterHost(masterName);
338337

339-
if (ScanForOtherSentinels && DateTime.UtcNow - lastSentinelsRefresh > RefreshSentinelHostsAfter)
340-
{
341-
RefreshActiveSentinels();
342-
}
343-
344-
return host != null
345-
? (HostFilter != null ? HostFilter(host) : host).ToRedisEndpoint()
346-
: null;
338+
if (ScanForOtherSentinels && DateTime.UtcNow - lastSentinelsRefresh > RefreshSentinelHostsAfter)
339+
{
340+
RefreshActiveSentinels();
347341
}
342+
343+
return host != null
344+
? (HostFilter != null ? HostFilter(host) : host).ToRedisEndpoint()
345+
: null;
348346
}
349347

350348
public List<RedisEndpoint> GetSlaves()
351349
{
352350
var sentinelWorker = GetValidSentinelWorker();
353-
lock (sentinelWorker)
354-
{
355-
var hosts = sentinelWorker.GetSlaveHosts(masterName);
356-
return ConfigureHosts(hosts).Map(x => x.ToRedisEndpoint());
357-
}
351+
var hosts = sentinelWorker.GetSlaveHosts(masterName);
352+
return ConfigureHosts(hosts).Map(x => x.ToRedisEndpoint());
358353
}
359354

360355
/// <summary>
@@ -369,23 +364,32 @@ private bool ShouldRetry()
369364

370365
private RedisSentinelWorker GetNextSentinel()
371366
{
372-
lock (oLock)
367+
RedisSentinelWorker disposeWorker = null;
368+
369+
try
373370
{
374-
if (this.worker != null)
371+
lock (oLock)
375372
{
376-
this.worker.Dispose();
377-
this.worker = null;
378-
}
373+
if (this.worker != null)
374+
{
375+
disposeWorker = this.worker;
376+
this.worker = null;
377+
}
379378

380-
if (++sentinelIndex >= SentinelEndpoints.Length)
381-
sentinelIndex = 0;
379+
if (++sentinelIndex >= SentinelEndpoints.Length)
380+
sentinelIndex = 0;
382381

383-
var sentinelWorker = new RedisSentinelWorker(this, SentinelEndpoints[sentinelIndex])
384-
{
385-
OnSentinelError = OnSentinelError
386-
};
382+
var sentinelWorker = new RedisSentinelWorker(this, SentinelEndpoints[sentinelIndex])
383+
{
384+
OnSentinelError = OnSentinelError
385+
};
387386

388-
return sentinelWorker;
387+
return sentinelWorker;
388+
}
389+
}
390+
finally
391+
{
392+
disposeWorker?.Dispose();
389393
}
390394
}
391395

@@ -406,19 +410,13 @@ private void OnSentinelError(Exception ex)
406410
public void ForceMasterFailover()
407411
{
408412
var sentinelWorker = GetValidSentinelWorker();
409-
lock (sentinelWorker)
410-
{
411-
sentinelWorker.ForceMasterFailover(masterName);
412-
}
413+
sentinelWorker.ForceMasterFailover(masterName);
413414
}
414415

415416
public SentinelInfo GetSentinelInfo()
416417
{
417418
var sentinelWorker = GetValidSentinelWorker();
418-
lock (sentinelWorker)
419-
{
420-
return sentinelWorker.GetSentinelInfo();
421-
}
419+
return sentinelWorker.GetSentinelInfo();
422420
}
423421

424422
public void Dispose()

src/ServiceStack.Redis/RedisSentinelWorker.cs

Lines changed: 40 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ internal class RedisSentinelWorker : IDisposable
99
{
1010
protected static readonly ILog Log = LogManager.GetLogger(typeof(RedisSentinelWorker));
1111

12+
static int IdCounter = 0;
13+
public int Id { get; }
14+
15+
private readonly object oLock = new object();
16+
1217
private readonly RedisSentinel sentinel;
1318
private readonly RedisClient sentinelClient;
1419
private RedisPubSubServer sentinePubSub;
@@ -17,6 +22,7 @@ internal class RedisSentinelWorker : IDisposable
1722

1823
public RedisSentinelWorker(RedisSentinel sentinel, RedisEndpoint sentinelEndpoint)
1924
{
25+
this.Id = Interlocked.Increment(ref IdCounter);
2026
this.sentinel = sentinel;
2127
this.sentinelClient = new RedisClient(sentinelEndpoint) {
2228
Db = 0, //Sentinel Servers doesn't support DB, reset to 0
@@ -95,7 +101,10 @@ internal string GetMasterHost(string masterName)
95101

96102
private string GetMasterHostInternal(string masterName)
97103
{
98-
var masterInfo = sentinelClient.SentinelGetMasterAddrByName(masterName);
104+
List<string> masterInfo;
105+
lock (oLock)
106+
masterInfo = sentinelClient.SentinelGetMasterAddrByName(masterName);
107+
99108
return masterInfo.Count > 0
100109
? SanitizeMasterConfig(masterInfo)
101110
: null;
@@ -114,12 +123,21 @@ private string SanitizeMasterConfig(List<string> masterInfo)
114123

115124
internal List<string> GetSentinelHosts(string masterName)
116125
{
117-
return SanitizeHostsConfig(this.sentinelClient.SentinelSentinels(sentinel.MasterName));
126+
List<Dictionary<string, string>> sentinelSentinels;
127+
lock (oLock)
128+
sentinelSentinels = this.sentinelClient.SentinelSentinels(sentinel.MasterName);
129+
130+
return SanitizeHostsConfig(sentinelSentinels);
118131
}
119132

120133
internal List<string> GetSlaveHosts(string masterName)
121134
{
122-
return SanitizeHostsConfig(this.sentinelClient.SentinelSlaves(sentinel.MasterName));
135+
List<Dictionary<string, string>> sentinelSlaves;
136+
137+
lock (oLock)
138+
sentinelSlaves = sentinelClient.SentinelSlaves(sentinel.MasterName);
139+
140+
return SanitizeHostsConfig(sentinelSlaves);
123141
}
124142

125143
private List<string> SanitizeHostsConfig(IEnumerable<Dictionary<string, string>> slaves)
@@ -146,27 +164,30 @@ public void BeginListeningForConfigurationChanges()
146164
{
147165
try
148166
{
149-
if (this.sentinePubSub == null)
167+
lock (oLock)
150168
{
151-
var sentinelManager = new BasicRedisClientManager(sentinel.SentinelHosts, sentinel.SentinelHosts)
169+
if (this.sentinePubSub == null)
152170
{
153-
//Use BasicRedisResolver which doesn't validate non-Master Sentinel instances
154-
RedisResolver = new BasicRedisResolver(sentinel.SentinelEndpoints, sentinel.SentinelEndpoints)
155-
};
156-
this.sentinePubSub = new RedisPubSubServer(sentinelManager)
157-
{
158-
HeartbeatInterval = null,
159-
IsSentinelSubscription = true,
160-
ChannelsMatching = new[] { RedisPubSubServer.AllChannelsWildCard },
161-
OnMessage = SentinelMessageReceived
162-
};
171+
var sentinelManager = new BasicRedisClientManager(sentinel.SentinelHosts, sentinel.SentinelHosts)
172+
{
173+
//Use BasicRedisResolver which doesn't validate non-Master Sentinel instances
174+
RedisResolver = new BasicRedisResolver(sentinel.SentinelEndpoints, sentinel.SentinelEndpoints)
175+
};
176+
this.sentinePubSub = new RedisPubSubServer(sentinelManager)
177+
{
178+
HeartbeatInterval = null,
179+
IsSentinelSubscription = true,
180+
ChannelsMatching = new[] { RedisPubSubServer.AllChannelsWildCard },
181+
OnMessage = SentinelMessageReceived
182+
};
183+
}
163184
}
185+
164186
this.sentinePubSub.Start();
165187
}
166188
catch (Exception ex)
167189
{
168-
Log.Error("Error Subscribing to Redis Channel on {0}:{1}"
169-
.Fmt(this.sentinelClient.Host, this.sentinelClient.Port), ex);
190+
Log.Error($"Error Subscribing to Redis Channel on {this.sentinelClient.Host}:{this.sentinelClient.Port}", ex);
170191

171192
if (OnSentinelError != null)
172193
OnSentinelError(ex);
@@ -175,7 +196,8 @@ public void BeginListeningForConfigurationChanges()
175196

176197
public void ForceMasterFailover(string masterName)
177198
{
178-
this.sentinelClient.SentinelFailover(masterName);
199+
lock (oLock)
200+
this.sentinelClient.SentinelFailover(masterName);
179201
}
180202

181203
public void Dispose()

0 commit comments

Comments
 (0)