Skip to content

Commit d2925c3

Browse files
committed
Merge branch 'develop' of https://github.com/nopSolutions/nopCommerce into develop
2 parents ba958c9 + b1cf9d9 commit d2925c3

File tree

13 files changed

+482
-226
lines changed

13 files changed

+482
-226
lines changed

src/Libraries/Nop.Core/Caching/IRedisConnectionWrapper.cs

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,43 @@
55
namespace Nop.Core.Caching
66
{
77
/// <summary>
8-
/// Redis connection wrapper
8+
/// Redis connection wrapper interface
99
/// </summary>
1010
public interface IRedisConnectionWrapper : IDisposable
1111
{
12-
IDatabase Database(int? db = null);
13-
IServer Server(EndPoint endPoint);
14-
EndPoint[] GetEndpoints();
15-
void FlushDb(int? db = null);
12+
/// <summary>
13+
/// Obtain an interactive connection to a database inside redis
14+
/// </summary>
15+
/// <param name="db">Database number; pass null to use the default value</param>
16+
/// <returns>Redis cache database</returns>
17+
IDatabase GetDatabase(int? db = null);
18+
19+
/// <summary>
20+
/// Obtain a configuration API for an individual server
21+
/// </summary>
22+
/// <param name="endPoint">The network endpoint</param>
23+
/// <returns>Redis server</returns>
24+
IServer GetServer(EndPoint endPoint);
25+
26+
/// <summary>
27+
/// Gets all endpoints defined on the server
28+
/// </summary>
29+
/// <returns>Array of endpoints</returns>
30+
EndPoint[] GetEndPoints();
31+
32+
/// <summary>
33+
/// Delete all the keys of the database
34+
/// </summary>
35+
/// <param name="db">Database number; pass null to use the default value<</param>
36+
void FlushDatabase(int? db = null);
37+
38+
/// <summary>
39+
/// Perform some action with Redis distributed lock
40+
/// </summary>
41+
/// <param name="resource">The thing we are locking on</param>
42+
/// <param name="expirationTime">The time after which the lock will automatically be expired by Redis</param>
43+
/// <param name="action">Action to be performed with locking</param>
44+
/// <returns>True if lock was acquired and action was performed; otherwise false</returns>
45+
bool PerformActionWithLock(string resource, TimeSpan expirationTime, Action action);
1646
}
1747
}

src/Libraries/Nop.Core/Caching/RedisCacheManager.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public RedisCacheManager(NopConfig config, IRedisConnectionWrapper connectionWra
3131
// ConnectionMultiplexer.Connect should only be called once and shared between callers
3232
this._connectionWrapper = connectionWrapper;
3333

34-
this._db = _connectionWrapper.Database();
34+
this._db = _connectionWrapper.GetDatabase();
3535
this._perRequestCacheManager = EngineContext.Current.Resolve<ICacheManager>();
3636
}
3737

