Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/main' into pr/2722
Browse files Browse the repository at this point in the history
  • Loading branch information
NickCraver committed Aug 3, 2024
2 parents 3d3a158 + 8346a5c commit 1541f84
Show file tree
Hide file tree
Showing 215 changed files with 3,292 additions and 4,146 deletions.
78 changes: 64 additions & 14 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -138,23 +138,73 @@ csharp_space_between_method_call_empty_parameter_list_parentheses = false
csharp_preserve_single_line_statements = true
csharp_preserve_single_line_blocks = true

# IDE0090: Use 'new(...)'
dotnet_diagnostic.IDE0090.severity = silent

# RCS1037: Remove trailing white-space.
dotnet_diagnostic.RCS1037.severity = error
# IDE preferences
dotnet_diagnostic.IDE0090.severity = silent # IDE0090: Use 'new(...)'

#Roslynator preferences
dotnet_diagnostic.RCS1037.severity = error # RCS1037: Remove trailing white-space.
dotnet_diagnostic.RCS1098.severity = none # RCS1098: Constant values should be placed on right side of comparisons.

dotnet_diagnostic.RCS1194.severity = none # RCS1194: Implement exception constructors.
dotnet_diagnostic.RCS1229.severity = none # RCS1229: Use async/await when necessary.
dotnet_diagnostic.RCS1233.severity = none # RCS1233: Use short-circuiting operator.
dotnet_diagnostic.RCS1234.severity = none # RCS1234: Duplicate enum value.

# StyleCop preferences
dotnet_diagnostic.SA0001.severity = none # SA0001: XML comment analysis is disabled

dotnet_diagnostic.SA1101.severity = none # SA1101: Prefix local calls with this
dotnet_diagnostic.SA1108.severity = none # SA1108: Block statements should not contain embedded comments
dotnet_diagnostic.SA1122.severity = none # SA1122: Use string.Empty for empty strings
dotnet_diagnostic.SA1127.severity = none # SA1127: Generic type constraints should be on their own line
dotnet_diagnostic.SA1128.severity = none # SA1128: Put constructor initializers on their own line
dotnet_diagnostic.SA1132.severity = none # SA1132: Do not combine fields
dotnet_diagnostic.SA1133.severity = none # SA1133: Do not combine attributes

dotnet_diagnostic.SA1200.severity = none # SA1200: Using directives should be placed correctly
dotnet_diagnostic.SA1201.severity = none # SA1201: Elements should appear in the correct order
dotnet_diagnostic.SA1202.severity = none # SA1202: Elements should be ordered by access
dotnet_diagnostic.SA1203.severity = none # SA1203: Constants should appear before fields

dotnet_diagnostic.SA1306.severity = none # SA1306: Field names should begin with lower-case letter
dotnet_diagnostic.SA1309.severity = none # SA1309: Field names should not begin with underscore
dotnet_diagnostic.SA1310.severity = silent # SA1310: Field names should not contain underscore
dotnet_diagnostic.SA1311.severity = none # SA1311: Static readonly fields should begin with upper-case letter
dotnet_diagnostic.SA1312.severity = none # SA1312: Variable names should begin with lower-case letter

dotnet_diagnostic.SA1401.severity = silent # SA1401: Fields should be private
dotnet_diagnostic.SA1402.severity = suggestion # SA1402: File may only contain a single type

dotnet_diagnostic.SA1503.severity = silent # SA1503: Braces should not be omitted
dotnet_diagnostic.SA1516.severity = silent # SA1516: Elements should be separated by blank line

dotnet_diagnostic.SA1600.severity = none # SA1600: Elements should be documented
dotnet_diagnostic.SA1601.severity = none # SA1601: Partial elements should be documented
dotnet_diagnostic.SA1602.severity = none # SA1602: Enumeration items should be documented
dotnet_diagnostic.SA1615.severity = none # SA1615: Element return value should be documented
dotnet_diagnostic.SA1623.severity = none # SA1623: Property summary documentation should match accessors
dotnet_diagnostic.SA1633.severity = none # SA1633: File should have header
dotnet_diagnostic.SA1642.severity = none # SA1642: Constructor summary documentation should begin with standard text
dotnet_diagnostic.SA1643.severity = none # SA1643: Destructor summary documentation should begin with standard text


