Commit b6e4bd65 authored by Marc Gravell's avatar Marc Gravell

Revisit prefixed keys to avoid allocations; update MS redis-64 from nuget;...

Revisit prefixed keys to avoid allocations; update MS redis-64 from nuget; update tests; change namespace of keyspace isolation - that was an error
parent a541e22d
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="NuGet.CommandLine" version="2.8.2" /> <package id="NuGet.CommandLine" version="2.8.3" />
<package id="Redis-64" version="2.8.12" /> <package id="Redis-64" version="2.8.17" />
</packages> </packages>
\ No newline at end of file
@..\packages\Redis-64.2.8.12\redis-cli.exe -h cluster -p 7000 @..\packages\Redis-64.2.8.17\redis-cli.exe -h cluster -p 7000
\ No newline at end of file
@..\packages\Redis-64.2.8.12\redis-cli.exe -h cluster -p 7001 @..\packages\Redis-64.2.8.17\redis-cli.exe -h cluster -p 7001
@..\packages\Redis-64.2.8.12\redis-cli.exe -h cluster -p 7002 @..\packages\Redis-64.2.8.17\redis-cli.exe -h cluster -p 7002
@..\packages\Redis-64.2.8.12\redis-cli.exe -h cluster -p 7003 @..\packages\Redis-64.2.8.17\redis-cli.exe -h cluster -p 7003
@..\packages\Redis-64.2.8.12\redis-cli.exe -h cluster -p 7004 @..\packages\Redis-64.2.8.17\redis-cli.exe -h cluster -p 7004
@..\packages\Redis-64.2.8.12\redis-cli.exe -h cluster -p 7005 @..\packages\Redis-64.2.8.17\redis-cli.exe -h cluster -p 7005
@..\packages\Redis-64.2.8.12\redis-cli.exe -p 6379 @..\packages\Redis-64.2.8.17\redis-cli.exe -p 6379
@..\packages\Redis-64.2.8.12\redis-cli.exe -p 6381 @..\packages\Redis-64.2.8.17\redis-cli.exe -p 6381
@..\packages\Redis-64.2.8.12\redis-cli.exe -p 6380 @..\packages\Redis-64.2.8.17\redis-cli.exe -p 6380
@start ..\packages\Redis-64.2.8.12\redis-server.exe master.conf @start ..\packages\Redis-64.2.8.17\redis-server.exe master.conf
@start ..\packages\Redis-64.2.8.12\redis-server.exe slave.conf @start ..\packages\Redis-64.2.8.17\redis-server.exe slave.conf
@start ..\packages\Redis-64.2.8.12\redis-server.exe secure.conf @start ..\packages\Redis-64.2.8.17\redis-server.exe secure.conf
@..\packages\Redis-64.2.8.12\redis-server.exe master.conf @..\packages\Redis-64.2.8.17\redis-server.exe master.conf
@..\packages\Redis-64.2.8.12\redis-server.exe secure.conf @..\packages\Redis-64.2.8.17\redis-server.exe secure.conf
@..\packages\Redis-64.2.8.12\redis-server.exe slave.conf @..\packages\Redis-64.2.8.17\redis-server.exe slave.conf
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
using System.Threading.Tasks; using System.Threading.Tasks;
using BookSleeve; using BookSleeve;
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.KeyspaceIsolation;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
[TestFixture] [TestFixture]
...@@ -664,6 +664,22 @@ private void Incr(IDatabase database, RedisKey key, int delta, ref int total) ...@@ -664,6 +664,22 @@ private void Incr(IDatabase database, RedisKey key, int delta, ref int total)
database.StringIncrement(key, delta, CommandFlags.FireAndForget); database.StringIncrement(key, delta, CommandFlags.FireAndForget);
total += delta; total += delta;
} }
[Test]
public void WrappedDatabasePrefixIntegration()
{
using (var conn = Create())
{
var db = conn.GetDatabase().WithKeyPrefix("abc");
db.KeyDelete("count");
db.StringIncrement("count");
db.StringIncrement("count");
db.StringIncrement("count");
int count = (int)conn.GetDatabase().StringGet("abccount");
Assert.AreEqual(3, count);
}
}
} }
} }
using System; using System;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
using System.Text;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
...@@ -15,7 +16,7 @@ public sealed class BatchWrapperTests ...@@ -15,7 +16,7 @@ public sealed class BatchWrapperTests
public void Initialize() public void Initialize()
{ {
mock = new Mock<IBatch>(); mock = new Mock<IBatch>();
wrapper = new BatchWrapper(mock.Object, "prefix:"); wrapper = new BatchWrapper(mock.Object, Encoding.UTF8.GetBytes("prefix:"));
} }
[Test] [Test]
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
using System.Net; using System.Net;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
using System.Text;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
...@@ -18,7 +19,7 @@ public sealed class DatabaseWrapperTests ...@@ -18,7 +19,7 @@ public sealed class DatabaseWrapperTests
public void Initialize() public void Initialize()
{ {
mock = new Mock<IDatabase>(); mock = new Mock<IDatabase>();
wrapper = new DatabaseWrapper(mock.Object, "prefix:"); wrapper = new DatabaseWrapper(mock.Object, Encoding.UTF8.GetBytes("prefix:"));
} }
[Test] [Test]
...@@ -149,7 +150,7 @@ public void HashLength() ...@@ -149,7 +150,7 @@ public void HashLength()
public void HashScan() public void HashScan()
{ {
wrapper.HashScan("key", "pattern", 123, flags: CommandFlags.HighPriority); wrapper.HashScan("key", "pattern", 123, flags: CommandFlags.HighPriority);
mock.Verify(_ => _.HashScan("prefix:key", "pattern", 123, CommandFlags.HighPriority)); mock.Verify(_ => _.HashScan("prefix:key", "pattern", 123, 0, 0, CommandFlags.HighPriority));
} }
[Test] [Test]
...@@ -604,7 +605,7 @@ public void SetRemove_2() ...@@ -604,7 +605,7 @@ public void SetRemove_2()
public void SetScan() public void SetScan()
{ {
wrapper.SetScan("key", "pattern", 123, flags: CommandFlags.HighPriority); wrapper.SetScan("key", "pattern", 123, flags: CommandFlags.HighPriority);
mock.Verify(_ => _.SetScan("prefix:key", "pattern", 123, CommandFlags.HighPriority)); mock.Verify(_ => _.SetScan("prefix:key", "pattern", 123, 0, 0, CommandFlags.HighPriority));
} }
[Test] [Test]
...@@ -774,7 +775,7 @@ public void SortedSetRemoveRangeByValue() ...@@ -774,7 +775,7 @@ public void SortedSetRemoveRangeByValue()
public void SortedSetScan() public void SortedSetScan()
{ {
wrapper.SortedSetScan("key", "pattern", 123, flags: CommandFlags.HighPriority); wrapper.SortedSetScan("key", "pattern", 123, flags: CommandFlags.HighPriority);
mock.Verify(_ => _.SortedSetScan("prefix:key", "pattern", 123, CommandFlags.HighPriority)); mock.Verify(_ => _.SortedSetScan("prefix:key", "pattern", 123, 0, 0, CommandFlags.HighPriority));
} }
[Test] [Test]
......
...@@ -5,10 +5,6 @@ namespace StackExchange.Redis.Tests ...@@ -5,10 +5,6 @@ namespace StackExchange.Redis.Tests
[TestFixture] [TestFixture]
public class Lex : TestBase public class Lex : TestBase
{ {
protected override string GetConfiguration()
{
return "ubuntu";
}
[Test] [Test]
public void QueryRangeAndLengthByLex() public void QueryRangeAndLengthByLex()
......
...@@ -14,7 +14,7 @@ protected override string GetConfiguration() ...@@ -14,7 +14,7 @@ protected override string GetConfiguration()
return PrimaryServer + ":" + SecurePort + "," + PrimaryServer + ":" + PrimaryPort + ",password=" + SecurePassword; return PrimaryServer + ":" + SecurePort + "," + PrimaryServer + ":" + PrimaryPort + ",password=" + SecurePassword;
} }
[Test, ExpectedException(typeof(RedisCommandException), ExpectedMessage = "FLUSHDB cannot be issued to a slave")] [Test, ExpectedException(typeof(RedisCommandException), ExpectedMessage = "Command cannot be issued to a slave: FLUSHDB")]
public void CannotFlushSlave() public void CannotFlushSlave()
{ {
ConfigurationOptions config = GetMasterSlaveConfig(); ConfigurationOptions config = GetMasterSlaveConfig();
...@@ -73,7 +73,7 @@ public void DeslaveGoesToPrimary() ...@@ -73,7 +73,7 @@ public void DeslaveGoesToPrimary()
} }
catch (RedisConnectionException ex) catch (RedisConnectionException ex)
{ {
Assert.AreEqual("No connection is available to service this operation: EXISTS", ex.Message); Assert.AreEqual("No connection is available to service this operation: EXISTS DeslaveGoesToPrimary", ex.Message);
} }
primary.MakeMaster(ReplicationChangeOptions.Broadcast | ReplicationChangeOptions.EnslaveSubordinates | ReplicationChangeOptions.SetTiebreaker); primary.MakeMaster(ReplicationChangeOptions.Broadcast | ReplicationChangeOptions.EnslaveSubordinates | ReplicationChangeOptions.SetTiebreaker);
......
...@@ -73,6 +73,8 @@ public void CheckDatabaseMethodsUseKeys(Type type) ...@@ -73,6 +73,8 @@ public void CheckDatabaseMethodsUseKeys(Type type)
{ {
case "KeyRandom": case "KeyRandom":
case "KeyRandomAsync": case "KeyRandomAsync":
case "Publish":
case "PublishAsync":
continue; // they're fine, but don't want to widen check to return type continue; // they're fine, but don't want to widen check to return type
} }
......
...@@ -33,9 +33,5 @@ public void SubscriberCount() ...@@ -33,9 +33,5 @@ public void SubscriberCount()
Assert.IsTrue(channels.Contains(channel)); Assert.IsTrue(channels.Contains(channel));
} }
} }
protected override string GetConfiguration()
{
return "ubuntu";
}
} }
} }
using System; using System;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
using System.Text;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
...@@ -15,7 +16,7 @@ public sealed class TransactionWrapperTests ...@@ -15,7 +16,7 @@ public sealed class TransactionWrapperTests
public void Initialize() public void Initialize()
{ {
mock = new Mock<ITransaction>(); mock = new Mock<ITransaction>();
wrapper = new TransactionWrapper(mock.Object, "prefix:"); wrapper = new TransactionWrapper(mock.Object, Encoding.UTF8.GetBytes("prefix:"));
} }
[Test] [Test]
......
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
using System; using System;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
......
...@@ -4,7 +4,8 @@ ...@@ -4,7 +4,8 @@
using System.Net; using System.Net;
using Moq; using Moq;
using NUnit.Framework; using NUnit.Framework;
using StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation; using StackExchange.Redis.KeyspaceIsolation;
using System.Text;
namespace StackExchange.Redis.Tests namespace StackExchange.Redis.Tests
{ {
...@@ -18,7 +19,7 @@ public sealed class WrapperBaseTests ...@@ -18,7 +19,7 @@ public sealed class WrapperBaseTests
public void Initialize() public void Initialize()
{ {
mock = new Mock<IDatabaseAsync>(); mock = new Mock<IDatabaseAsync>();
wrapper = new WrapperBase<IDatabaseAsync>(mock.Object, "prefix:"); wrapper = new WrapperBase<IDatabaseAsync>(mock.Object, Encoding.UTF8.GetBytes("prefix:"));
} }
[Test] [Test]
......
...@@ -163,7 +163,7 @@ public ExistsCondition(RedisKey key, RedisValue hashField, bool expectedResult) ...@@ -163,7 +163,7 @@ public ExistsCondition(RedisKey key, RedisValue hashField, bool expectedResult)
public override string ToString() public override string ToString()
{ {
return (hashField.IsNull ? key.ToString() : key + " > " + hashField) return (hashField.IsNull ? key.ToString() : ((string)key) + " > " + hashField)
+ (expectedResult ? " exists" : " does not exists"); + (expectedResult ? " exists" : " does not exists");
} }
...@@ -221,7 +221,7 @@ public EqualsCondition(RedisKey key, RedisValue hashField, bool expectedEqual, R ...@@ -221,7 +221,7 @@ public EqualsCondition(RedisKey key, RedisValue hashField, bool expectedEqual, R
public override string ToString() public override string ToString()
{ {
return (hashField.IsNull ? key.ToString() : key + " > " + hashField) return (hashField.IsNull ? key.ToString() : ((string)key) + " > " + hashField)
+ (expectedEqual ? " == " : " != ") + (expectedEqual ? " == " : " != ")
+ expectedValue; + expectedValue;
} }
......
using System; using System;
namespace StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation namespace StackExchange.Redis.KeyspaceIsolation
{ {
internal sealed class BatchWrapper : WrapperBase<IBatch>, IBatch internal sealed class BatchWrapper : WrapperBase<IBatch>, IBatch
{ {
public BatchWrapper(IBatch inner, RedisKey prefix) public BatchWrapper(IBatch inner, byte[] prefix)
: base(inner, prefix) : base(inner, prefix)
{ {
} }
......
using System; using System;
namespace StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation namespace StackExchange.Redis.KeyspaceIsolation
{ {
/// <summary> /// <summary>
/// Provides the <see cref="WithKeyPrefix"/> extension method to <see cref="IDatabase"/>. /// Provides the <see cref="WithKeyPrefix"/> extension method to <see cref="IDatabase"/>.
...@@ -49,7 +49,7 @@ public static IDatabase WithKeyPrefix(this IDatabase database, RedisKey keyPrefi ...@@ -49,7 +49,7 @@ public static IDatabase WithKeyPrefix(this IDatabase database, RedisKey keyPrefi
throw new ArgumentNullException("keyPrefix"); throw new ArgumentNullException("keyPrefix");
} }
if (keyPrefix.Value.Length == 0) if (keyPrefix.IsEmpty)
{ {
return database; // fine - you can keep using the original, then return database; // fine - you can keep using the original, then
} }
...@@ -62,7 +62,7 @@ public static IDatabase WithKeyPrefix(this IDatabase database, RedisKey keyPrefi ...@@ -62,7 +62,7 @@ public static IDatabase WithKeyPrefix(this IDatabase database, RedisKey keyPrefi
database = wrapper.Inner; database = wrapper.Inner;
} }
return new DatabaseWrapper(database, keyPrefix); return new DatabaseWrapper(database, keyPrefix.AsPrefix());
} }
} }
} }
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Net; using System.Net;
namespace StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation namespace StackExchange.Redis.KeyspaceIsolation
{ {
internal sealed class DatabaseWrapper : WrapperBase<IDatabase>, IDatabase internal sealed class DatabaseWrapper : WrapperBase<IDatabase>, IDatabase
{ {
public DatabaseWrapper(IDatabase inner, RedisKey prefix) public DatabaseWrapper(IDatabase inner, byte[] prefix)
: base(inner, prefix) : base(inner, prefix)
{ {
} }
......
using System; using System;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation namespace StackExchange.Redis.KeyspaceIsolation
{ {
internal sealed class TransactionWrapper : WrapperBase<ITransaction>, ITransaction internal sealed class TransactionWrapper : WrapperBase<ITransaction>, ITransaction
{ {
public TransactionWrapper(ITransaction inner, RedisKey prefix) public TransactionWrapper(ITransaction inner, byte[] prefix)
: base(inner, prefix) : base(inner, prefix)
{ {
} }
......
...@@ -4,17 +4,17 @@ ...@@ -4,17 +4,17 @@
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace StackExchange.Redis.StackExchange.Redis.KeyspaceIsolation namespace StackExchange.Redis.KeyspaceIsolation
{ {
internal class WrapperBase<TInner> : IDatabaseAsync where TInner : IDatabaseAsync internal class WrapperBase<TInner> : IDatabaseAsync where TInner : IDatabaseAsync
{ {
private readonly TInner _inner; private readonly TInner _inner;
private readonly RedisKey _prefix; private readonly byte[] _keyPrefix;
internal WrapperBase(TInner inner, RedisKey prefix) internal WrapperBase(TInner inner, byte[] keyPrefix)
{ {
_inner = inner; _inner = inner;
_prefix = prefix; _keyPrefix = keyPrefix;
} }
public ConnectionMultiplexer Multiplexer public ConnectionMultiplexer Multiplexer
...@@ -27,9 +27,9 @@ internal TInner Inner ...@@ -27,9 +27,9 @@ internal TInner Inner
get { return _inner; } get { return _inner; }
} }
internal RedisKey Prefix internal byte[] Prefix
{ {
get { return _prefix; } get { return _keyPrefix; }
} }
public Task<RedisValue> DebugObjectAsync(RedisKey key, CommandFlags flags = CommandFlags.None) public Task<RedisValue> DebugObjectAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
...@@ -653,7 +653,7 @@ public Task<string> ClientGetNameAsync(CommandFlags flags = CommandFlags.None) ...@@ -653,7 +653,7 @@ public Task<string> ClientGetNameAsync(CommandFlags flags = CommandFlags.None)
protected internal RedisKey ToInner(RedisKey outer) protected internal RedisKey ToInner(RedisKey outer)
{ {
return this.Prefix + outer; return RedisKey.WithPrefix(_keyPrefix, outer);
} }
protected RedisKey ToInnerOrDefault(RedisKey outer) protected RedisKey ToInnerOrDefault(RedisKey outer)
...@@ -713,7 +713,7 @@ protected RedisKey[] ToInner(RedisKey[] outer) ...@@ -713,7 +713,7 @@ protected RedisKey[] ToInner(RedisKey[] outer)
protected RedisValue ToInner(RedisValue outer) protected RedisValue ToInner(RedisValue outer)
{ {
return RedisKey.Concatenate(this.Prefix, outer); return RedisKey.ConcatenateBytes(this.Prefix, null, (byte[])outer);
} }
protected RedisValue SortByToInner(RedisValue outer) protected RedisValue SortByToInner(RedisValue outer)
...@@ -761,7 +761,7 @@ protected RedisValue[] SortGetToInner(RedisValue[] outer) ...@@ -761,7 +761,7 @@ protected RedisValue[] SortGetToInner(RedisValue[] outer)
protected RedisChannel ToInner(RedisChannel outer) protected RedisChannel ToInner(RedisChannel outer)
{ {
return RedisKey.Concatenate((byte[])Prefix, (byte[])outer); return RedisKey.ConcatenateBytes(this.Prefix, null, (byte[])outer);
} }
private Func<RedisKey, RedisKey> mapFunction; private Func<RedisKey, RedisKey> mapFunction;
......
...@@ -612,7 +612,7 @@ public CommandKeyBase(int db, CommandFlags flags, RedisCommand command, RedisKey ...@@ -612,7 +612,7 @@ public CommandKeyBase(int db, CommandFlags flags, RedisCommand command, RedisKey
this.Key = key; this.Key = key;
} }
public override string CommandAndKey { get { return Command + " " + Key; } } public override string CommandAndKey { get { return Command + " " + ((string)Key); } }
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
{ {
return serverSelectionStrategy.HashSlot(Key); return serverSelectionStrategy.HashSlot(Key);
......
...@@ -354,7 +354,15 @@ internal void SetUnknownDatabase() ...@@ -354,7 +354,15 @@ internal void SetUnknownDatabase()
internal void Write(RedisKey key) internal void Write(RedisKey key)
{ {
WriteUnified(outStream, key.Value); var val = key.KeyValue;
if (val is string)
{
WriteUnified(outStream, key.KeyPrefix, (string)val);
}
else
{
WriteUnified(outStream, key.KeyPrefix, (byte[])val);
}
} }
internal void Write(RedisChannel channel) internal void Write(RedisChannel channel)
...@@ -494,6 +502,61 @@ internal static byte ToHexNibble(int value) ...@@ -494,6 +502,61 @@ internal static byte ToHexNibble(int value)
return value < 10 ? (byte)('0' + value) : (byte)('a' - 10 + value); return value < 10 ? (byte)('0' + value) : (byte)('a' - 10 + value);
} }
void WriteUnified(Stream stream, byte[] prefix, string value)
{
stream.WriteByte((byte)'$');
if (value == null)
{
WriteRaw(stream, -1); // note that not many things like this...
}
else
{
int encodedLength = Encoding.UTF8.GetByteCount(value);
if (prefix == null)
{
WriteRaw(stream, encodedLength);
WriteRaw(stream, value, encodedLength);
stream.Write(Crlf, 0, 2);
}
else
{
WriteRaw(stream, prefix.Length + encodedLength);
stream.Write(prefix, 0, prefix.Length);
WriteRaw(stream, value, encodedLength);
stream.Write(Crlf, 0, 2);
}
}
}
unsafe void WriteRaw(Stream stream, string value, int encodedLength)
{
if (encodedLength <= ScratchSize)
{
int bytes = Encoding.UTF8.GetBytes(value, 0, value.Length, outScratch, 0);
stream.Write(outScratch, 0, bytes);
}
else
{
fixed (char* c = value)
fixed (byte* b = outScratch)
{
int charsRemaining = value.Length, charOffset = 0, bytesWritten;
while (charsRemaining > Scratch_CharsPerBlock)
{
bytesWritten = outEncoder.GetBytes(c + charOffset, Scratch_CharsPerBlock, b, ScratchSize, false);
stream.Write(outScratch, 0, bytesWritten);
charOffset += Scratch_CharsPerBlock;
charsRemaining -= Scratch_CharsPerBlock;
}
bytesWritten = outEncoder.GetBytes(c + charOffset, charsRemaining, b, ScratchSize, true);
if (bytesWritten != 0) stream.Write(outScratch, 0, bytesWritten);
}
}
}
const int ScratchSize = 512;
static readonly int Scratch_CharsPerBlock = ScratchSize / Encoding.UTF8.GetMaxByteCount(1);
private readonly byte[] outScratch = new byte[ScratchSize];
private readonly Encoder outEncoder = Encoding.UTF8.GetEncoder();
static void WriteUnified(Stream stream, byte[] prefix, byte[] value) static void WriteUnified(Stream stream, byte[] prefix, byte[] value)
{ {
stream.WriteByte((byte)'$'); stream.WriteByte((byte)'$');
......
...@@ -2322,7 +2322,7 @@ public StringGetWithExpiryMessage(int db, CommandFlags flags, RedisCommand ttlCo ...@@ -2322,7 +2322,7 @@ public StringGetWithExpiryMessage(int db, CommandFlags flags, RedisCommand ttlCo
{ {
this.ttlCommand = ttlCommand; this.ttlCommand = ttlCommand;
} }
public override string CommandAndKey { get { return ttlCommand + "+" + RedisCommand.GET + " " + Key; } } public override string CommandAndKey { get { return ttlCommand + "+" + RedisCommand.GET + " " + (string)Key; } }
public IEnumerable<Message> GetMessages(PhysicalConnection connection) public IEnumerable<Message> GetMessages(PhysicalConnection connection)
{ {
......
...@@ -61,15 +61,16 @@ public ServerSelectionStrategy(ConnectionMultiplexer multiplexer) ...@@ -61,15 +61,16 @@ public ServerSelectionStrategy(ConnectionMultiplexer multiplexer)
/// <summary> /// <summary>
/// Computes the hash-slot that would be used by the given key /// Computes the hash-slot that would be used by the given key
/// </summary> /// </summary>
public unsafe int HashSlot(byte[] key) public unsafe int HashSlot(RedisKey key)
{ {
//HASH_SLOT = CRC16(key) mod 16384 //HASH_SLOT = CRC16(key) mod 16384
if (key == null) return NoSlot; if (key.IsNull) return NoSlot;
unchecked unchecked
{ {
fixed (byte* ptr = key) var blob = (byte[])key;
fixed (byte* ptr = blob)
{ {
int offset = 0, count = key.Length, start, end; int offset = 0, count = blob.Length, start, end;
if ((start = IndexOf(ptr, (byte)'{', 0, count - 1)) >= 0 if ((start = IndexOf(ptr, (byte)'{', 0, count - 1)) >= 0
&& (end = IndexOf(ptr, (byte)'}', start + 1, count)) >= 0 && (end = IndexOf(ptr, (byte)'}', start + 1, count)) >= 0
&& --end != start) && --end != start)
...@@ -183,10 +184,9 @@ internal int CombineSlot(int oldSlot, int newSlot) ...@@ -183,10 +184,9 @@ internal int CombineSlot(int oldSlot, int newSlot)
} }
internal int CombineSlot(int oldSlot, RedisKey key) internal int CombineSlot(int oldSlot, RedisKey key)
{ {
byte[] blob = key.Value; if (oldSlot == MultipleSlots || key.IsNull) return oldSlot;
if (oldSlot == MultipleSlots || (blob = key.Value) == null) return oldSlot;
int newSlot = HashSlot(blob); int newSlot = HashSlot(key);
if (oldSlot == NoSlot) return newSlot; if (oldSlot == NoSlot) return newSlot;
return oldSlot == newSlot ? oldSlot : MultipleSlots; return oldSlot == newSlot ? oldSlot : MultipleSlots;
} }
......
...@@ -327,6 +327,16 @@ slave-priority 100 ...@@ -327,6 +327,16 @@ slave-priority 100
# Note that you must specify a directory here, not a file name. # Note that you must specify a directory here, not a file name.
# heapdir <directory path(absolute or relative)> # heapdir <directory path(absolute or relative)>
# If Redis is to be used as an in-memory-only cache without any kind of
# persistence, then the fork() mechanism used by the background AOF/RDB
# persistence is unneccessary. As an optimization, all persistence can be
# turned off in the Windows version of Redis. This will disable the creation of
# the memory mapped heap file, redirect heap allocations to the system heap
# allocator, and disable commands that would otherwise cause fork() operations:
# BGSAVE and BGREWRITEAOF. This flag may not be combined with any of the other
# flags that configure AOF and RDB operations.
# persistence-available [(yes)|no]
# Don't use more memory than the specified amount of bytes. # Don't use more memory than the specified amount of bytes.
# When the memory limit is reached Redis will try to remove keys # When the memory limit is reached Redis will try to remove keys
# accordingly to the eviction policy selected (see maxmemmory-policy). # accordingly to the eviction policy selected (see maxmemmory-policy).
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment