Unverified Commit 6580a824 authored by Marc Gravell's avatar Marc Gravell Committed by GitHub

remove indirect vector usage (on < net472, at least); it breaks the world (#932)

parent 83e7d4e7
...@@ -155,7 +155,7 @@ public void Consume(int count) ...@@ -155,7 +155,7 @@ public void Consume(int count)
if (reader.RemainingThisSpan == 0) continue; if (reader.RemainingThisSpan == 0) continue;
var span = reader.SlicedSpan; var span = reader.SlicedSpan;
int found = span.IndexOf(value); int found = span.VectorSafeIndexOf(value);
if (found >= 0) return totalSkipped + found; if (found >= 0) return totalSkipped + found;
totalSkipped += span.Length; totalSkipped += span.Length;
...@@ -168,7 +168,6 @@ public void Consume(int count) ...@@ -168,7 +168,6 @@ public void Consume(int count)
int totalSkipped = 0; int totalSkipped = 0;
bool haveTrailingCR = false; bool haveTrailingCR = false;
ReadOnlySpan<byte> CRLF = stackalloc byte[2] { (byte)'\r', (byte)'\n' };
do do
{ {
if (reader.RemainingThisSpan == 0) continue; if (reader.RemainingThisSpan == 0) continue;
...@@ -180,7 +179,7 @@ public void Consume(int count) ...@@ -180,7 +179,7 @@ public void Consume(int count)
haveTrailingCR = false; haveTrailingCR = false;
} }
int found = span.IndexOf(CRLF); int found = span.VectorSafeIndexOfCRLF();
if (found >= 0) return totalSkipped + found; if (found >= 0) return totalSkipped + found;
haveTrailingCR = span[span.Length - 1] == '\r'; haveTrailingCR = span[span.Length - 1] == '\r';
......
...@@ -966,38 +966,8 @@ internal ServerEndPoint GetServerEndPoint(EndPoint endpoint, TextWriter log = nu ...@@ -966,38 +966,8 @@ internal ServerEndPoint GetServerEndPoint(EndPoint endpoint, TextWriter log = nu
internal readonly CommandMap CommandMap; internal readonly CommandMap CommandMap;
[MethodImpl(MethodImplOptions.NoInlining)]
private static void CheckNumericsVectors()
{
try
{
CheckNumericsVectorsImpl();
}
catch (Exception ex)
{
throw new InvalidOperationException(
"It looks like there's a problem resolving System.Numerics.Vectors.dll; "
+ "this is a well-known pain point between .NET Framework and .NET Core - "
+ "try adding an explicit package reference to System.Numerics.Vectors; "
+ "and if you're wondering 'why do you need that?' - we actually don't: "
+ "it is a down-stream dependency that we don't need directly, but which "
+ "keeps causing pain.", ex);
}
}
[MethodImpl(MethodImplOptions.NoInlining)]
private static void CheckNumericsVectorsImpl()
{
DoNothingWith(System.Numerics.Vector.IsHardwareAccelerated, System.Numerics.Vector<byte>.Count);
}
[MethodImpl(MethodImplOptions.NoInlining)]
#pragma warning disable RCS1163 // Unused parameter.
private static void DoNothingWith(bool b, int i) { }
#pragma warning restore RCS1163 // Unused parameter.
private ConnectionMultiplexer(ConfigurationOptions configuration) private ConnectionMultiplexer(ConfigurationOptions configuration)
{ {
CheckNumericsVectors();
IncludeDetailInExceptions = true; IncludeDetailInExceptions = true;
IncludePerformanceCountersInExceptions = false; IncludePerformanceCountersInExceptions = false;
......
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Net.Security; using System.Net.Security;
using System.Runtime.CompilerServices;
using System.Security.Authentication; using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates; using System.Security.Cryptography.X509Certificates;
using System.Text; using System.Text;
...@@ -224,5 +225,51 @@ protected override void Dispose(bool disposing) ...@@ -224,5 +225,51 @@ protected override void Dispose(bool disposing)
if (disposing) _parent.Dispose(); if (disposing) _parent.Dispose();
} }
} }
// IMPORTANT: System.Numerics.Vectors is just... broken on .NET with anything < net472; the dependency
// indirection routinely fails and causes epic levels of fail. We're going to get around this by simply
// *not using SpanHelpers.IndexOf* (which is what uses it) for net < net472 builds. I've tried every
// trick (including some that are pure evil), and I can't see a better mechanism. Ultimately, the bindings
// fail in unusual and unexpected ways, causing:
//
// Could not load file or assembly 'System.Numerics.Vectors, Version=4.1.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a'
// or one of its dependencies.The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)
//
// also; note that the nuget tools *do not* reliably (or even occasionally) produce the correct
// assembly-binding-redirect entries to fix this up, so; it would present an unreasonable support burden
// otherwise. And yes, I've tried explicitly referencing System.Numerics.Vectors in the manifest to
// force it... nothing. Nada.
#if VECTOR_SAFE
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int VectorSafeIndexOf(this ReadOnlySpan<byte> span, byte value)
=> span.IndexOf(value);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static int VectorSafeIndexOfCRLF(this ReadOnlySpan<byte> span)
{
ReadOnlySpan<byte> CRLF = stackalloc byte[2] { (byte)'\r', (byte)'\n' };
return span.IndexOf(CRLF);
}
#else
internal static int VectorSafeIndexOf(this ReadOnlySpan<byte> span, byte value)
{
// yes, this has zero optimization; I'm OK with this as the fallback strategy
for (int i = 0; i < span.Length; i++)
{
if (span[i] == value) return i;
}
return -1;
}
internal static int VectorSafeIndexOfCRLF(this ReadOnlySpan<byte> span)
{
// yes, this has zero optimization; I'm OK with this as the fallback strategy
for (int i = 1; i < span.Length; i++)
{
if (span[i] == '\n' && span[i-1] == '\r') return i - 1;
}
return -1;
}
#endif
} }
} }
...@@ -12,18 +12,29 @@ ...@@ -12,18 +12,29 @@
<!-- we should preferably not include this in release builds, but isn't dramatic --> <!-- we should preferably not include this in release builds, but isn't dramatic -->
<DefineConstants>$(DefineConstants);TEST</DefineConstants> <DefineConstants>$(DefineConstants);TEST</DefineConstants>
<VectorSafe>true</VectorSafe>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net461'">
<VectorSafe>false</VectorSafe>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net472'">
<!--<PackageReference Include="System.IO.Compression" Version="4.3.0" />-->
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug' and '$(Computername)'=='OCHO'"> <PropertyGroup Condition="'$(Configuration)' == 'Debug' and '$(Computername)'=='OCHO'">
<!--<DefineConstants>$(DefineConstants);LOGOUTPUT</DefineConstants>--> <!--<DefineConstants>$(DefineConstants);LOGOUTPUT</DefineConstants>-->
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(VectorSafe)' == 'true'">
<DefineConstants>$(DefineConstants);VECTOR_SAFE</DefineConstants>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Pipelines.Sockets.Unofficial" Version="1.0.0" /> <PackageReference Include="Pipelines.Sockets.Unofficial" Version="1.0.0" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="4.5.0" /> <PackageReference Include="System.Diagnostics.PerformanceCounter" Version="4.5.0" />
<PackageReference Include="System.IO.Pipelines" Version="4.5.0" /> <PackageReference Include="System.IO.Pipelines" Version="4.5.0" />
<PackageReference Include="System.Threading.Channels" Version="4.5.0" /> <PackageReference Include="System.Threading.Channels" Version="4.5.0" />
<PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
</ItemGroup> </ItemGroup>
</Project> </Project>
\ No newline at end of file
...@@ -11,15 +11,19 @@ private static async Task Main() ...@@ -11,15 +11,19 @@ private static async Task Main()
using (var conn = Create()) using (var conn = Create())
{ {
var sub = conn.GetSubscriber(); var sub = conn.GetSubscriber();
Console.WriteLine("Subscsribe...");
sub.Subscribe("foo", (channel, value) => Console.WriteLine($"{channel}: {value}")); sub.Subscribe("foo", (channel, value) => Console.WriteLine($"{channel}: {value}"));
Console.WriteLine("Ping...");
sub.Ping(); sub.Ping();
Console.WriteLine("Run publish...");
await RunPub().ConfigureAwait(false); await RunPub().ConfigureAwait(false);
} }
await Console.Out.WriteLineAsync("Waiting a minute...").ConfigureAwait(false); await Console.Out.WriteLineAsync("Waiting a minute...").ConfigureAwait(false);
await Task.Delay(60 * 1000).ConfigureAwait(false); await Task.Delay(60 * 1000).ConfigureAwait(false);
} }
private static ConnectionMultiplexer Create() private static ConnectionMultiplexer Create()
{ {
var options = new ConfigurationOptions var options = new ConfigurationOptions
...@@ -29,12 +33,18 @@ private static ConnectionMultiplexer Create() ...@@ -29,12 +33,18 @@ private static ConnectionMultiplexer Create()
SyncTimeout = int.MaxValue, SyncTimeout = int.MaxValue,
// CommandMap = CommandMap.Create(new HashSet<string> { "subscribe", "psubscsribe", "publish" }, false), // CommandMap = CommandMap.Create(new HashSet<string> { "subscribe", "psubscsribe", "publish" }, false),
}; };
var muxer = ConnectionMultiplexer.Connect(options);
muxer.ConnectionFailed += (s, a) => Console.WriteLine($"Failed: {a.ConnectionType}, {a.EndPoint}, {a.FailureType}, {a.Exception}"); Console.WriteLine("Connecting...");
muxer.ConnectionRestored += (s, a) => Console.WriteLine($"Restored: {a.ConnectionType}, {a.EndPoint}, {a.FailureType}, {a.Exception}"); var muxer = ConnectionMultiplexer.Connect(options, Console.Out);
muxer.GetDatabase().Ping(); Console.WriteLine("Connected");
muxer.ConnectionFailed += (_, a) => Console.WriteLine($"Failed: {a.ConnectionType}, {a.EndPoint}, {a.FailureType}, {a.Exception}");
muxer.ConnectionRestored += (_, a) => Console.WriteLine($"Restored: {a.ConnectionType}, {a.EndPoint}, {a.FailureType}, {a.Exception}");
Console.WriteLine("Ping...");
var time = muxer.GetDatabase().Ping();
Console.WriteLine($"Pinged: {time.TotalMilliseconds}ms");
return muxer; return muxer;
} }
public static async Task RunPub() public static async Task RunPub()
{ {
using (var conn = Create()) using (var conn = Create())
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.1;net47</TargetFrameworks> <TargetFrameworks>netcoreapp2.1;net462;net47</TargetFrameworks>
<LangVersion>latest</LangVersion> <LangVersion>latest</LangVersion>
</PropertyGroup> </PropertyGroup>
...@@ -11,9 +11,9 @@ ...@@ -11,9 +11,9 @@
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\..\tests\BasicTest\BasicTest.csproj" /> <!--<ProjectReference Include="..\..\tests\BasicTest\BasicTest.csproj" />
<ProjectReference Include="..\StackExchange.Redis.Server\StackExchange.Redis.Server.csproj" /> <ProjectReference Include="..\StackExchange.Redis.Server\StackExchange.Redis.Server.csproj" />
<ProjectReference Include="..\..\tests\StackExchange.Redis.Tests\StackExchange.Redis.Tests.csproj" /> <ProjectReference Include="..\..\tests\StackExchange.Redis.Tests\StackExchange.Redis.Tests.csproj" />-->
<ProjectReference Include="..\..\src\StackExchange.Redis\StackExchange.Redis.csproj" /> <ProjectReference Include="..\..\src\StackExchange.Redis\StackExchange.Redis.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
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