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)
if (reader.RemainingThisSpan == 0) continue;
var span = reader.SlicedSpan;
int found = span.IndexOf(value);
int found = span.VectorSafeIndexOf(value);
if (found >= 0) return totalSkipped + found;
totalSkipped += span.Length;
......@@ -168,7 +168,6 @@ public void Consume(int count)
int totalSkipped = 0;
bool haveTrailingCR = false;
ReadOnlySpan<byte> CRLF = stackalloc byte[2] { (byte)'\r', (byte)'\n' };
do
{
if (reader.RemainingThisSpan == 0) continue;
......@@ -180,7 +179,7 @@ public void Consume(int count)
haveTrailingCR = false;
}
int found = span.IndexOf(CRLF);
int found = span.VectorSafeIndexOfCRLF();
if (found >= 0) return totalSkipped + found;
haveTrailingCR = span[span.Length - 1] == '\r';
......
......@@ -966,38 +966,8 @@ internal ServerEndPoint GetServerEndPoint(EndPoint endpoint, TextWriter log = nu
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)
{
CheckNumericsVectors();
IncludeDetailInExceptions = true;
IncludePerformanceCountersInExceptions = false;
......
......@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.IO;
using System.Net.Security;
using System.Runtime.CompilerServices;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Text;
......@@ -224,5 +225,51 @@ protected override void Dispose(bool disposing)
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 @@
<!-- we should preferably not include this in release builds, but isn't dramatic -->
<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 Condition="'$(Configuration)' == 'Debug' and '$(Computername)'=='OCHO'">
<!--<DefineConstants>$(DefineConstants);LOGOUTPUT</DefineConstants>-->
</PropertyGroup>
<PropertyGroup Condition="'$(VectorSafe)' == 'true'">
<DefineConstants>$(DefineConstants);VECTOR_SAFE</DefineConstants>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Pipelines.Sockets.Unofficial" Version="1.0.0" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" 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.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
</ItemGroup>
</Project>
\ No newline at end of file
......@@ -11,15 +11,19 @@ private static async Task Main()
using (var conn = Create())
{
var sub = conn.GetSubscriber();
Console.WriteLine("Subscsribe...");
sub.Subscribe("foo", (channel, value) => Console.WriteLine($"{channel}: {value}"));
Console.WriteLine("Ping...");
sub.Ping();
Console.WriteLine("Run publish...");
await RunPub().ConfigureAwait(false);
}
await Console.Out.WriteLineAsync("Waiting a minute...").ConfigureAwait(false);
await Task.Delay(60 * 1000).ConfigureAwait(false);
}
private static ConnectionMultiplexer Create()
{
var options = new ConfigurationOptions
......@@ -29,12 +33,18 @@ private static ConnectionMultiplexer Create()
SyncTimeout = int.MaxValue,
// 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}");
muxer.ConnectionRestored += (s, a) => Console.WriteLine($"Restored: {a.ConnectionType}, {a.EndPoint}, {a.FailureType}, {a.Exception}");
muxer.GetDatabase().Ping();
Console.WriteLine("Connecting...");
var muxer = ConnectionMultiplexer.Connect(options, Console.Out);
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;
}
public static async Task RunPub()
{
using (var conn = Create())
......
......@@ -2,7 +2,7 @@
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFrameworks>netcoreapp2.1;net47</TargetFrameworks>
<TargetFrameworks>netcoreapp2.1;net462;net47</TargetFrameworks>
<LangVersion>latest</LangVersion>
</PropertyGroup>
......@@ -11,9 +11,9 @@
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\tests\BasicTest\BasicTest.csproj" />
<!--<ProjectReference Include="..\..\tests\BasicTest\BasicTest.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" />
</ItemGroup>
</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