# To Fix:
dotnet_diagnostic.SA1204.severity = none # SA1204: Static elements should appear before instance elements
dotnet_diagnostic.SA1214.severity = none # SA1214: Readonly fields should appear before non-readonly fields
dotnet_diagnostic.SA1304.severity = none # SA1304: Non-private readonly fields should begin with upper-case letter
dotnet_diagnostic.SA1307.severity = none # SA1307: Accessible fields should begin with upper-case letter
dotnet_diagnostic.SA1308.severity = suggestion # SA1308: Variable names should not be prefixed
dotnet_diagnostic.SA1131.severity = none # SA1131: Use readable conditions
dotnet_diagnostic.SA1405.severity = none # SA1405: Debug.Assert should provide message text
dotnet_diagnostic.SA1501.severity = none # SA1501: Statement should not be on a single line
dotnet_diagnostic.SA1502.severity = suggestion # SA1502: Element should not be on a single line
dotnet_diagnostic.SA1513.severity = none # SA1513: Closing brace should be followed by blank line
dotnet_diagnostic.SA1515.severity = none # SA1515: Single-line comment should be preceded by blank line
dotnet_diagnostic.SA1611.severity = suggestion # SA1611: Element parameters should be documented
dotnet_diagnostic.SA1649.severity = suggestion # SA1649: File name should match first type name

# RCS1098: Constant values should be placed on right side of comparisons.
dotnet_diagnostic.RCS1098.severity = none

# RCS1194: Implement exception constructors.
dotnet_diagnostic.RCS1194.severity = none

# RCS1229: Use async/await when necessary.
dotnet_diagnostic.RCS1229.severity = none

# RCS1233: Use short-circuiting operator.
dotnet_diagnostic.RCS1233.severity = none

# RCS1234: Duplicate enum value.
dotnet_diagnostic.RCS1234.severity = none
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ jobs:
run: dotnet build Build.csproj -c Release /p:CI=true
- name: Start Redis Services (docker-compose)
working-directory: ./tests/RedisConfigs
run: docker-compose -f docker-compose.yml up -d
run: docker compose -f docker-compose.yml up -d
- name: StackExchange.Redis.Tests
run: dotnet test tests/StackExchange.Redis.Tests/StackExchange.Redis.Tests.csproj -c Release --logger trx --logger GitHubActions --results-directory ./test-results/ /p:CI=true
- uses: dorny/test-reporter@v1
Expand Down
3 changes: 3 additions & 0 deletions Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,13 @@
<Deterministic>true</Deterministic>
<EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>

<ItemGroup Condition="'$(Configuration)' == 'Release' and '$(SourceRoot)'==''">
<SourceRoot Include="$(MSBuildThisFileDirectory)/"/>
</ItemGroup>

<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" PrivateAssets="all" />
<PackageReference Include="StyleCop.Analyzers" PrivateAssets="All" />
</ItemGroup>
</Project>
1 change: 1 addition & 0 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
<PackageVersion Include="Newtonsoft.Json" Version="13.0.1" />
<PackageVersion Include="NSubstitute" Version="5.0.0" />
<PackageVersion Include="StackExchange.Redis" Version="2.6.96" />
<PackageVersion Include="StyleCop.Analyzers" Version="1.2.0-beta.556" />
<!-- For binding redirect testing, main package gets this transitively -->
<PackageVersion Include="System.IO.Pipelines" Version="5.0.1" />
<PackageVersion Include="System.Runtime.Caching" Version="5.0.0" />
Expand Down
5 changes: 5 additions & 0 deletions docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ The `ConfigurationOptions` object has a wide range of properties, all of which a
| tunnel={string} | `Tunnel` | `null` | Tunnel for connections (use `http:{proxy url}` for "connect"-based proxy server) |
| setlib={bool} | `SetClientLibrary` | `true` | Whether to attempt to use `CLIENT SETINFO` to set the library name/version on the connection |
| protocol={string} | `Protocol` | `null` | Redis protocol to use; see section below |
| highIntegrity={bool} | `HighIntegrity` | `false` | High integrity (incurs overhead) sequence checking on every command; see section below |

