Commit 4e4bcae6 authored by mgravell's avatar mgravell

merge GEO PR (incomplete)

parents 786e946d d0d108bf
...@@ -117,7 +117,9 @@ public void CheckFailureRecovered() ...@@ -117,7 +117,9 @@ public void CheckFailureRecovered()
ClearAmbientFailures(); ClearAmbientFailures();
} }
} }
#endif
#endif
[Test] [Test]
public void TryGetAzureRoleInstanceIdNoThrow() public void TryGetAzureRoleInstanceIdNoThrow()
{ {
......
using System.Linq;
using NUnit.Framework;
namespace StackExchange.Redis.Tests
{
[TestFixture]
public class GeoTests : TestBase
{
[Test]
public void GeoAddEveryWay()
{
using (var conn = Create())
{
var db = conn.GetDatabase(3);
var added1 = db.GeoAdd("Sicily", 14.361389, 39.115556, "PalermoPlusOne");
var geo1 = new GeoEntry(13.361389, 38.115556, "Palermo");
var geo2 = new GeoEntry(15.087269, 37.502669, "Catania");
var added2 = db.GeoAdd("Sicily",new GeoEntry[] {geo1,geo2});
Assert.IsTrue(added1 & (added2==2));
}
}
[Test]
public void GetGeoDist()
{
using (var conn = Create())
{
var db = conn.GetDatabase(3);
var geo1 = new GeoEntry(13.361389, 38.115556, "Palermo");
var geo2 = new GeoEntry(15.087269, 37.502669, "Catania");
var added2 = db.GeoAdd("Sicily", new GeoEntry[] { geo1, geo2 });
var val = db.GeoDistance("Sicily", "Palermo", "Catania",GeoUnit.Meters);
Assert.Equals(166274.15156960039, (double) val);
}
}
}
}
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
/// <summary> /// <summary>
/// Behaviour markers associated with a given command /// Behaviour markers associated with a given command
/// </summary> /// </summary>
[Flags] [Flags]
......
using System;
namespace StackExchange.Redis
{
/// <summary>
/// GeoRadius command options.
/// </summary>
[Flags]
public enum GeoRadiusOptions
{
/// <summary>
/// No Options
/// </summary>
None = 0,
/// <summary>
/// Redis will return the coordinates of any results.
/// </summary>
WithCoordinates = 1,
/// <summary>
/// Redis will return the distance from center for all results.
/// </summary>
WithDistance = 2,
/// <summary>
/// Redis will return the geo hash value as an integer. (This is the score in the sorted set)
/// </summary>
WithGeoHash = 4
}
/// <summary>
/// The result of a GeoRadius command.
/// </summary>
public struct GeoRadiusResult
{
/// <summary>
/// The matched member.
/// </summary>
public RedisValue Member { get; }
/// <summary>
/// The original GeoRadius command
/// </summary>
public GeoRadius Command { get; }
/// <summary>
/// The distance of the matched member from the center of the geo radius command.
/// </summary>
public double? DistanceFromCenter { get; }
/// <summary>
/// The Geo Hash of the matched member as an integer. (The key in the sorted set)
/// </summary>
public long? GeoHash { get; }
/// <summary>
/// The coordinates of the matched member.
/// </summary>
public GeoPosition? GeoPosition { get; }
/// <summary>
/// Returns a new GeoRadiusResult
/// </summary>
public GeoRadiusResult(RedisValue member,GeoRadius command,double? distanceFromCenter,long? geoHash,GeoPosition? geoPosition)
{
Member = member;
Command = command;
DistanceFromCenter = distanceFromCenter;
GeoHash = geoHash;
GeoPosition = geoPosition;
}
}
/// <summary>
/// Represents a GeoRadius command and its options.
/// </summary>
public class GeoRadius
{
/// <summary>
/// The Radius size of this GeoRadius command.
/// </summary>
public double Radius { get; }
/// <summary>
/// The center point to base the search.
/// </summary>
public GeoPosition GeoPosition { get; }
/// <summary>
/// The key to use.
/// </summary>
public RedisKey Key { get; }
/// <summary>
/// The unit to return distance measurments in.
/// </summary>
public GeoUnit Unit { get; }
/// <summary>
/// The possible options for the GeoRadius command
/// </summary>
public GeoRadiusOptions GeoRadiusOptions { get; }
/// <summary>
/// The maximum number of results to return.
/// However note that internally the command needs to perform an effort proportional to the number of items matching the specified area, so to query very large areas with a very small COUNT option may be slow even if just a few results are returned.
/// </summary>
public int MaxReturnCount { get; }
/// <summary>
/// Creates a new GeoRadius
/// </summary>
public GeoRadius(RedisKey key,GeoPosition geoPosition,double radius,int maxReturnCount =-1,GeoUnit unit = GeoUnit.Meters,GeoRadiusOptions geoRadiusOptions = (GeoRadiusOptions.WithCoordinates | GeoRadiusOptions.WithDistance | GeoRadiusOptions.WithGeoHash))
{
Key = key;
GeoPosition = geoPosition;
Radius = radius;
Unit = unit;
GeoRadiusOptions = geoRadiusOptions;
MaxReturnCount = maxReturnCount;
}
public bool HasFlag(GeoRadiusOptions flag)
{
return (GeoRadiusOptions & flag) != 0;
}
}
/// <summary>
/// Describes the longitude and latitude of a GeoEntry
/// </summary>
public struct GeoPosition : IEquatable<GeoPosition>
{
/// <summary>
/// The Latitude of the GeoPosition
/// </summary>
public double Latitude { get; }
/// <summary>
/// The Logitude of the GeoPosition
/// </summary>
public double Longitude { get; }
/// <summary>
/// Creates a new GeoPosition
/// </summary>
/// <param name="longitude"></param>
/// <param name="latitude"></param>
public GeoPosition(double longitude,double latitude)
{
Longitude = longitude;
Latitude = latitude;
}
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
return string.Format("{0} {1}", Longitude, Latitude);
}
/// <summary>
/// See Object.GetHashCode()
/// Diagonals not an issue in the case of lat/long
/// </summary>
public override int GetHashCode()
{
// diagonals not an issue in the case of lat/long
return Longitude.GetHashCode() ^ Latitude.GetHashCode();
}
/// <summary>
/// Compares two values for equality
/// </summary>
public override bool Equals(object obj)
{
return obj is GeoPosition && Equals((GeoPosition)obj);
}
/// <summary>
/// Compares two values for equality
/// </summary>
public bool Equals(GeoPosition value)
{
return this == value;
}
/// <summary>
/// Compares two values for equality
/// </summary>
public static bool operator ==(GeoPosition x, GeoPosition y)
{
return x.Longitude == y.Longitude && x.Latitude == y.Latitude;
}
/// <summary>
/// Compares two values for non-equality
/// </summary>
public static bool operator !=(GeoPosition x, GeoPosition y)
{
return x.Longitude!= y.Longitude || x.Latitude != y.Latitude;
}
}
/// <summary>
/// Describes a GeoEntry element with the corresponding value
/// GeoEntries are stored in redis as SortedSetEntries
/// </summary>
public struct GeoEntry : IEquatable<GeoEntry>
{
/// <summary>
/// The name of the geo entry
/// </summary>
public string Member { get; }
/// <summary>
/// Describes the longitude and latitude of a GeoEntry
/// </summary>
public GeoPosition Point { get; }
/// <summary>
/// Initializes a GeoEntry value
/// </summary>
public GeoEntry(double longitude,double latitude,RedisValue member)
{
Member = member;
Point = new GeoPosition(longitude, latitude);
}
/// <summary>
/// The longitude of the geo entry
/// </summary>
public double Longitude => Point.Longitude;
/// <summary>
/// The latitude of the geo entry
/// </summary>
public double Latitude => Point.Latitude;
/// <summary>
/// See Object.ToString()
/// </summary>
public override string ToString()
{
return $"({Longitude},{Latitude})={Member}";
}
/// <summary>
/// See Object.GetHashCode()
/// </summary>
public override int GetHashCode()
{
return Point.GetHashCode() ^ Member.GetHashCode();
}
/// <summary>
/// Compares two values for equality
/// </summary>
public override bool Equals(object obj)
{
return obj is GeoEntry && Equals((GeoEntry)obj);
}
/// <summary>
/// Compares two values for equality
/// </summary>
public bool Equals(GeoEntry value)
{
return this == value;
}
/// <summary>
/// Compares two values for equality
/// </summary>
public static bool operator ==(GeoEntry x, GeoEntry y)
{
return Equals(x.Point, y.Point) && x.Member == y.Member;
}
/// <summary>
/// Compares two values for non-equality
/// </summary>
public static bool operator !=(GeoEntry x, GeoEntry y)
{
return !Equals(x.Point, y.Point) || x.Member != y.Member;
}
}
}
\ No newline at end of file
using System;
using System.ComponentModel;
namespace StackExchange.Redis
{
/// <summary>
/// Units associated with Geo Commands
/// </summary>
public enum GeoUnit
{
/// <summary>
/// Meters/Metres
/// </summary>
Meters,
/// <summary>
/// Kilometers/Kilometres
/// </summary>
Kilometers,
/// <summary>
/// Miles
/// </summary>
Miles,
/// <summary>
/// Feet
/// </summary>
Feet
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -27,6 +27,55 @@ public RedisValue DebugObject(RedisKey key, CommandFlags flags = CommandFlags.No ...@@ -27,6 +27,55 @@ public RedisValue DebugObject(RedisKey key, CommandFlags flags = CommandFlags.No
return Inner.DebugObject(ToInner(key), flags); return Inner.DebugObject(ToInner(key), flags);
} }
public bool GeoAdd(RedisKey key, double longitude, double latitude, RedisValue member, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoAdd(ToInner(key), longitude, latitude, member, flags);
}
public long GeoAdd(RedisKey key, GeoEntry[] geoEntries, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoAdd(ToInner(key), geoEntries, flags);
}
public bool GeoAdd(RedisKey key, GeoEntry geoEntry, RedisValue member, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoAdd(key, geoEntry, member, flags);
}
public bool GeoRemove(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoRemove(key, member, flags);
}
public double GeoDistance(RedisKey key, RedisValue value0, RedisValue value1, GeoUnit geoUnit = GeoUnit.Meters,CommandFlags flags = CommandFlags.None)
{
return Inner.GeoDistance(ToInner(key), value0, value1, geoUnit, flags);
}
public string[] GeoHash(RedisKey key, string[] members, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoHash(key, members, flags);
}
public string[] GeoHash(RedisKey key, string member, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoHash(key, member, flags);
}
public GeoPosition?[] GeoPos(RedisKey key, string[] members, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoPos(key, members, flags);
}
public GeoPosition? GeoPos(RedisKey key, string member, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoPos(key, member, flags);
}
public GeoRadiusResult[] GeoRadius(RedisKey key, GeoRadius geoRadius, CommandFlags flags = CommandFlags.None)
{
return Inner.GeoRadius(key, geoRadius, flags);
}
public double HashDecrement(RedisKey key, RedisValue hashField, double value, CommandFlags flags = CommandFlags.None) public double HashDecrement(RedisKey key, RedisValue hashField, double value, CommandFlags flags = CommandFlags.None)
{ {
return Inner.HashDecrement(ToInner(key), hashField, value, flags); return Inner.HashDecrement(ToInner(key), hashField, value, flags);
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
using System.Runtime.Serialization; using System.Runtime.Serialization;
#endif #endif
using System.Text; using System.Text;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
/// <summary> /// <summary>
/// Indicates that a command was illegal and was not sent to the server /// Indicates that a command was illegal and was not sent to the server
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
[Serializable] [Serializable]
#endif #endif
public sealed class RedisCommandException : Exception public sealed class RedisCommandException : Exception
{ {
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
private RedisCommandException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { } private RedisCommandException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif #endif
internal RedisCommandException(string message) : base(message) { } internal RedisCommandException(string message) : base(message) { }
internal RedisCommandException(string message, Exception innerException) : base(message, innerException) { } internal RedisCommandException(string message, Exception innerException) : base(message, innerException) { }
} }
/// <summary> /// <summary>
/// Indicates a connection fault when communicating with redis /// Indicates a connection fault when communicating with redis
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
[Serializable] [Serializable]
#endif #endif
public sealed class RedisConnectionException : RedisException public sealed class RedisConnectionException : RedisException
{ {
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
private RedisConnectionException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) private RedisConnectionException(SerializationInfo info, StreamingContext ctx) : base(info, ctx)
{ {
FailureType = (ConnectionFailureType)info.GetInt32("failureType"); FailureType = (ConnectionFailureType)info.GetInt32("failureType");
} }
/// <summary> /// <summary>
/// Serialization implementation; not intended for general usage /// Serialization implementation; not intended for general usage
/// </summary> /// </summary>
public override void GetObjectData(SerializationInfo info, StreamingContext context) public override void GetObjectData(SerializationInfo info, StreamingContext context)
{ {
base.GetObjectData(info, context); base.GetObjectData(info, context);
info.AddValue("failureType", (int)FailureType); info.AddValue("failureType", (int)FailureType);
} }
#endif #endif
internal RedisConnectionException(ConnectionFailureType failureType, string message) : base(message) internal RedisConnectionException(ConnectionFailureType failureType, string message) : base(message)
{ {
FailureType = failureType; FailureType = failureType;
} }
internal RedisConnectionException(ConnectionFailureType failureType, string message, Exception innerException) : base(message, innerException) internal RedisConnectionException(ConnectionFailureType failureType, string message, Exception innerException) : base(message, innerException)
{ {
FailureType = failureType; FailureType = failureType;
} }
/// <summary> /// <summary>
/// The type of connection failure /// The type of connection failure
/// </summary> /// </summary>
public ConnectionFailureType FailureType { get; } public ConnectionFailureType FailureType { get; }
} }
/// <summary> /// <summary>
/// Indicates an issue communicating with redis /// Indicates an issue communicating with redis
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
[Serializable] [Serializable]
#endif #endif
public class RedisException : Exception public class RedisException : Exception
{ {
/// <summary> /// <summary>
/// Deserialization constructor; not intended for general usage /// Deserialization constructor; not intended for general usage
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
protected RedisException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { } protected RedisException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif #endif
internal RedisException(string message) : base(message) { } internal RedisException(string message) : base(message) { }
internal RedisException(string message, Exception innerException) : base(message, innerException) { } internal RedisException(string message, Exception innerException) : base(message, innerException) { }
} }
/// <summary> /// <summary>
/// Indicates an exception raised by a redis server /// Indicates an exception raised by a redis server
/// </summary> /// </summary>
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
[Serializable] [Serializable]
#endif #endif
public sealed class RedisServerException : RedisException public sealed class RedisServerException : RedisException
{ {
#if FEATURE_SERIALIZATION #if FEATURE_SERIALIZATION
private RedisServerException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { } private RedisServerException(SerializationInfo info, StreamingContext ctx) : base(info, ctx) { }
#endif #endif
internal RedisServerException(string message) : base(message) { } internal RedisServerException(string message) : base(message) { }
} }
sealed class LoggingMessage : Message sealed class LoggingMessage : Message
{ {
public readonly TextWriter log; public readonly TextWriter log;
private readonly Message tail; private readonly Message tail;
public static Message Create(TextWriter log, Message tail) public static Message Create(TextWriter log, Message tail)
{ {
return log == null ? tail : new LoggingMessage(log, tail); return log == null ? tail : new LoggingMessage(log, tail);
} }
private LoggingMessage(TextWriter log, Message tail) : base(tail.Db, tail.Flags, tail.Command) private LoggingMessage(TextWriter log, Message tail) : base(tail.Db, tail.Flags, tail.Command)
{ {
this.log = log; this.log = log;
this.tail = tail; this.tail = tail;
FlagsRaw = tail.FlagsRaw; FlagsRaw = tail.FlagsRaw;
} }
public override string CommandAndKey => tail.CommandAndKey; public override string CommandAndKey => tail.CommandAndKey;
public override void AppendStormLog(StringBuilder sb) public override void AppendStormLog(StringBuilder sb)
{ {
tail.AppendStormLog(sb); tail.AppendStormLog(sb);
} }
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
{ {
return tail.GetHashSlot(serverSelectionStrategy); return tail.GetHashSlot(serverSelectionStrategy);
} }
internal override void WriteImpl(PhysicalConnection physical) internal override void WriteImpl(PhysicalConnection physical)
{ {
try try
{ {
physical.Multiplexer.LogLocked(log, "Writing to {0}: {1}", physical.Bridge, tail.CommandAndKey); physical.Multiplexer.LogLocked(log, "Writing to {0}: {1}", physical.Bridge, tail.CommandAndKey);
} }
catch { } catch { }
tail.WriteImpl(physical); tail.WriteImpl(physical);
} }
public TextWriter Log => log; public TextWriter Log => log;
} }
abstract class Message : ICompletable abstract class Message : ICompletable
{ {
public static readonly Message[] EmptyArray = new Message[0]; public static readonly Message[] EmptyArray = new Message[0];
public readonly int Db; public readonly int Db;
internal const CommandFlags InternalCallFlag = (CommandFlags)128; internal const CommandFlags InternalCallFlag = (CommandFlags)128;
protected RedisCommand command; protected RedisCommand command;
private const CommandFlags AskingFlag = (CommandFlags)32, private const CommandFlags AskingFlag = (CommandFlags)32,
ScriptUnavailableFlag = (CommandFlags)256; ScriptUnavailableFlag = (CommandFlags)256;
const CommandFlags MaskMasterServerPreference = CommandFlags.DemandMaster | CommandFlags.DemandSlave | CommandFlags.PreferMaster | CommandFlags.PreferSlave; const CommandFlags MaskMasterServerPreference = CommandFlags.DemandMaster | CommandFlags.DemandSlave | CommandFlags.PreferMaster | CommandFlags.PreferSlave;
private const CommandFlags UserSelectableFlags private const CommandFlags UserSelectableFlags
= CommandFlags.None | CommandFlags.DemandMaster | CommandFlags.DemandSlave = CommandFlags.None | CommandFlags.DemandMaster | CommandFlags.DemandSlave
| CommandFlags.PreferMaster | CommandFlags.PreferSlave | CommandFlags.PreferMaster | CommandFlags.PreferSlave
| CommandFlags.HighPriority | CommandFlags.FireAndForget | CommandFlags.NoRedirect; | CommandFlags.HighPriority | CommandFlags.FireAndForget | CommandFlags.NoRedirect;
private CommandFlags flags; private CommandFlags flags;
internal CommandFlags FlagsRaw { get { return flags; } set { flags = value; } } internal CommandFlags FlagsRaw { get { return flags; } set { flags = value; } }
private ResultBox resultBox; private ResultBox resultBox;
private ResultProcessor resultProcessor; private ResultProcessor resultProcessor;
// All for profiling purposes // All for profiling purposes
private ProfileStorage performance; private ProfileStorage performance;
internal DateTime createdDateTime; internal DateTime createdDateTime;
internal long createdTimestamp; internal long createdTimestamp;
protected Message(int db, CommandFlags flags, RedisCommand command) protected Message(int db, CommandFlags flags, RedisCommand command)
{ {
bool dbNeeded = RequiresDatabase(command); bool dbNeeded = RequiresDatabase(command);
if (db < 0) if (db < 0)
{ {
if (dbNeeded) if (dbNeeded)
{ {
throw ExceptionFactory.DatabaseRequired(false, command); throw ExceptionFactory.DatabaseRequired(false, command);
} }
} }
else else
{ {
if (!dbNeeded) if (!dbNeeded)
{ {
throw ExceptionFactory.DatabaseNotRequired(false, command); throw ExceptionFactory.DatabaseNotRequired(false, command);
} }
} }
bool masterOnly = IsMasterOnly(command); bool masterOnly = IsMasterOnly(command);
Db = db; Db = db;
this.command = command; this.command = command;
this.flags = flags & UserSelectableFlags; this.flags = flags & UserSelectableFlags;
if (masterOnly) SetMasterOnly(); if (masterOnly) SetMasterOnly();
...@@ -216,8 +216,8 @@ internal void SetProfileStorage(ProfileStorage storage) ...@@ -216,8 +216,8 @@ internal void SetProfileStorage(ProfileStorage storage)
{ {
performance = storage; performance = storage;
performance.SetMessage(this); performance.SetMessage(this);
} }
internal void PrepareToResend(ServerEndPoint resendTo, bool isMoved) internal void PrepareToResend(ServerEndPoint resendTo, bool isMoved)
{ {
if (performance == null) return; if (performance == null) return;
...@@ -231,269 +231,281 @@ internal void PrepareToResend(ServerEndPoint resendTo, bool isMoved) ...@@ -231,269 +231,281 @@ internal void PrepareToResend(ServerEndPoint resendTo, bool isMoved)
createdTimestamp = System.Diagnostics.Stopwatch.GetTimestamp(); createdTimestamp = System.Diagnostics.Stopwatch.GetTimestamp();
performance = ProfileStorage.NewAttachedToSameContext(oldPerformance, resendTo, isMoved); performance = ProfileStorage.NewAttachedToSameContext(oldPerformance, resendTo, isMoved);
performance.SetMessage(this); performance.SetMessage(this);
} }
public RedisCommand Command => command; public RedisCommand Command => command;
public virtual string CommandAndKey => Command.ToString(); public virtual string CommandAndKey => Command.ToString();
public CommandFlags Flags => flags; public CommandFlags Flags => flags;
/// <summary> /// <summary>
/// Things with the potential to cause harm, or to reveal configuration information /// Things with the potential to cause harm, or to reveal configuration information
/// </summary> /// </summary>
public bool IsAdmin public bool IsAdmin
{ {
get get
{ {
switch (Command) switch (Command)
{ {
case RedisCommand.BGREWRITEAOF: case RedisCommand.BGREWRITEAOF:
case RedisCommand.BGSAVE: case RedisCommand.BGSAVE:
case RedisCommand.CLIENT: case RedisCommand.CLIENT:
case RedisCommand.CLUSTER: case RedisCommand.CLUSTER:
case RedisCommand.CONFIG: case RedisCommand.CONFIG:
case RedisCommand.DEBUG: case RedisCommand.DEBUG:
case RedisCommand.FLUSHALL: case RedisCommand.FLUSHALL:
case RedisCommand.FLUSHDB: case RedisCommand.FLUSHDB:
case RedisCommand.INFO: case RedisCommand.INFO:
case RedisCommand.KEYS: case RedisCommand.KEYS:
case RedisCommand.MONITOR: case RedisCommand.MONITOR:
case RedisCommand.SAVE: case RedisCommand.SAVE:
case RedisCommand.SHUTDOWN: case RedisCommand.SHUTDOWN:
case RedisCommand.SLAVEOF: case RedisCommand.SLAVEOF:
case RedisCommand.SLOWLOG: case RedisCommand.SLOWLOG:
case RedisCommand.SYNC: case RedisCommand.SYNC:
return true; return true;
default: default:
return false; return false;
} }
} }
} }
public bool IsAsking => (flags & AskingFlag) != 0; public bool IsAsking => (flags & AskingFlag) != 0;
internal bool IsScriptUnavailable => (flags & ScriptUnavailableFlag) != 0; internal bool IsScriptUnavailable => (flags & ScriptUnavailableFlag) != 0;
internal void SetScriptUnavailable() internal void SetScriptUnavailable()
{ {
flags |= ScriptUnavailableFlag; flags |= ScriptUnavailableFlag;
} }
public bool IsFireAndForget => (flags & CommandFlags.FireAndForget) != 0; public bool IsFireAndForget => (flags & CommandFlags.FireAndForget) != 0;
public bool IsHighPriority => (flags & CommandFlags.HighPriority) != 0; public bool IsHighPriority => (flags & CommandFlags.HighPriority) != 0;
public bool IsInternalCall => (flags & InternalCallFlag) != 0; public bool IsInternalCall => (flags & InternalCallFlag) != 0;
public ResultBox ResultBox => resultBox; public ResultBox ResultBox => resultBox;
public static Message Create(int db, CommandFlags flags, RedisCommand command) public static Message Create(int db, CommandFlags flags, RedisCommand command)
{ {
if (command == RedisCommand.SELECT) if (command == RedisCommand.SELECT)
return new SelectMessage(db, flags); return new SelectMessage(db, flags);
return new CommandMessage(db, flags, command); return new CommandMessage(db, flags, command);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key)
{ {
return new CommandKeyMessage(db, flags, command, key); return new CommandKeyMessage(db, flags, command, key);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1)
{ {
return new CommandKeyKeyMessage(db, flags, command, key0, key1); return new CommandKeyKeyMessage(db, flags, command, key0, key1);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1, RedisValue value) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1, RedisValue value)
{ {
return new CommandKeyKeyValueMessage(db, flags, command, key0, key1, value); return new CommandKeyKeyValueMessage(db, flags, command, key0, key1, value);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1, RedisKey key2) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1, RedisKey key2)
{ {
return new CommandKeyKeyKeyMessage(db, flags, command, key0, key1, key2); return new CommandKeyKeyKeyMessage(db, flags, command, key0, key1, key2);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value)
{ {
return new CommandValueMessage(db, flags, command, value); return new CommandValueMessage(db, flags, command, value);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value)
{ {
return new CommandKeyValueMessage(db, flags, command, key, value); return new CommandKeyValueMessage(db, flags, command, key, value);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisChannel channel) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisChannel channel)
{ {
return new CommandChannelMessage(db, flags, command, channel); return new CommandChannelMessage(db, flags, command, channel);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisChannel channel, RedisValue value) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisChannel channel, RedisValue value)
{ {
return new CommandChannelValueMessage(db, flags, command, channel, value); return new CommandChannelValueMessage(db, flags, command, channel, value);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value, RedisChannel channel) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value, RedisChannel channel)
{ {
return new CommandValueChannelMessage(db, flags, command, value, channel); return new CommandValueChannelMessage(db, flags, command, value, channel);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1)
{ {
return new CommandKeyValueValueMessage(db, flags, command, key, value0, value1); return new CommandKeyValueValueMessage(db, flags, command, key, value0, value1);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1, RedisValue value2) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1, RedisValue value2)
{ {
return new CommandKeyValueValueValueMessage(db, flags, command, key, value0, value1, value2); return new CommandKeyValueValueValueMessage(db, flags, command, key, value0, value1, value2);
} }
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1, RedisValue value2, RedisValue value3) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, GeoEntry[] values)
{ {
return new CommandKeyValueValueValueValueMessage(db, flags, command, key, value0, value1, value2, value3); var redisValues = new List<RedisValue>();
} foreach (var value in values)
{
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1) redisValues.Add(value.Point.Longitude);
{ redisValues.Add(value.Point.Latitude);
return new CommandValueValueMessage(db, flags, command, value0, value1); redisValues.Add(value.Member);
} }
return new CommandKeyValuesMessage(db,flags,command,key,redisValues.ToArray());
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value, RedisKey key) }
{
return new CommandValueKeyMessage(db, flags, command, value, key); public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1, RedisValue value2, RedisValue value3)
} {
return new CommandKeyValueValueValueValueMessage(db, flags, command, key, value0, value1, value2, value3);
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1, RedisValue value2) }
{
return new CommandValueValueValueMessage(db, flags, command, value0, value1, value2); public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1)
} {
return new CommandValueValueMessage(db, flags, command, value0, value1);
public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1, RedisValue value2, RedisValue value3, RedisValue value4) }
{
return new CommandValueValueValueValueValueMessage(db, flags, command, value0, value1, value2, value3, value4); public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value, RedisKey key)
} {
return new CommandValueKeyMessage(db, flags, command, value, key);
public static Message CreateInSlot(int db, int slot, CommandFlags flags, RedisCommand command, RedisValue[] values) }
{
return new CommandSlotValuesMessage(db, slot, flags, command, values); public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1, RedisValue value2)
} {
return new CommandValueValueValueMessage(db, flags, command, value0, value1, value2);
public static bool IsMasterOnly(RedisCommand command) }
{
switch (command) public static Message Create(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1, RedisValue value2, RedisValue value3, RedisValue value4)
{ {
case RedisCommand.APPEND: return new CommandValueValueValueValueValueMessage(db, flags, command, value0, value1, value2, value3, value4);
case RedisCommand.BITOP: }
case RedisCommand.BLPOP:
case RedisCommand.BRPOP: public static Message CreateInSlot(int db, int slot, CommandFlags flags, RedisCommand command, RedisValue[] values)
case RedisCommand.BRPOPLPUSH: {
case RedisCommand.DECR: return new CommandSlotValuesMessage(db, slot, flags, command, values);
case RedisCommand.DECRBY: }
case RedisCommand.DEL:
case RedisCommand.EXPIRE: public static bool IsMasterOnly(RedisCommand command)
case RedisCommand.EXPIREAT: {
case RedisCommand.FLUSHALL: switch (command)
case RedisCommand.FLUSHDB: {
case RedisCommand.GETSET: case RedisCommand.APPEND:
case RedisCommand.HDEL: case RedisCommand.BITOP:
case RedisCommand.HINCRBY: case RedisCommand.BLPOP:
case RedisCommand.HINCRBYFLOAT: case RedisCommand.BRPOP:
case RedisCommand.HMSET: case RedisCommand.BRPOPLPUSH:
case RedisCommand.HSET: case RedisCommand.DECR:
case RedisCommand.HSETNX: case RedisCommand.DECRBY:
case RedisCommand.INCR: case RedisCommand.DEL:
case RedisCommand.INCRBY: case RedisCommand.EXPIRE:
case RedisCommand.INCRBYFLOAT: case RedisCommand.EXPIREAT:
case RedisCommand.LINSERT: case RedisCommand.FLUSHALL:
case RedisCommand.LPOP: case RedisCommand.FLUSHDB:
case RedisCommand.LPUSH: case RedisCommand.GETSET:
case RedisCommand.LPUSHX: case RedisCommand.HDEL:
case RedisCommand.LREM: case RedisCommand.HINCRBY:
case RedisCommand.LSET: case RedisCommand.HINCRBYFLOAT:
case RedisCommand.LTRIM: case RedisCommand.HMSET:
case RedisCommand.MIGRATE: case RedisCommand.HSET:
case RedisCommand.MOVE: case RedisCommand.HSETNX:
case RedisCommand.MSET: case RedisCommand.INCR:
case RedisCommand.MSETNX: case RedisCommand.INCRBY:
case RedisCommand.PERSIST: case RedisCommand.INCRBYFLOAT:
case RedisCommand.PEXPIRE: case RedisCommand.LINSERT:
case RedisCommand.PEXPIREAT: case RedisCommand.LPOP:
case RedisCommand.PFADD: case RedisCommand.LPUSH:
case RedisCommand.PFMERGE: case RedisCommand.LPUSHX:
case RedisCommand.PSETEX: case RedisCommand.LREM:
case RedisCommand.RENAME: case RedisCommand.LSET:
case RedisCommand.RENAMENX: case RedisCommand.LTRIM:
case RedisCommand.RESTORE: case RedisCommand.MIGRATE:
case RedisCommand.RPOP: case RedisCommand.MOVE:
case RedisCommand.RPOPLPUSH: case RedisCommand.MSET:
case RedisCommand.RPUSH: case RedisCommand.MSETNX:
case RedisCommand.RPUSHX: case RedisCommand.PERSIST:
case RedisCommand.SADD: case RedisCommand.PEXPIRE:
case RedisCommand.SDIFFSTORE: case RedisCommand.PEXPIREAT:
case RedisCommand.SET: case RedisCommand.PFADD:
case RedisCommand.SETBIT: case RedisCommand.PFMERGE:
case RedisCommand.SETEX: case RedisCommand.PSETEX:
case RedisCommand.SETNX: case RedisCommand.RENAME:
case RedisCommand.SETRANGE: case RedisCommand.RENAMENX:
case RedisCommand.SINTERSTORE: case RedisCommand.RESTORE:
case RedisCommand.SMOVE: case RedisCommand.RPOP:
case RedisCommand.SPOP: case RedisCommand.RPOPLPUSH:
case RedisCommand.SREM: case RedisCommand.RPUSH:
case RedisCommand.SUNIONSTORE: case RedisCommand.RPUSHX:
case RedisCommand.ZADD: case RedisCommand.SADD:
case RedisCommand.ZINTERSTORE: case RedisCommand.SDIFFSTORE:
case RedisCommand.ZINCRBY: case RedisCommand.SET:
case RedisCommand.ZREM: case RedisCommand.SETBIT:
case RedisCommand.ZREMRANGEBYLEX: case RedisCommand.SETEX:
case RedisCommand.ZREMRANGEBYRANK: case RedisCommand.SETNX:
case RedisCommand.ZREMRANGEBYSCORE: case RedisCommand.SETRANGE:
case RedisCommand.ZUNIONSTORE: case RedisCommand.SINTERSTORE:
return true; case RedisCommand.SMOVE:
default: case RedisCommand.SPOP:
return false; case RedisCommand.SREM:
} case RedisCommand.SUNIONSTORE:
} case RedisCommand.ZADD:
case RedisCommand.ZINTERSTORE:
public virtual void AppendStormLog(StringBuilder sb) case RedisCommand.ZINCRBY:
{ case RedisCommand.ZREM:
if (Db >= 0) sb.Append(Db).Append(':'); case RedisCommand.ZREMRANGEBYLEX:
sb.Append(CommandAndKey); case RedisCommand.ZREMRANGEBYRANK:
} case RedisCommand.ZREMRANGEBYSCORE:
public virtual int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) { return ServerSelectionStrategy.NoSlot; } case RedisCommand.ZUNIONSTORE:
public bool IsMasterOnly() return true;
{ default:
// note that the constructor runs the switch statement above, so return false;
// this will alread be true for master-only commands, even if the }
// user specified PreferMaster etc }
return GetMasterSlaveFlags(flags) == CommandFlags.DemandMaster;
} public virtual void AppendStormLog(StringBuilder sb)
{
/// <summary> if (Db >= 0) sb.Append(Db).Append(':');
/// This does a few important things: sb.Append(CommandAndKey);
/// 1: it suppresses error events for commands that the user isn't interested in }
/// (i.e. "why does my standalone server keep saying ERR unknown command 'cluster' ?") public virtual int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) { return ServerSelectionStrategy.NoSlot; }
/// 2: it allows the initial PING and GET (during connect) to get queued rather public bool IsMasterOnly()
/// than be rejected as no-server-available (note that this doesn't apply to {
/// handshake messages, as they bypass the queue completely) // note that the constructor runs the switch statement above, so
/// 3: it disables non-pref logging, as it is usually server-targeted // this will alread be true for master-only commands, even if the
/// </summary> // user specified PreferMaster etc
public void SetInternalCall() return GetMasterSlaveFlags(flags) == CommandFlags.DemandMaster;
{ }
flags |= InternalCallFlag;
} /// <summary>
/// This does a few important things:
public override string ToString() /// 1: it suppresses error events for commands that the user isn't interested in
{ /// (i.e. "why does my standalone server keep saying ERR unknown command 'cluster' ?")
return $"[{Db}]:{CommandAndKey} ({resultProcessor?.GetType().Name ?? "(n/a)"})"; /// 2: it allows the initial PING and GET (during connect) to get queued rather
} /// than be rejected as no-server-available (note that this doesn't apply to
/// handshake messages, as they bypass the queue completely)
public void SetResponseReceived() /// 3: it disables non-pref logging, as it is usually server-targeted
{ /// </summary>
performance?.SetResponseReceived(); public void SetInternalCall()
} {
flags |= InternalCallFlag;
}
public override string ToString()
{
return $"[{Db}]:{CommandAndKey} ({resultProcessor?.GetType().Name ?? "(n/a)"})";
}
public void SetResponseReceived()
{
performance?.SetResponseReceived();
}
public bool TryComplete(bool isAsync) public bool TryComplete(bool isAsync)
{ {
//Ensure we can never call TryComplete on the same resultBox from two threads by grabbing it now //Ensure we can never call TryComplete on the same resultBox from two threads by grabbing it now
...@@ -507,719 +519,733 @@ public bool TryComplete(bool isAsync) ...@@ -507,719 +519,733 @@ public bool TryComplete(bool isAsync)
{ {
//put result box back if it was not already recycled //put result box back if it was not already recycled
Interlocked.Exchange(ref resultBox, currBox); Interlocked.Exchange(ref resultBox, currBox);
} }
performance?.SetCompleted(); performance?.SetCompleted();
return ret; return ret;
} }
else else
{ {
ConnectionMultiplexer.TraceWithoutContext("No result-box to complete for " + Command, "Message"); ConnectionMultiplexer.TraceWithoutContext("No result-box to complete for " + Command, "Message");
performance?.SetCompleted(); performance?.SetCompleted();
return true; return true;
} }
} }
internal static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisKey[] keys) internal static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisKey[] keys)
{ {
switch (keys.Length) switch (keys.Length)
{ {
case 0: return new CommandKeyMessage(db, flags, command, key); case 0: return new CommandKeyMessage(db, flags, command, key);
case 1: return new CommandKeyKeyMessage(db, flags, command, key, keys[0]); case 1: return new CommandKeyKeyMessage(db, flags, command, key, keys[0]);
case 2: return new CommandKeyKeyKeyMessage(db, flags, command, key, keys[0], keys[1]); case 2: return new CommandKeyKeyKeyMessage(db, flags, command, key, keys[0], keys[1]);
default: return new CommandKeyKeysMessage(db, flags, command, key, keys); default: return new CommandKeyKeysMessage(db, flags, command, key, keys);
} }
} }
internal static Message Create(int db, CommandFlags flags, RedisCommand command, IList<RedisKey> keys) internal static Message Create(int db, CommandFlags flags, RedisCommand command, IList<RedisKey> keys)
{ {
switch (keys.Count) switch (keys.Count)
{ {
case 0: return new CommandMessage(db, flags, command); case 0: return new CommandMessage(db, flags, command);
case 1: return new CommandKeyMessage(db, flags, command, keys[0]); case 1: return new CommandKeyMessage(db, flags, command, keys[0]);
case 2: return new CommandKeyKeyMessage(db, flags, command, keys[0], keys[1]); case 2: return new CommandKeyKeyMessage(db, flags, command, keys[0], keys[1]);
case 3: return new CommandKeyKeyKeyMessage(db, flags, command, keys[0], keys[1], keys[2]); case 3: return new CommandKeyKeyKeyMessage(db, flags, command, keys[0], keys[1], keys[2]);
default: return new CommandKeysMessage(db, flags, command, (keys as RedisKey[]) ?? keys.ToArray()); default: return new CommandKeysMessage(db, flags, command, (keys as RedisKey[]) ?? keys.ToArray());
} }
} }
internal static Message Create(int db, CommandFlags flags, RedisCommand command, IList<RedisValue> values) internal static Message Create(int db, CommandFlags flags, RedisCommand command, IList<RedisValue> values)
{ {
switch (values.Count) switch (values.Count)
{ {
case 0: return new CommandMessage(db, flags, command); case 0: return new CommandMessage(db, flags, command);
case 1: return new CommandValueMessage(db, flags, command, values[0]); case 1: return new CommandValueMessage(db, flags, command, values[0]);
case 2: return new CommandValueValueMessage(db, flags, command, values[0], values[1]); case 2: return new CommandValueValueMessage(db, flags, command, values[0], values[1]);
case 3: return new CommandValueValueValueMessage(db, flags, command, values[0], values[1], values[2]); case 3: return new CommandValueValueValueMessage(db, flags, command, values[0], values[1], values[2]);
// no 4; not worth adding // no 4; not worth adding
case 5: return new CommandValueValueValueValueValueMessage(db, flags, command, values[0], values[1], values[2], values[3], values[4]); case 5: return new CommandValueValueValueValueValueMessage(db, flags, command, values[0], values[1], values[2], values[3], values[4]);
default: return new CommandValuesMessage(db, flags, command, (values as RedisValue[]) ?? values.ToArray()); default: return new CommandValuesMessage(db, flags, command, (values as RedisValue[]) ?? values.ToArray());
} }
} }
internal static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue[] values) internal static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue[] values)
{ {
if (values == null) throw new ArgumentNullException(nameof(values)); if (values == null) throw new ArgumentNullException(nameof(values));
switch (values.Length) switch (values.Length)
{ {
case 0: return new CommandKeyMessage(db, flags, command, key); case 0: return new CommandKeyMessage(db, flags, command, key);
case 1: return new CommandKeyValueMessage(db, flags, command, key, values[0]); case 1: return new CommandKeyValueMessage(db, flags, command, key, values[0]);
case 2: return new CommandKeyValueValueMessage(db, flags, command, key, values[0], values[1]); case 2: return new CommandKeyValueValueMessage(db, flags, command, key, values[0], values[1]);
case 3: return new CommandKeyValueValueValueMessage(db, flags, command, key, values[0], values[1], values[2]); case 3: return new CommandKeyValueValueValueMessage(db, flags, command, key, values[0], values[1], values[2]);
case 4: return new CommandKeyValueValueValueValueMessage(db, flags, command, key, values[0], values[1], values[2], values[3]); case 4: return new CommandKeyValueValueValueValueMessage(db, flags, command, key, values[0], values[1], values[2], values[3]);
default: return new CommandKeyValuesMessage(db, flags, command, key, values); default: return new CommandKeyValuesMessage(db, flags, command, key, values);
} }
} }
internal static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisValue[] values, RedisKey key1) internal static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue[] values,GeoRadius geoRadius)
{ {
if (values == null) throw new ArgumentNullException(nameof(values)); if (values == null) throw new ArgumentNullException(nameof(values));
return new CommandKeyValuesKeyMessage(db, flags, command, key0, values, key1); switch (values.Length)
} {
case 0: return new CommandKeyMessage(db, flags, command, key);
internal static CommandFlags GetMasterSlaveFlags(CommandFlags flags) case 1: return new CommandKeyValueMessage(db, flags, command, key, values[0]);
{ case 2: return new CommandKeyValueValueMessage(db, flags, command, key, values[0], values[1]);
// for the purposes of the switch, we only care about two bits case 3: return new CommandKeyValueValueValueMessage(db, flags, command, key, values[0], values[1], values[2]);
return flags & MaskMasterServerPreference; case 4: return new CommandKeyValueValueValueValueMessage(db, flags, command, key, values[0], values[1], values[2], values[3]);
} default: return new CommandKeyValuesMessage(db, flags, command, key, values);
internal static bool RequiresDatabase(RedisCommand command) }
{ }
switch (command)
{ internal static Message Create(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisValue[] values, RedisKey key1)
case RedisCommand.ASKING: {
case RedisCommand.AUTH: if (values == null) throw new ArgumentNullException(nameof(values));
case RedisCommand.BGREWRITEAOF: return new CommandKeyValuesKeyMessage(db, flags, command, key0, values, key1);
case RedisCommand.BGSAVE: }
case RedisCommand.CLIENT:
case RedisCommand.CLUSTER: internal static CommandFlags GetMasterSlaveFlags(CommandFlags flags)
case RedisCommand.CONFIG: {
case RedisCommand.DISCARD: // for the purposes of the switch, we only care about two bits
case RedisCommand.ECHO: return flags & MaskMasterServerPreference;
case RedisCommand.FLUSHALL: }
case RedisCommand.INFO: internal static bool RequiresDatabase(RedisCommand command)
case RedisCommand.LASTSAVE: {
case RedisCommand.MONITOR: switch (command)
case RedisCommand.MULTI: {
case RedisCommand.PING: case RedisCommand.ASKING:
case RedisCommand.PUBLISH: case RedisCommand.AUTH:
case RedisCommand.PUBSUB: case RedisCommand.BGREWRITEAOF:
case RedisCommand.PUNSUBSCRIBE: case RedisCommand.BGSAVE:
case RedisCommand.PSUBSCRIBE: case RedisCommand.CLIENT:
case RedisCommand.QUIT: case RedisCommand.CLUSTER:
case RedisCommand.READONLY: case RedisCommand.CONFIG:
case RedisCommand.READWRITE: case RedisCommand.DISCARD:
case RedisCommand.SAVE: case RedisCommand.ECHO:
case RedisCommand.SCRIPT: case RedisCommand.FLUSHALL:
case RedisCommand.SHUTDOWN: case RedisCommand.INFO:
case RedisCommand.SLAVEOF: case RedisCommand.LASTSAVE:
case RedisCommand.SLOWLOG: case RedisCommand.MONITOR:
case RedisCommand.SUBSCRIBE: case RedisCommand.MULTI:
case RedisCommand.SYNC: case RedisCommand.PING:
case RedisCommand.TIME: case RedisCommand.PUBLISH:
case RedisCommand.UNSUBSCRIBE: case RedisCommand.PUBSUB:
case RedisCommand.SENTINEL: case RedisCommand.PUNSUBSCRIBE:
return false; case RedisCommand.PSUBSCRIBE:
default: case RedisCommand.QUIT:
return true; case RedisCommand.READONLY:
} case RedisCommand.READWRITE:
} case RedisCommand.SAVE:
case RedisCommand.SCRIPT:
internal static CommandFlags SetMasterSlaveFlags(CommandFlags everything, CommandFlags masterSlave) case RedisCommand.SHUTDOWN:
{ case RedisCommand.SLAVEOF:
// take away the two flags we don't want, and add back the ones we care about case RedisCommand.SLOWLOG:
return (everything & ~(CommandFlags.DemandMaster | CommandFlags.DemandSlave | CommandFlags.PreferMaster | CommandFlags.PreferSlave)) case RedisCommand.SUBSCRIBE:
| masterSlave; case RedisCommand.SYNC:
} case RedisCommand.TIME:
case RedisCommand.UNSUBSCRIBE:
internal void Cancel() case RedisCommand.SENTINEL:
{ return false;
resultProcessor?.SetException(this, new TaskCanceledException()); default:
} return true;
}
// true if ready to be completed (i.e. false if re-issued to another server) }
internal bool ComputeResult(PhysicalConnection connection, RawResult result)
{ internal static CommandFlags SetMasterSlaveFlags(CommandFlags everything, CommandFlags masterSlave)
return resultProcessor == null || resultProcessor.SetResult(connection, this, result); {
} // take away the two flags we don't want, and add back the ones we care about
return (everything & ~(CommandFlags.DemandMaster | CommandFlags.DemandSlave | CommandFlags.PreferMaster | CommandFlags.PreferSlave))
internal void Fail(ConnectionFailureType failure, Exception innerException) | masterSlave;
{ }
PhysicalConnection.IdentifyFailureType(innerException, ref failure);
resultProcessor?.ConnectionFail(this, failure, innerException); internal void Cancel()
} {
resultProcessor?.SetException(this, new TaskCanceledException());
internal void SetEnqueued() }
{
performance?.SetEnqueued(); // true if ready to be completed (i.e. false if re-issued to another server)
} internal bool ComputeResult(PhysicalConnection connection, RawResult result)
{
internal void SetRequestSent() return resultProcessor == null || resultProcessor.SetResult(connection, this, result);
{ }
performance?.SetRequestSent();
} internal void Fail(ConnectionFailureType failure, Exception innerException)
{
internal void SetAsking(bool value) PhysicalConnection.IdentifyFailureType(innerException, ref failure);
{ resultProcessor?.ConnectionFail(this, failure, innerException);
if (value) flags |= AskingFlag; // the bits giveth }
else flags &= ~AskingFlag; // and the bits taketh away
} internal void SetEnqueued()
{
internal void SetNoRedirect() performance?.SetEnqueued();
{ }
flags |= CommandFlags.NoRedirect;
} internal void SetRequestSent()
{
internal void SetPreferMaster() performance?.SetRequestSent();
{ }
flags = (flags & ~MaskMasterServerPreference) | CommandFlags.PreferMaster;
} internal void SetAsking(bool value)
{
internal void SetPreferSlave() if (value) flags |= AskingFlag; // the bits giveth
{ else flags &= ~AskingFlag; // and the bits taketh away
flags = (flags & ~MaskMasterServerPreference) | CommandFlags.PreferSlave; }
}
internal void SetSource(ResultProcessor resultProcessor, ResultBox resultBox) internal void SetNoRedirect()
{ // note order here reversed to prevent overload resolution errors {
this.resultBox = resultBox; flags |= CommandFlags.NoRedirect;
this.resultProcessor = resultProcessor; }
}
internal void SetPreferMaster()
internal void SetSource<T>(ResultBox<T> resultBox, ResultProcessor<T> resultProcessor) {
{ flags = (flags & ~MaskMasterServerPreference) | CommandFlags.PreferMaster;
this.resultBox = resultBox; }
this.resultProcessor = resultProcessor;
} internal void SetPreferSlave()
{
internal abstract void WriteImpl(PhysicalConnection physical); flags = (flags & ~MaskMasterServerPreference) | CommandFlags.PreferSlave;
}
internal void WriteTo(PhysicalConnection physical) internal void SetSource(ResultProcessor resultProcessor, ResultBox resultBox)
{ { // note order here reversed to prevent overload resolution errors
try this.resultBox = resultBox;
{ this.resultProcessor = resultProcessor;
WriteImpl(physical); }
}
catch (RedisCommandException) internal void SetSource<T>(ResultBox<T> resultBox, ResultProcessor<T> resultProcessor)
{ // these have specific meaning; don't wrap {
throw; this.resultBox = resultBox;
} this.resultProcessor = resultProcessor;
catch (Exception ex) }
{
physical?.OnInternalError(ex); internal abstract void WriteImpl(PhysicalConnection physical);
Fail(ConnectionFailureType.InternalFailure, ex);
} internal void WriteTo(PhysicalConnection physical)
} {
internal abstract class CommandChannelBase : Message try
{ {
protected readonly RedisChannel Channel; WriteImpl(physical);
}
public CommandChannelBase(int db, CommandFlags flags, RedisCommand command, RedisChannel channel) : base(db, flags, command) catch (RedisCommandException)
{ { // these have specific meaning; don't wrap
channel.AssertNotNull(); throw;
Channel = channel; }
} catch (Exception ex)
{
public override string CommandAndKey => Command + " " + Channel; physical?.OnInternalError(ex);
} Fail(ConnectionFailureType.InternalFailure, ex);
}
internal abstract class CommandKeyBase : Message }
{ internal abstract class CommandChannelBase : Message
protected readonly RedisKey Key; {
protected readonly RedisChannel Channel;
public CommandKeyBase(int db, CommandFlags flags, RedisCommand command, RedisKey key) : base(db, flags, command)
{ public CommandChannelBase(int db, CommandFlags flags, RedisCommand command, RedisChannel channel) : base(db, flags, command)
key.AssertNotNull(); {
Key = key; channel.AssertNotNull();
} Channel = channel;
}
public override string CommandAndKey => Command + " " + (string)Key;
public override string CommandAndKey => Command + " " + Channel;
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) }
{
return serverSelectionStrategy.HashSlot(Key); internal abstract class CommandKeyBase : Message
} {
} protected readonly RedisKey Key;
sealed class CommandChannelMessage : CommandChannelBase
{ public CommandKeyBase(int db, CommandFlags flags, RedisCommand command, RedisKey key) : base(db, flags, command)
public CommandChannelMessage(int db, CommandFlags flags, RedisCommand command, RedisChannel channel) : base(db, flags, command, channel) {
{ } key.AssertNotNull();
internal override void WriteImpl(PhysicalConnection physical) Key = key;
{ }
physical.WriteHeader(Command, 1);
physical.Write(Channel); public override string CommandAndKey => Command + " " + (string)Key;
}
} public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
{
sealed class CommandChannelValueMessage : CommandChannelBase return serverSelectionStrategy.HashSlot(Key);
{ }
private readonly RedisValue value; }
public CommandChannelValueMessage(int db, CommandFlags flags, RedisCommand command, RedisChannel channel, RedisValue value) : base(db, flags, command, channel) sealed class CommandChannelMessage : CommandChannelBase
{ {
value.AssertNotNull(); public CommandChannelMessage(int db, CommandFlags flags, RedisCommand command, RedisChannel channel) : base(db, flags, command, channel)
this.value = value; { }
} internal override void WriteImpl(PhysicalConnection physical)
internal override void WriteImpl(PhysicalConnection physical) {
{ physical.WriteHeader(Command, 1);
physical.WriteHeader(Command, 2); physical.Write(Channel);
physical.Write(Channel); }
physical.Write(value); }
}
} sealed class CommandChannelValueMessage : CommandChannelBase
{
sealed class CommandKeyKeyKeyMessage : CommandKeyBase private readonly RedisValue value;
{ public CommandChannelValueMessage(int db, CommandFlags flags, RedisCommand command, RedisChannel channel, RedisValue value) : base(db, flags, command, channel)
private readonly RedisKey key1, key2; {
public CommandKeyKeyKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1, RedisKey key2) : base(db, flags, command, key0) value.AssertNotNull();
{ this.value = value;
key1.AssertNotNull(); }
key2.AssertNotNull(); internal override void WriteImpl(PhysicalConnection physical)
this.key1 = key1; {
this.key2 = key2; physical.WriteHeader(Command, 2);
} physical.Write(Channel);
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) physical.Write(value);
{ }
var slot = serverSelectionStrategy.HashSlot(Key); }
slot = serverSelectionStrategy.CombineSlot(slot, key1);
slot = serverSelectionStrategy.CombineSlot(slot, key2); sealed class CommandKeyKeyKeyMessage : CommandKeyBase
return slot; {
} private readonly RedisKey key1, key2;
public CommandKeyKeyKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1, RedisKey key2) : base(db, flags, command, key0)
internal override void WriteImpl(PhysicalConnection physical) {
{ key1.AssertNotNull();
physical.WriteHeader(Command, 3); key2.AssertNotNull();
physical.Write(Key); this.key1 = key1;
physical.Write(key1); this.key2 = key2;
physical.Write(key2); }
} public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
} {
var slot = serverSelectionStrategy.HashSlot(Key);
class CommandKeyKeyMessage : CommandKeyBase slot = serverSelectionStrategy.CombineSlot(slot, key1);
{ slot = serverSelectionStrategy.CombineSlot(slot, key2);
protected readonly RedisKey key1; return slot;
public CommandKeyKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1) : base(db, flags, command, key0) }
{
key1.AssertNotNull(); internal override void WriteImpl(PhysicalConnection physical)
this.key1 = key1; {
} physical.WriteHeader(Command, 3);
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) physical.Write(Key);
{ physical.Write(key1);
var slot = serverSelectionStrategy.HashSlot(Key); physical.Write(key2);
slot = serverSelectionStrategy.CombineSlot(slot, key1); }
return slot; }
}
class CommandKeyKeyMessage : CommandKeyBase
internal override void WriteImpl(PhysicalConnection physical) {
{ protected readonly RedisKey key1;
physical.WriteHeader(Command, 2); public CommandKeyKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1) : base(db, flags, command, key0)
physical.Write(Key); {
physical.Write(key1); key1.AssertNotNull();
} this.key1 = key1;
} }
sealed class CommandKeyKeysMessage : CommandKeyBase public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
{ {
private readonly RedisKey[] keys; var slot = serverSelectionStrategy.HashSlot(Key);
public CommandKeyKeysMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisKey[] keys) : base(db, flags, command, key) slot = serverSelectionStrategy.CombineSlot(slot, key1);
{ return slot;
for (int i = 0; i < keys.Length; i++) }
{
keys[i].AssertNotNull(); internal override void WriteImpl(PhysicalConnection physical)
} {
this.keys = keys; physical.WriteHeader(Command, 2);
} physical.Write(Key);
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) physical.Write(key1);
{ }
var slot = serverSelectionStrategy.HashSlot(Key); }
for (int i = 0; i < keys.Length; i++) sealed class CommandKeyKeysMessage : CommandKeyBase
{ {
slot = serverSelectionStrategy.CombineSlot(slot, keys[i]); private readonly RedisKey[] keys;
} public CommandKeyKeysMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisKey[] keys) : base(db, flags, command, key)
return slot; {
} for (int i = 0; i < keys.Length; i++)
internal override void WriteImpl(PhysicalConnection physical) {
{ keys[i].AssertNotNull();
physical.WriteHeader(command, keys.Length + 1); }
physical.Write(Key); this.keys = keys;
for (int i = 0; i < keys.Length; i++) }
{ public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
physical.Write(keys[i]); {
} var slot = serverSelectionStrategy.HashSlot(Key);
} for (int i = 0; i < keys.Length; i++)
} {
slot = serverSelectionStrategy.CombineSlot(slot, keys[i]);
sealed class CommandKeyKeyValueMessage : CommandKeyKeyMessage }
{ return slot;
private readonly RedisValue value; }
public CommandKeyKeyValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1, RedisValue value) : base(db, flags, command, key0, key1) internal override void WriteImpl(PhysicalConnection physical)
{ {
value.AssertNotNull(); physical.WriteHeader(command, keys.Length + 1);
this.value = value; physical.Write(Key);
} for (int i = 0; i < keys.Length; i++)
{
internal override void WriteImpl(PhysicalConnection physical) physical.Write(keys[i]);
{ }
physical.WriteHeader(Command, 3); }
physical.Write(Key); }
physical.Write(key1);
physical.Write(value); sealed class CommandKeyKeyValueMessage : CommandKeyKeyMessage
} {
} private readonly RedisValue value;
sealed class CommandKeyMessage : CommandKeyBase public CommandKeyKeyValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisKey key1, RedisValue value) : base(db, flags, command, key0, key1)
{ {
public CommandKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key) : base(db, flags, command, key) value.AssertNotNull();
{ } this.value = value;
internal override void WriteImpl(PhysicalConnection physical) }
{
physical.WriteHeader(Command, 1); internal override void WriteImpl(PhysicalConnection physical)
physical.Write(Key); {
} physical.WriteHeader(Command, 3);
} physical.Write(Key);
sealed class CommandValuesMessage : Message physical.Write(key1);
{ physical.Write(value);
private readonly RedisValue[] values; }
public CommandValuesMessage(int db, CommandFlags flags, RedisCommand command, RedisValue[] values) : base(db, flags, command) }
{ sealed class CommandKeyMessage : CommandKeyBase
for (int i = 0; i < values.Length; i++) {
{ public CommandKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key) : base(db, flags, command, key)
values[i].AssertNotNull(); { }
} internal override void WriteImpl(PhysicalConnection physical)
this.values = values; {
} physical.WriteHeader(Command, 1);
internal override void WriteImpl(PhysicalConnection physical) physical.Write(Key);
{ }
physical.WriteHeader(command, values.Length); }
for (int i = 0; i < values.Length; i++) sealed class CommandValuesMessage : Message
{ {
physical.Write(values[i]); private readonly RedisValue[] values;
} public CommandValuesMessage(int db, CommandFlags flags, RedisCommand command, RedisValue[] values) : base(db, flags, command)
} {
} for (int i = 0; i < values.Length; i++)
sealed class CommandKeysMessage : Message {
{ values[i].AssertNotNull();
private readonly RedisKey[] keys; }
public CommandKeysMessage(int db, CommandFlags flags, RedisCommand command, RedisKey[] keys) : base(db, flags, command) this.values = values;
{ }
for (int i = 0; i < keys.Length; i++) internal override void WriteImpl(PhysicalConnection physical)
{ {
keys[i].AssertNotNull(); physical.WriteHeader(command, values.Length);
} for (int i = 0; i < values.Length; i++)
this.keys = keys; {
} physical.Write(values[i]);
}
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) }
{ }
int slot = ServerSelectionStrategy.NoSlot; sealed class CommandKeysMessage : Message
for(int i = 0; i < keys.Length; i++) {
{ private readonly RedisKey[] keys;
slot = serverSelectionStrategy.CombineSlot(slot, keys[i]); public CommandKeysMessage(int db, CommandFlags flags, RedisCommand command, RedisKey[] keys) : base(db, flags, command)
} {
return slot; for (int i = 0; i < keys.Length; i++)
} {
keys[i].AssertNotNull();
internal override void WriteImpl(PhysicalConnection physical) }
{ this.keys = keys;
physical.WriteHeader(command, keys.Length); }
for (int i = 0; i < keys.Length; i++)
{ public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
physical.Write(keys[i]); {
} int slot = ServerSelectionStrategy.NoSlot;
} for(int i = 0; i < keys.Length; i++)
} {
slot = serverSelectionStrategy.CombineSlot(slot, keys[i]);
sealed class CommandKeyValueMessage : CommandKeyBase }
{ return slot;
private readonly RedisValue value; }
public CommandKeyValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value) : base(db, flags, command, key)
{ internal override void WriteImpl(PhysicalConnection physical)
value.AssertNotNull(); {
this.value = value; physical.WriteHeader(command, keys.Length);
} for (int i = 0; i < keys.Length; i++)
internal override void WriteImpl(PhysicalConnection physical) {
{ physical.Write(keys[i]);
physical.WriteHeader(Command, 2); }
physical.Write(Key); }
physical.Write(value); }
}
} sealed class CommandKeyValueMessage : CommandKeyBase
sealed class CommandKeyValuesKeyMessage : CommandKeyBase {
{ private readonly RedisValue value;
private readonly RedisKey key1; public CommandKeyValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value) : base(db, flags, command, key)
private readonly RedisValue[] values; {
public CommandKeyValuesKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisValue[] values, RedisKey key1) : base(db, flags, command, key0) value.AssertNotNull();
{ this.value = value;
for (int i = 0; i < values.Length; i++) }
{ internal override void WriteImpl(PhysicalConnection physical)
values[i].AssertNotNull(); {
} physical.WriteHeader(Command, 2);
this.values = values; physical.Write(Key);
key1.AssertNotNull(); physical.Write(value);
this.key1 = key1; }
} }
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) sealed class CommandKeyValuesKeyMessage : CommandKeyBase
{ {
var slot = base.GetHashSlot(serverSelectionStrategy); private readonly RedisKey key1;
return serverSelectionStrategy.CombineSlot(slot, key1); private readonly RedisValue[] values;
} public CommandKeyValuesKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key0, RedisValue[] values, RedisKey key1) : base(db, flags, command, key0)
{
internal override void WriteImpl(PhysicalConnection physical) for (int i = 0; i < values.Length; i++)
{ {
physical.WriteHeader(Command, values.Length + 2); values[i].AssertNotNull();
physical.Write(Key); }
for (int i = 0; i < values.Length; i++) physical.Write(values[i]); this.values = values;
physical.Write(key1); key1.AssertNotNull();
} this.key1 = key1;
} }
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
sealed class CommandKeyValuesMessage : CommandKeyBase {
{ var slot = base.GetHashSlot(serverSelectionStrategy);
private readonly RedisValue[] values; return serverSelectionStrategy.CombineSlot(slot, key1);
public CommandKeyValuesMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue[] values) : base(db, flags, command, key) }
{
for (int i = 0; i < values.Length; i++) internal override void WriteImpl(PhysicalConnection physical)
{ {
values[i].AssertNotNull(); physical.WriteHeader(Command, values.Length + 2);
} physical.Write(Key);
this.values = values; for (int i = 0; i < values.Length; i++) physical.Write(values[i]);
} physical.Write(key1);
internal override void WriteImpl(PhysicalConnection physical) }
{ }
physical.WriteHeader(Command, values.Length + 1);
physical.Write(Key); sealed class CommandKeyValuesMessage : CommandKeyBase
for (int i = 0; i < values.Length; i++) physical.Write(values[i]); {
} private readonly RedisValue[] values;
} public CommandKeyValuesMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue[] values) : base(db, flags, command, key)
{
sealed class CommandKeyValueValueMessage : CommandKeyBase for (int i = 0; i < values.Length; i++)
{ {
private readonly RedisValue value0, value1; values[i].AssertNotNull();
public CommandKeyValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1) : base(db, flags, command, key) }
{ this.values = values;
value0.AssertNotNull(); }
value1.AssertNotNull(); internal override void WriteImpl(PhysicalConnection physical)
this.value0 = value0; {
this.value1 = value1; physical.WriteHeader(Command, values.Length + 1);
} physical.Write(Key);
internal override void WriteImpl(PhysicalConnection physical) for (int i = 0; i < values.Length; i++) physical.Write(values[i]);
{ }
physical.WriteHeader(Command, 3); }
physical.Write(Key);
physical.Write(value0); sealed class CommandKeyValueValueMessage : CommandKeyBase
physical.Write(value1); {
} private readonly RedisValue value0, value1;
} public CommandKeyValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1) : base(db, flags, command, key)
{
sealed class CommandKeyValueValueValueMessage : CommandKeyBase value0.AssertNotNull();
{ value1.AssertNotNull();
private readonly RedisValue value0, value1, value2; this.value0 = value0;
public CommandKeyValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1, RedisValue value2) : base(db, flags, command, key) this.value1 = value1;
{ }
value0.AssertNotNull(); internal override void WriteImpl(PhysicalConnection physical)
value1.AssertNotNull(); {
value2.AssertNotNull(); physical.WriteHeader(Command, 3);
this.value0 = value0; physical.Write(Key);
this.value1 = value1; physical.Write(value0);
this.value2 = value2; physical.Write(value1);
} }
internal override void WriteImpl(PhysicalConnection physical) }
{
physical.WriteHeader(Command, 4); sealed class CommandKeyValueValueValueMessage : CommandKeyBase
physical.Write(Key); {
physical.Write(value0); private readonly RedisValue value0, value1, value2;
physical.Write(value1); public CommandKeyValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1, RedisValue value2) : base(db, flags, command, key)
physical.Write(value2); {
} value0.AssertNotNull();
} value1.AssertNotNull();
value2.AssertNotNull();
sealed class CommandKeyValueValueValueValueMessage : CommandKeyBase this.value0 = value0;
{ this.value1 = value1;
private readonly RedisValue value0, value1, value2, value3; this.value2 = value2;
public CommandKeyValueValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1, RedisValue value2, RedisValue value3) : base(db, flags, command, key) }
{ internal override void WriteImpl(PhysicalConnection physical)
value0.AssertNotNull(); {
value1.AssertNotNull(); physical.WriteHeader(Command, 4);
value2.AssertNotNull(); physical.Write(Key);
value3.AssertNotNull(); physical.Write(value0);
this.value0 = value0; physical.Write(value1);
this.value1 = value1; physical.Write(value2);
this.value2 = value2; }
this.value3 = value3; }
}
internal override void WriteImpl(PhysicalConnection physical) sealed class CommandKeyValueValueValueValueMessage : CommandKeyBase
{ {
physical.WriteHeader(Command, 5); private readonly RedisValue value0, value1, value2, value3;
physical.Write(Key); public CommandKeyValueValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisKey key, RedisValue value0, RedisValue value1, RedisValue value2, RedisValue value3) : base(db, flags, command, key)
physical.Write(value0); {
physical.Write(value1); value0.AssertNotNull();
physical.Write(value2); value1.AssertNotNull();
physical.Write(value3); value2.AssertNotNull();
} value3.AssertNotNull();
} this.value0 = value0;
this.value1 = value1;
sealed class CommandMessage : Message this.value2 = value2;
{ this.value3 = value3;
public CommandMessage(int db, CommandFlags flags, RedisCommand command) : base(db, flags, command) { } }
internal override void WriteImpl(PhysicalConnection physical) internal override void WriteImpl(PhysicalConnection physical)
{ {
physical.WriteHeader(Command, 0); physical.WriteHeader(Command, 5);
} physical.Write(Key);
} physical.Write(value0);
physical.Write(value1);
private class CommandSlotValuesMessage : Message physical.Write(value2);
{ physical.Write(value3);
private readonly int slot; }
private readonly RedisValue[] values; }
public CommandSlotValuesMessage(int db, int slot, CommandFlags flags, RedisCommand command, RedisValue[] values) sealed class CommandMessage : Message
: base(db, flags, command) {
{ public CommandMessage(int db, CommandFlags flags, RedisCommand command) : base(db, flags, command) { }
this.slot = slot; internal override void WriteImpl(PhysicalConnection physical)
for (int i = 0; i < values.Length; i++) {
{ physical.WriteHeader(Command, 0);
values[i].AssertNotNull(); }
} }
this.values = values;
} private class CommandSlotValuesMessage : Message
public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy) {
{ private readonly int slot;
return slot; private readonly RedisValue[] values;
}
internal override void WriteImpl(PhysicalConnection physical) public CommandSlotValuesMessage(int db, int slot, CommandFlags flags, RedisCommand command, RedisValue[] values)
{ : base(db, flags, command)
physical.WriteHeader(command, values.Length); {
for (int i = 0; i < values.Length; i++) this.slot = slot;
{ for (int i = 0; i < values.Length; i++)
physical.Write(values[i]); {
} values[i].AssertNotNull();
} }
} this.values = values;
}
sealed class CommandValueChannelMessage : CommandChannelBase public override int GetHashSlot(ServerSelectionStrategy serverSelectionStrategy)
{ {
private readonly RedisValue value; return slot;
public CommandValueChannelMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value, RedisChannel channel) : base(db, flags, command, channel) }
{ internal override void WriteImpl(PhysicalConnection physical)
value.AssertNotNull(); {
this.value = value; physical.WriteHeader(command, values.Length);
} for (int i = 0; i < values.Length; i++)
internal override void WriteImpl(PhysicalConnection physical) {
{ physical.Write(values[i]);
physical.WriteHeader(Command, 2); }
physical.Write(value); }
physical.Write(Channel); }
}
} sealed class CommandValueChannelMessage : CommandChannelBase
sealed class CommandValueKeyMessage : CommandKeyBase {
{ private readonly RedisValue value;
private readonly RedisValue value; public CommandValueChannelMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value, RedisChannel channel) : base(db, flags, command, channel)
{
public CommandValueKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value, RedisKey key) : base(db, flags, command, key) value.AssertNotNull();
{ this.value = value;
value.AssertNotNull(); }
this.value = value; internal override void WriteImpl(PhysicalConnection physical)
} {
physical.WriteHeader(Command, 2);
public override void AppendStormLog(StringBuilder sb) physical.Write(value);
{ physical.Write(Channel);
base.AppendStormLog(sb); }
sb.Append(" (").Append((string)value).Append(')'); }
} sealed class CommandValueKeyMessage : CommandKeyBase
internal override void WriteImpl(PhysicalConnection physical) {
{ private readonly RedisValue value;
physical.WriteHeader(Command, 2);
physical.Write(value); public CommandValueKeyMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value, RedisKey key) : base(db, flags, command, key)
physical.Write(Key); {
} value.AssertNotNull();
} this.value = value;
}
sealed class CommandValueMessage : Message
{ public override void AppendStormLog(StringBuilder sb)
private readonly RedisValue value; {
public CommandValueMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value) : base(db, flags, command) base.AppendStormLog(sb);
{ sb.Append(" (").Append((string)value).Append(')');
value.AssertNotNull(); }
this.value = value; internal override void WriteImpl(PhysicalConnection physical)
} {
internal override void WriteImpl(PhysicalConnection physical) physical.WriteHeader(Command, 2);
{ physical.Write(value);
physical.WriteHeader(Command, 1); physical.Write(Key);
physical.Write(value); }
} }
}
sealed class CommandValueMessage : Message
sealed class CommandValueValueMessage : Message {
{ private readonly RedisValue value;
private readonly RedisValue value0, value1; public CommandValueMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value) : base(db, flags, command)
public CommandValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1) : base(db, flags, command) {
{ value.AssertNotNull();
value0.AssertNotNull(); this.value = value;
value1.AssertNotNull(); }
this.value0 = value0; internal override void WriteImpl(PhysicalConnection physical)
this.value1 = value1; {
} physical.WriteHeader(Command, 1);
internal override void WriteImpl(PhysicalConnection physical) physical.Write(value);
{ }
physical.WriteHeader(Command, 2); }
physical.Write(value0);
physical.Write(value1); sealed class CommandValueValueMessage : Message
} {
} private readonly RedisValue value0, value1;
public CommandValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1) : base(db, flags, command)
sealed class CommandValueValueValueMessage : Message {
{ value0.AssertNotNull();
private readonly RedisValue value0, value1, value2; value1.AssertNotNull();
public CommandValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1, RedisValue value2) : base(db, flags, command) this.value0 = value0;
{ this.value1 = value1;
value0.AssertNotNull(); }
value1.AssertNotNull(); internal override void WriteImpl(PhysicalConnection physical)
value2.AssertNotNull(); {
this.value0 = value0; physical.WriteHeader(Command, 2);
this.value1 = value1; physical.Write(value0);
this.value2 = value2; physical.Write(value1);
} }
internal override void WriteImpl(PhysicalConnection physical) }
{
physical.WriteHeader(Command, 3); sealed class CommandValueValueValueMessage : Message
physical.Write(value0); {
physical.Write(value1); private readonly RedisValue value0, value1, value2;
physical.Write(value2); public CommandValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1, RedisValue value2) : base(db, flags, command)
} {
} value0.AssertNotNull();
value1.AssertNotNull();
sealed class CommandValueValueValueValueValueMessage : Message value2.AssertNotNull();
{ this.value0 = value0;
private readonly RedisValue value0, value1, value2, value3, value4; this.value1 = value1;
public CommandValueValueValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1, RedisValue value2, RedisValue value3, RedisValue value4) : base(db, flags, command) this.value2 = value2;
{ }
value0.AssertNotNull(); internal override void WriteImpl(PhysicalConnection physical)
value1.AssertNotNull(); {
value2.AssertNotNull(); physical.WriteHeader(Command, 3);
value3.AssertNotNull(); physical.Write(value0);
value4.AssertNotNull(); physical.Write(value1);
this.value0 = value0; physical.Write(value2);
this.value1 = value1; }
this.value2 = value2; }
this.value3 = value3;
this.value4 = value4; sealed class CommandValueValueValueValueValueMessage : Message
} {
internal override void WriteImpl(PhysicalConnection physical) private readonly RedisValue value0, value1, value2, value3, value4;
{ public CommandValueValueValueValueValueMessage(int db, CommandFlags flags, RedisCommand command, RedisValue value0, RedisValue value1, RedisValue value2, RedisValue value3, RedisValue value4) : base(db, flags, command)
physical.WriteHeader(Command, 5); {
physical.Write(value0); value0.AssertNotNull();
physical.Write(value1); value1.AssertNotNull();
physical.Write(value2); value2.AssertNotNull();
physical.Write(value3); value3.AssertNotNull();
physical.Write(value4); value4.AssertNotNull();
} this.value0 = value0;
} this.value1 = value1;
this.value2 = value2;
sealed class SelectMessage : Message this.value3 = value3;
{ this.value4 = value4;
public SelectMessage(int db, CommandFlags flags) : base(db, flags, RedisCommand.SELECT) }
{ internal override void WriteImpl(PhysicalConnection physical)
} {
internal override void WriteImpl(PhysicalConnection physical) physical.WriteHeader(Command, 5);
{ physical.Write(value0);
physical.WriteHeader(Command, 1); physical.Write(value1);
physical.Write(Db); physical.Write(value2);
} physical.Write(value3);
} physical.Write(value4);
} }
} }
sealed class SelectMessage : Message
{
public SelectMessage(int db, CommandFlags flags) : base(db, flags, RedisCommand.SELECT)
{
}
internal override void WriteImpl(PhysicalConnection physical)
{
physical.WriteHeader(Command, 1);
physical.Write(Db);
}
}
}
}
...@@ -230,6 +230,42 @@ internal RedisValue[] GetItemsAsValues() ...@@ -230,6 +230,42 @@ internal RedisValue[] GetItemsAsValues()
return arr; return arr;
} }
} }
internal GeoPosition?[] GetItemsAsGeoPositionArray()
{
RawResult[] items = GetItems();
if (items == null)
{
return null;
}
else if (items.Length == 0)
{
return new GeoPosition?[0];
}
else
{
var arr = new GeoPosition?[items.Length];
for (int i = 0; i < arr.Length; i++)
{
RawResult[] item = items[i].GetArrayOfRawResults();
if (item == null)
{
arr[i] = null;
}
else
{
arr[i] = new GeoPosition((double)item[0].AsRedisValue(), (double)item[1].AsRedisValue());
}
}
return arr;
}
}
internal RawResult[] GetItemsAsRawResults()
{
return GetItems();
}
// returns an array of RawResults // returns an array of RawResults
internal RawResult[] GetArrayOfRawResults() internal RawResult[] GetArrayOfRawResults()
......
...@@ -38,6 +38,13 @@ enum RedisCommand ...@@ -38,6 +38,13 @@ enum RedisCommand
FLUSHALL, FLUSHALL,
FLUSHDB, FLUSHDB,
GEOADD,
GEODIST,
GEOHASH,
GEOPOS,
GEORADIUS,
GEORADIUSBYMEMBER,
GET, GET,
GETBIT, GETBIT,
GETRANGE, GETRANGE,
......
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Net; using System.Net;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -13,6 +14,7 @@ internal RedisDatabase(ConnectionMultiplexer multiplexer, int db, object asyncSt ...@@ -13,6 +14,7 @@ internal RedisDatabase(ConnectionMultiplexer multiplexer, int db, object asyncSt
Database = db; Database = db;
} }
private static string[] _redisUnits = new[] {"m", "km", "mi", "ft"};
public object AsyncState => asyncState; public object AsyncState => asyncState;
public int Database { get; } public int Database { get; }
...@@ -45,6 +47,134 @@ public RedisValue DebugObject(RedisKey key, CommandFlags flags = CommandFlags.No ...@@ -45,6 +47,134 @@ public RedisValue DebugObject(RedisKey key, CommandFlags flags = CommandFlags.No
return ExecuteSync(msg, ResultProcessor.RedisValue); return ExecuteSync(msg, ResultProcessor.RedisValue);
} }
public bool GeoAdd(RedisKey key, double longitude,double latitude,RedisValue member,CommandFlags flags = CommandFlags.None)
{
return GeoAdd(key, new GeoEntry(longitude, latitude,member), member, flags);
}
public bool GeoAdd(RedisKey key, GeoEntry geoPosition, RedisValue member, CommandFlags flags = CommandFlags.None)
{
var msg = Message.Create(Database, flags, RedisCommand.GEOADD, key, geoPosition.Longitude, geoPosition.Latitude, member);
return ExecuteSync(msg, ResultProcessor.Boolean);
}
public long GeoAdd(RedisKey key, GeoEntry[] geoEntries, CommandFlags flags = CommandFlags.None)
{
if(geoEntries == null) throw new ArgumentNullException(nameof(geoEntries));
var msg = Message.Create(Database,flags, RedisCommand.GEOADD, key, geoEntries);
return ExecuteSync(msg, ResultProcessor.Int64);
}
public bool GeoRemove(RedisKey key, RedisValue member, CommandFlags flags = CommandFlags.None)
{
return SortedSetRemove(key, member, flags);
}
public double GeoDistance(RedisKey key, RedisValue value0, RedisValue value1, GeoUnit geoUnit = GeoUnit.Meters,CommandFlags flags = CommandFlags.None)
{
var msg = Message.Create(Database, flags, RedisCommand.GEODIST, key,value0,value1,_redisUnits[(int)geoUnit]);
return (double)ExecuteSync(msg, ResultProcessor.RedisValue);
}
public string[] GeoHash(RedisKey key, string[] members, CommandFlags flags = CommandFlags.None)
{
if(members == null)throw new ArgumentNullException(nameof(members));
var redisValues = new RedisValue[members.Length];
for (var i = 0; i < members.Length; i++) redisValues[i] = members[i];
var msg = Message.Create(Database, flags, RedisCommand.GEOHASH, key, redisValues);
var results = ExecuteSync(msg, ResultProcessor.RedisValueArray);
var retArray = new string[results.Length];
for (int i = 0; i < results.Length; i++)
{
retArray[i] = (string)results[i];
}
return retArray;
}
public string[] GeoHash(RedisKey key, string member, CommandFlags flags = CommandFlags.None)
{
return GeoHash(key, new[] {member}, flags);
}
public GeoPosition?[] GeoPos(RedisKey key, string[] members, CommandFlags flags = CommandFlags.None)
{
if (members == null) throw new ArgumentNullException(nameof(members));
var redisValues = new RedisValue[members.Length];
for (var i = 0; i < members.Length; i++) redisValues[i] = members[i];
var msg = Message.Create(Database, flags, RedisCommand.GEOPOS, key, redisValues);
return ExecuteSync(msg, ResultProcessor.RedisGeoPosition);
}
public GeoPosition? GeoPos(RedisKey key, string member, CommandFlags flags = CommandFlags.None)
{
return GeoPos(key, new string[] {member}, flags).FirstOrDefault();
}
public GeoRadiusResult[] GeoRadius(RedisKey key, GeoRadius geoRadius,CommandFlags flags = CommandFlags.None)
{
var redisValues = new List<RedisValue>();
redisValues.Add(geoRadius.GeoPosition.Longitude);
redisValues.Add(geoRadius.GeoPosition.Latitude);
redisValues.Add(geoRadius.Radius);
redisValues.Add(_redisUnits[(int)geoRadius.Unit]);
if(geoRadius.HasFlag(GeoRadiusOptions.WithCoordinates))
redisValues.Add("WITHCOORD");
if (geoRadius.HasFlag(GeoRadiusOptions.WithDistance))
redisValues.Add("WITHDIST");
if (geoRadius.HasFlag(GeoRadiusOptions.WithGeoHash))
redisValues.Add("WITHHASH");
if(geoRadius.MaxReturnCount >0)
redisValues.Add(geoRadius.MaxReturnCount);
var msg = Message.Create(Database, flags, RedisCommand.GEORADIUS, key, redisValues.ToArray());
var items = ExecuteSync(msg, ResultProcessor.RedisGeoRadius);
var arr = new GeoRadiusResult[items.Length];
for (int i = 0; i < arr.Length; i++)
{
RawResult[] item = items[i].GetArrayOfRawResults();
if (item == null)
{
continue;
}
else
{
var x = 0;
var member = item[x++].AsRedisValue();
var distance = geoRadius.HasFlag(GeoRadiusOptions.WithDistance) ? new double?((double)item[x++].AsRedisValue()) : null;
GeoPosition? geoPosition;
long? geoHash;
if (geoRadius.HasFlag(GeoRadiusOptions.WithGeoHash))
{
long tempL;
if (item[x++].TryGetInt64(out tempL))
geoHash = new long?(tempL);
else
geoHash = new long?();
}
else
{
geoHash =null;
}
if (geoRadius.HasFlag(GeoRadiusOptions.WithCoordinates))
{
var radIem = item[x++].GetItemsAsRawResults();
var longitude = (double)radIem[0].AsRedisValue();
var latitude = (double)radIem[1].AsRedisValue();
geoPosition = new GeoPosition?(new GeoPosition(longitude, latitude));
}
else
{
geoPosition = null;
}
var newRadiusResult = new GeoRadiusResult(member, geoRadius, distance, geoHash, geoPosition);
arr[i] = newRadiusResult;
}
}
return arr;
}
public Task<RedisValue> DebugObjectAsync(RedisKey key, CommandFlags flags = CommandFlags.None) public Task<RedisValue> DebugObjectAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
{ {
var msg = Message.Create(Database, flags, RedisCommand.DEBUG, RedisLiterals.OBJECT, key); var msg = Message.Create(Database, flags, RedisCommand.DEBUG, RedisLiterals.OBJECT, key);
...@@ -926,7 +1056,6 @@ public Task<RedisResult> ScriptEvaluateAsync(LoadedLuaScript script, object para ...@@ -926,7 +1056,6 @@ public Task<RedisResult> ScriptEvaluateAsync(LoadedLuaScript script, object para
{ {
return script.EvaluateAsync(this, parameters, null, flags); return script.EvaluateAsync(this, parameters, null, flags);
} }
public bool SetAdd(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None) public bool SetAdd(RedisKey key, RedisValue value, CommandFlags flags = CommandFlags.None)
{ {
var msg = Message.Create(Database, flags, RedisCommand.SADD, key, value); var msg = Message.Create(Database, flags, RedisCommand.SADD, key, value);
...@@ -2431,4 +2560,4 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes ...@@ -2431,4 +2560,4 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
} }
} }
} }
} }
...@@ -66,6 +66,13 @@ abstract class ResultProcessor ...@@ -66,6 +66,13 @@ abstract class ResultProcessor
public static readonly ResultProcessor<RedisValue[]> public static readonly ResultProcessor<RedisValue[]>
RedisValueArray = new RedisValueArrayProcessor(); RedisValueArray = new RedisValueArrayProcessor();
public static readonly ResultProcessor<GeoPosition?[]>
RedisGeoPosition = new RedisValueGeoPositionProcessor();
public static readonly ResultProcessor<RawResult[]>
RedisGeoRadius = new RedisGeoRadiusProcessor();
public static readonly ResultProcessor<TimeSpan> public static readonly ResultProcessor<TimeSpan>
ResponseTimer = new TimingProcessor(); ResponseTimer = new TimingProcessor();
...@@ -1088,6 +1095,39 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes ...@@ -1088,6 +1095,39 @@ protected override bool SetResultCore(PhysicalConnection connection, Message mes
return false; return false;
} }
} }
sealed class RedisValueGeoPositionProcessor : ResultProcessor<GeoPosition?[]>
{
protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
{
switch (result.Type)
{
case ResultType.MultiBulk:
var arr = result.GetItemsAsGeoPositionArray();
SetResult(message, arr);
return true;
}
return false;
}
}
sealed class RedisGeoRadiusProcessor : ResultProcessor<RawResult[]>
{
protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
{
switch (result.Type)
{
case ResultType.MultiBulk:
var arr = result.GetItemsAsRawResults();
SetResult(message, arr);
return true;
}
return false;
}
}
sealed class RedisValueProcessor : ResultProcessor<RedisValue> sealed class RedisValueProcessor : ResultProcessor<RedisValue>
{ {
protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result) protected override bool SetResultCore(PhysicalConnection connection, Message message, RawResult result)
......
...@@ -4,6 +4,10 @@ ...@@ -4,6 +4,10 @@
namespace StackExchange.Redis namespace StackExchange.Redis
{ {
/// <summary> /// <summary>
/// Describes a sorted-set element with the corresponding value /// Describes a sorted-set element with the corresponding value
/// </summary> /// </summary>
......
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