@@ -129,9 +129,9 @@ public virtual void Remove(string key)
129129
/// <param name="pattern">pattern</param>
130130
public virtual void RemoveByPattern(string pattern)
131131
{
132-
foreach (var ep in _connectionWrapper.GetEndpoints())
132+
foreach (var ep in _connectionWrapper.GetEndPoints())
133133
{
134-
var server = _connectionWrapper.Server(ep);
134+
var server = _connectionWrapper.GetServer(ep);
135135
var keys = server.Keys(database: _db.Database, pattern: "*" + pattern + "*");
136136
foreach (var key in keys)
137137
Remove(key);
@@ -143,9 +143,9 @@ public virtual void RemoveByPattern(string pattern)
143143
/// </summary>
144144
public virtual void Clear()
145145
{
146-
foreach (var ep in _connectionWrapper.GetEndpoints())
146+
foreach (var ep in _connectionWrapper.GetEndPoints())
147147
{
148-
var server = _connectionWrapper.Server(ep);
148+
var server = _connectionWrapper.GetServer(ep);
149149
//we can use the code below (commented)
150150
//but it requires administration permission - ",allowAdmin=true"
151151
//server.FlushDatabase();

src/Libraries/Nop.Core/Caching/RedisConnectionWrapper.cs

Lines changed: 116 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,55 @@
11
using System;
2+
using System.Linq;
23
using System.Net;
34
using Nop.Core.Configuration;
5+
using RedLock;
46
using StackExchange.Redis;
57

68
namespace Nop.Core.Caching
79
{
810
/// <summary>
9-
/// Redis connection wrapper
11+
/// Redis connection wrapper implementation
1012
/// </summary>
1113
public class RedisConnectionWrapper : IRedisConnectionWrapper
1214
{
15+
#region Fields
16+
1317
private readonly NopConfig _config;
1418
private readonly Lazy<string> _connectionString;
1519

1620
private volatile ConnectionMultiplexer _connection;
21+
private volatile RedisLockFactory _redisLockFactory;
1722
private readonly object _lock = new object();
1823

24+
#endregion
25+
26+
#region Ctor
27+
1928
public RedisConnectionWrapper(NopConfig config)
2029
{
2130
this._config = config;
2231
this._connectionString = new Lazy<string>(GetConnectionString);
32+
this._redisLockFactory = CreateRedisLockFactory();
2333
}
2434

25-
private string GetConnectionString()
35+
#endregion
36+
37+
#region Utilities
38+
39+
/// <summary>
40+
/// Get connection string to Redis cache from configuration
41+
/// </summary>
42+
/// <returns></returns>
43+
protected string GetConnectionString()
2644
{
2745
return _config.RedisCachingConnectionString;
2846
}
2947

30-
private ConnectionMultiplexer GetConnection()
48+
/// <summary>
49+
/// Get connection to Redis servers
50+
/// </summary>
51+
/// <returns></returns>
52+
protected ConnectionMultiplexer GetConnection()
3153
{
3254
if (_connection != null && _connection.IsConnected) return _connection;
3355

@@ -48,37 +70,120 @@ private ConnectionMultiplexer GetConnection()
4870
return _connection;
4971
}
5072

51-
public IDatabase Database(int? db = null)
73+
/// <summary>
74+
/// Create instance of RedisLockFactory
75+
/// </summary>
76+
/// <returns>RedisLockFactory</returns>
77+
protected RedisLockFactory CreateRedisLockFactory()
78+
{
79+
//get password and value whether to use ssl from connection string
80+
var password = string.Empty;
81+
var useSsl = false;
82+
foreach (var option in GetConnectionString().Split(',').Where(option => option.Contains('=')))
83+
{
84+
switch (option.Substring(0, option.IndexOf('=')).Trim().ToLowerInvariant())
85+
{
86+
case "password":
87+
password = option.Substring(option.IndexOf('=') + 1).Trim();
88+
break;
89+
case "ssl":
90+
bool.TryParse(option.Substring(option.IndexOf('=') + 1).Trim(), out useSsl);
91+
break;
92+
}
93+
}
94+
95+
//create RedisLockFactory for using Redlock distributed lock algorithm
96+
return new RedisLockFactory(GetEndPoints().Select(endPoint => new RedisLockEndPoint
97+
{
98+
EndPoint = endPoint,
99+
Password = password,
100+
Ssl = useSsl
101+
}));
102+
}
103+
104+
#endregion
105+
106+
#region Methods
107+
108+
/// <summary>
109+
/// Obtain an interactive connection to a database inside redis
110+
/// </summary>
111+
/// <param name="db">Database number; pass null to use the default value</param>
112+
/// <returns>Redis cache database</returns>
113+
public IDatabase GetDatabase(int? db = null)
52114
{
53115
return GetConnection().GetDatabase(db ?? -1); //_settings.DefaultDb);
54116
}
55117

56-
public IServer Server(EndPoint endPoint)
118+
/// <summary>
119+
/// Obtain a configuration API for an individual server
120+
/// </summary>
121+
/// <param name="endPoint">The network endpoint</param>
122+
/// <returns>Redis server</returns>
123+
public IServer GetServer(EndPoint endPoint)
57124
{
58125
return GetConnection().GetServer(endPoint);
59126
}
60127

61-
public EndPoint[] GetEndpoints()
128+
/// <summary>
129+
/// Gets all endpoints defined on the server
130+
/// </summary>
131+
/// <returns>Array of endpoints</returns>
132+
public EndPoint[] GetEndPoints()
62133
{
63134
return GetConnection().GetEndPoints();
64135
}
65136

66-
public void FlushDb(int? db = null)
137+
/// <summary>
138+
/// Delete all the keys of the database
139+
/// </summary>
140+
/// <param name="db">Database number; pass null to use the default value<</param>
141+
public void FlushDatabase(int? db = null)
67142
{
68-
var endPoints = GetEndpoints();
143+
var endPoints = GetEndPoints();
69144

70145
foreach (var endPoint in endPoints)
71146
{
72-
Server(endPoint).FlushDatabase(db ?? -1); //_settings.DefaultDb);
147+
GetServer(endPoint).FlushDatabase(db ?? -1); //_settings.DefaultDb);
73148
}
74149
}
75150

151+
/// <summary>
152+
/// Perform some action with Redis distributed lock
153+
/// </summary>
154+
/// <param name="resource">The thing we are locking on</param>
155+
/// <param name="expirationTime">The time after which the lock will automatically be expired by Redis</param>
156+
/// <param name="action">Action to be performed with locking</param>
157+
/// <returns>True if lock was acquired and action was performed; otherwise false</returns>
158+
public bool PerformActionWithLock(string resource, TimeSpan expirationTime, Action action)
159+
{
160+
//use RedLock library
161+
using (var redisLock = _redisLockFactory.Create(resource, expirationTime))
162+
{
163+
//ensure that lock is acquired
164+
if (!redisLock.IsAcquired)
165+
return false;
166+
167+
//perform action
168+
action();
169+
return true;
170+
}
171+
}
172+
173+
/// <summary>
174+
/// Release all resources associated with this object
175+
/// </summary>
76176
public void Dispose()
77177
{
178+
//dispose ConnectionMultiplexer
78179
if (_connection != null)
79-
{
80180
_connection.Dispose();
81-
}
181+
182+
//dispose RedisLockFactory
183+
if (_redisLockFactory != null)
184+
_redisLockFactory.Dispose();
82185
}
186+
187+
#endregion
83188
}
84189
}

src/Libraries/Nop.Core/Nop.Core.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,10 @@
5454
<HintPath>..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
5555
<Private>True</Private>
5656
</Reference>
57+
<Reference Include="RedLock.StrongName, Version=1.7.4.0, Culture=neutral, PublicKeyToken=1dffde0a6c007f07, processorArchitecture=MSIL">
58+
<HintPath>..\..\packages\RedLock.net.StrongName.1.7.4\lib\net45\RedLock.StrongName.dll</HintPath>
59+
<Private>True</Private>
60+
</Reference>
5761
<Reference Include="StackExchange.Redis.StrongName, Version=1.1.608.0, Culture=neutral, PublicKeyToken=c219ff1ca8c2ce46, processorArchitecture=MSIL">
5862
<HintPath>..\..\packages\StackExchange.Redis.StrongName.1.1.608\lib\net45\StackExchange.Redis.StrongName.dll</HintPath>
5963
<Private>True</Private>

src/Libraries/Nop.Core/packages.config

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@
88
<package id="Microsoft.AspNet.WebPages" version="3.2.3" targetFramework="net451" />
99
<package id="Microsoft.Web.Infrastructure" version="1.0.0.0" targetFramework="net451" />
1010
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net451" />
11+
<package id="RedLock.net.StrongName" version="1.7.4" targetFramework="net451" />
1112
<package id="StackExchange.Redis.StrongName" version="1.1.608" targetFramework="net451" />
1213
</packages>

0 commit comments

Comments
 (0)