Additional code-only options:
- LoggerFactory (`ILoggerFactory`) - Default: `null`
Expand All @@ -115,6 +116,10 @@ Additional code-only options:
- The thread pool to use for scheduling work to and from the socket connected to Redis, one of...
- `SocketManager.Shared`: Use a shared dedicated thread pool for _all_ multiplexers (defaults to 10 threads) - best balance for most scenarios.
- `SocketManager.ThreadPool`: Use the build-in .NET thread pool for scheduling. This can perform better for very small numbers of cores or with large apps on large machines that need to use more than 10 threads (total, across all multiplexers) under load. **Important**: this option isn't the default because it's subject to thread pool growth/starvation and if for example synchronous calls are waiting on a redis command to come back to unblock other threads, stalls/hangs can result. Use with caution, especially if you have sync-over-async work in play.
- HighIntegrity - Default: `false`
- This enables sending a sequence check command after _every single command_ sent to Redis. This is an opt-in option that incurs overhead to add this integrity check which isn't in the Redis protocol (RESP2/3) itself. The impact on this for a given workload depends on the number of commands, size of payloads, etc. as to how proportionately impactful it will be - you should test with your workloads to assess this.
- This is especially relevant if your primary use case is all strings (e.g. key/value caching) where the protocol would otherwise not error.
- Intended for cases where network drops (e.g. bytes from the Redis stream, not packet loss) are suspected and integrity of responses is critical.
- HeartbeatConsistencyChecks - Default: `false`
- Allows _always_ sending keepalive checks even if a connection isn't idle. This trades extra commands (per `HeartbeatInterval` - default 1 second) to check the network stream for consistency. If any data was lost, the result won't be as expected and the connection will be terminated ASAP. This is a check to react to any data loss at the network layer as soon as possible.
- HeartbeatInterval - Default: `1000ms`
Expand Down
5 changes: 5 additions & 0 deletions docs/ReleaseNotes.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@ Current package versions:
| [![StackExchange.Redis](https://img.shields.io/nuget/v/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis](https://img.shields.io/nuget/vpre/StackExchange.Redis.svg)](https://www.nuget.org/packages/StackExchange.Redis/) | [![StackExchange.Redis MyGet](https://img.shields.io/myget/stackoverflow/vpre/StackExchange.Redis.svg)](https://www.myget.org/feed/stackoverflow/package/nuget/StackExchange.Redis) |

## Unreleased


## 2.8.0

- Add high-integrity mode ([docs](https://stackexchange.github.io/StackExchange.Redis/Configuration), [#2471 by mgravell](https://github.com/StackExchange/StackExchange.Redis/pull/2741]))
- TLS certificate/`TrustIssuer`: Check EKU in X509 chain checks when validating certificates ([#2670 by NickCraver](https://github.com/StackExchange/StackExchange.Redis/pull/2670))

## 2.7.33
Expand Down
179 changes: 179 additions & 0 deletions src/StackExchange.Redis/APITypes/ClientKillFilter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
using System;
using System.Collections.Generic;
using System.Net;

namespace StackExchange.Redis;

/// <summary>
/// Filter determining which Redis clients to kill.
/// </summary>
/// <seealso href="https://redis.io/docs/latest/commands/client-kill/"/>
public class ClientKillFilter
{
/// <summary>
/// Filter arguments builder for `CLIENT KILL`.
/// </summary>
public ClientKillFilter() { }

/// <summary>
/// The ID of the client to kill.
/// </summary>
public long? Id { get; private set; }

/// <summary>
/// The type of client.
/// </summary>
public ClientType? ClientType { get; private set; }

/// <summary>
/// The authenticated ACL username.
/// </summary>
public string? Username { get; private set; }

/// <summary>
/// The endpoint to kill.
/// </summary>
public EndPoint? Endpoint { get; private set; }

/// <summary>
/// The server endpoint to kill.
/// </summary>
public EndPoint? ServerEndpoint { get; private set; }

/// <summary>
/// Whether to skip the current connection.
/// </summary>
public bool? SkipMe { get; private set; }

/// <summary>
/// Age of connection in seconds.
/// </summary>
public long? MaxAgeInSeconds { get; private set; }

/// <summary>
/// Sets client id filter.
/// </summary>
/// <param name="id">Id of the client to kill.</param>
public ClientKillFilter WithId(long? id)
{
Id = id;
return this;
}

/// <summary>
/// Sets client type filter.
/// </summary>
/// <param name="clientType">The type of the client.</param>
public ClientKillFilter WithClientType(ClientType? clientType)
{
ClientType = clientType;
return this;
}

/// <summary>
/// Sets the username filter.
/// </summary>
/// <param name="username">Authenticated ACL username.</param>
public ClientKillFilter WithUsername(string? username)
{
Username = username;
return this;
}

/// <summary>
/// Set the endpoint filter.
/// </summary>
/// <param name="endpoint">The endpoint to kill.</param>
public ClientKillFilter WithEndpoint(EndPoint? endpoint)
{
Endpoint = endpoint;
return this;
}

/// <summary>
/// Set the server endpoint filter.
/// </summary>
/// <param name="serverEndpoint">The server endpoint to kill.</param>
public ClientKillFilter WithServerEndpoint(EndPoint? serverEndpoint)
{
ServerEndpoint = serverEndpoint;
return this;
}

/// <summary>
/// Set the skipMe filter (whether to skip the current connection).
/// </summary>
/// <param name="skipMe">Whether to skip the current connection.</param>
public ClientKillFilter WithSkipMe(bool? skipMe)
{
SkipMe = skipMe;
return this;
}

/// <summary>
/// Set the MaxAgeInSeconds filter.
/// </summary>
/// <param name="maxAgeInSeconds">Age of connection in seconds.</param>
public ClientKillFilter WithMaxAgeInSeconds(long? maxAgeInSeconds)
{
MaxAgeInSeconds = maxAgeInSeconds;
return this;
}

internal List<RedisValue> ToList(bool withReplicaCommands)
{
var parts = new List<RedisValue>(15)
{
RedisLiterals.KILL,
};
if (Id != null)
{
parts.Add(RedisLiterals.ID);
parts.Add(Id.Value);
}
if (ClientType != null)
{
parts.Add(RedisLiterals.TYPE);
switch (ClientType.Value)
{
case Redis.ClientType.Normal:
parts.Add(RedisLiterals.normal);
break;
case Redis.ClientType.Replica:
parts.Add(withReplicaCommands ? RedisLiterals.replica : RedisLiterals.slave);
break;
case Redis.ClientType.PubSub:
parts.Add(RedisLiterals.pubsub);
break;
default:
throw new ArgumentOutOfRangeException(nameof(ClientType));
}
}
if (Username != null)
{
parts.Add(RedisLiterals.USERNAME);
parts.Add(Username);
}
if (Endpoint != null)
{
parts.Add(RedisLiterals.ADDR);
parts.Add((RedisValue)Format.ToString(Endpoint));
}
if (ServerEndpoint != null)
{
parts.Add(RedisLiterals.LADDR);
parts.Add((RedisValue)Format.ToString(ServerEndpoint));
}
if (SkipMe != null)
{
parts.Add(RedisLiterals.SKIPME);
parts.Add(SkipMe.Value ? RedisLiterals.yes : RedisLiterals.no);
}
if (MaxAgeInSeconds != null)
{
parts.Add(RedisLiterals.MAXAGE);
parts.Add(MaxAgeInSeconds);
}
return parts;
}
}
6 changes: 5 additions & 1 deletion src/StackExchange.Redis/APITypes/GeoRadiusOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,22 +13,26 @@ public enum GeoRadiusOptions
/// 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>
/// Populates the commonly used values from the entry (the integer hash is not returned as it is not commonly useful).
/// </summary>
Default = WithCoordinates | WithDistance
Default = WithCoordinates | WithDistance,
}

internal static class GeoRadiusOptionsExtensions
Expand Down
2 changes: 1 addition & 1 deletion src/StackExchange.Redis/APITypes/GeoRadiusResult.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public readonly struct GeoRadiusResult
/// <summary>
/// The hash value of the matched member as an integer. (The key in the sorted set).
/// </summary>
/// <remarks>Note that this is not the same as the hash returned from GeoHash</remarks>
/// <remarks>Note that this is not the same as the hash returned from GeoHash.</remarks>
public long? Hash { get; }

/// <summary>
Expand Down
Loading

0 comments on commit 1541f84

Please sign in to comment.