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

Commit c997f7b

Browse files
committed
Add ExecCachedLua for managing book keeping around loading/executing cached lua scripts
1 parent a686433 commit c997f7b

File tree

5 files changed

+112
-0
lines changed

5 files changed

+112
-0
lines changed

lib/tests/ServiceStack.Interfaces.dll

0 Bytes
Binary file not shown.

src/ServiceStack.Redis/RedisClient.cs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
using System;
1414
using System.Collections;
15+
using System.Collections.Concurrent;
1516
using System.Collections.Generic;
1617
using System.Linq;
1718
using System.Text;
@@ -866,6 +867,29 @@ public string UrnKey(Type type, object id)
866867

867868
#region LUA EVAL
868869

870+
static readonly ConcurrentDictionary<string, string> CachedLuaSha1Map =
871+
new ConcurrentDictionary<string, string>();
872+
873+
public T ExecCachedLua<T>(string scriptBody, Func<string, T> scriptSha1)
874+
{
875+
string sha1;
876+
if (!CachedLuaSha1Map.TryGetValue(scriptBody, out sha1))
877+
CachedLuaSha1Map[scriptBody] = sha1 = LoadLuaScript(scriptBody);
878+
879+
try
880+
{
881+
return scriptSha1(sha1);
882+
}
883+
catch (RedisResponseException ex)
884+
{
885+
if (!ex.Message.StartsWith("NOSCRIPT"))
886+
throw;
887+
888+
CachedLuaSha1Map[scriptBody] = sha1 = LoadLuaScript(scriptBody);
889+
return scriptSha1(sha1);
890+
}
891+
}
892+
869893
public RedisText ExecLua(string body, params string[] args)
870894
{
871895
var data = base.EvalCommand(body, 0, args.ToMultiByteArray());

src/ServiceStack.Redis/RedisNativeClient_Utils.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -528,7 +528,10 @@ protected T SendReceive<T>(byte[][] cmdWithBinaryArgs,
528528
{
529529
var retryableEx = outerEx as RedisRetryableException;
530530
if (retryableEx == null && outerEx is RedisException)
531+
{
532+
ResetSendBuffer();
531533
throw;
534+
}
532535

533536
var ex = retryableEx ?? GetRetryableException(outerEx);
534537
if (ex == null)
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
using NUnit.Framework;
2+
using ServiceStack.Text;
3+
4+
namespace ServiceStack.Redis.Tests
5+
{
6+
[TestFixture]
7+
public class LuaCachedScripts
8+
{
9+
private const string LuaScript = @"
10+
local limit = tonumber(ARGV[2])
11+
local pattern = ARGV[1]
12+
local cursor = 0
13+
local len = 0
14+
local results = {}
15+
16+
repeat
17+
local r = redis.call('scan', cursor, 'MATCH', pattern, 'COUNT', limit)
18+
cursor = tonumber(r[1])
19+
for k,v in ipairs(r[2]) do
20+
table.insert(results, v)
21+
len = len + 1
22+
if len == limit then break end
23+
end
24+
until cursor == 0 or len == limit
25+
26+
return results
27+
";
28+
29+
private static void AddTestKeys(RedisClient redis, int count)
30+
{
31+
count.Times(i =>
32+
redis.SetValue("key:" + i, "value:" + i));
33+
}
34+
35+
[Test]
36+
public void Can_call_repeated_scans_in_LUA()
37+
{
38+
using (var redis = new RedisClient())
39+
{
40+
AddTestKeys(redis, 20);
41+
42+
var r = redis.ExecLua(LuaScript, "key:*", "10");
43+
Assert.That(r.Children.Count, Is.EqualTo(10));
44+
45+
r = redis.ExecLua(LuaScript, "key:*", "40");
46+
Assert.That(r.Children.Count, Is.EqualTo(20));
47+
}
48+
}
49+
50+
[Test]
51+
public void Can_call_Cached_Lua()
52+
{
53+
using (var redis = new RedisClient())
54+
{
55+
AddTestKeys(redis, 20);
56+
57+
var r = redis.ExecCachedLua(LuaScript, sha1 =>
58+
redis.ExecLuaSha(sha1, "key:*", "10"));
59+
Assert.That(r.Children.Count, Is.EqualTo(10));
60+
61+
r = redis.ExecCachedLua(LuaScript, sha1 =>
62+
redis.ExecLuaSha(sha1, "key:*", "10"));
63+
Assert.That(r.Children.Count, Is.EqualTo(10));
64+
}
65+
}
66+
67+
[Test]
68+
public void Can_call_Cached_Lua_even_after_script_is_flushed()
69+
{
70+
using (var redis = new RedisClient())
71+
{
72+
var r = redis.ExecCachedLua(LuaScript, sha1 =>
73+
redis.ExecLuaSha(sha1, "key:*", "10"));
74+
Assert.That(r.Children.Count, Is.EqualTo(10));
75+
76+
redis.ScriptFlush();
77+
78+
r = redis.ExecCachedLua(LuaScript, sha1 =>
79+
redis.ExecLuaSha(sha1, "key:*", "10"));
80+
Assert.That(r.Children.Count, Is.EqualTo(10));
81+
}
82+
}
83+
}
84+
}

tests/ServiceStack.Redis.Tests/ServiceStack.Redis.Tests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@
183183
<Compile Include="AdhocClientTests.cs" />
184184
<Compile Include="ConfigTests.cs" />
185185
<Compile Include="CustomCommandTests.cs" />
186+
<Compile Include="LuaCachedScripts.cs" />
186187
<Compile Include="Examples\TestData.cs" />
187188
<Compile Include="Issues\RedisCharacterizationTests.cs" />
188189
<Compile Include="RedisBatchTests.cs" />

0 commit comments

Comments
 (0)