Unverified Commit b40a47e9 authored by Nick Craver's avatar Nick Craver Committed by GitHub

Build: add Ubuntu (#914)

* Build: let's try and get Ubuntu working
* Eliminate LibraryTargetFrameworks
* Tests: only build net462 on Windows
* Oh Linux, you're gonna be fun
* More line ending love
* Move perf counter and thread bits to PerfCounterHelper
parent e167b092
......@@ -4,7 +4,7 @@
<Copyright>2017 Stack Exchange, Inc.</Copyright>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyOriginatorKeyFile>../StackExchange.Redis.snk</AssemblyOriginatorKeyFile>
<AssemblyOriginatorKeyFile>$(MSBuildThisFileDirectory)StackExchange.Redis.snk</AssemblyOriginatorKeyFile>
<PackageId>$(AssemblyName)</PackageId>
<Features>strict</Features>
<Authors>Stack Exchange, Inc.; marc.gravell</Authors>
......@@ -24,7 +24,6 @@
<DefaultLanguage>en-US</DefaultLanguage>
<IncludeSymbols>false</IncludeSymbols>
<LibraryTargetFrameworks>netstandard2.0</LibraryTargetFrameworks>
<xUnitVersion>2.4.0-beta.2.build3981</xUnitVersion>
</PropertyGroup>
<ItemGroup>
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LibraryTargetFrameworks)</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<PackageTags>Redis;Search;Modules;RediSearch</PackageTags>
<SignAssembly>true</SignAssembly>
......
echo Starting Redis servers for testing...
INDENT=' '
echo "Starting Redis servers for testing..."
#Basic Servers
echo Starting Basic: 6379-6382
echo "Starting Basic: 6379-6382"
pushd Basic > /dev/null
echo Master: 6379
echo "${INDENT}Master: 6379"
redis-server master-6379.conf &>/dev/null &
echo Slave: 6380
echo "${INDENT}Slave: 6380"
redis-server slave-6380.conf &>/dev/null &
echo Secure: 6381
echo "${INDENT}Secure: 6381"
redis-server secure-6381.conf &>/dev/null &
popd > /dev/null
#Failover Servers
echo Starting Failover: 6382-6383
pushd Failover > /dev/null
echo Master: 6382
echo "${INDENT}Master: 6382"
redis-server master-6382.conf &>/dev/null &
echo Slave: 6383
echo "${INDENT}Slave: 6383"
redis-server slave-6383.conf &>/dev/null &
popd > /dev/null
......@@ -34,10 +35,10 @@ popd > /dev/null
#Sentinel Servers
echo Starting Sentinel: 7010-7011,26379-26380
pushd Sentinel > /dev/null
echo Targets: 7010-7011
echo "${INDENT}Targets: 7010-7011"
redis-server redis-7010.conf &>/dev/null &
redis-server redis-7011.conf &>/dev/null &
echo Monitors: 26379-26380
echo "${INDENT}Monitors: 26379-26380"
redis-server sentinel-26379.conf --sentinel &>/dev/null &
redis-server sentinel-26380.conf --sentinel &>/dev/null &
popd > /dev/null
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LibraryTargetFrameworks)</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<VersionPrefix>0.1</VersionPrefix>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
<PackageTags>Redis;Search;Modules;RediSearch</PackageTags>
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LibraryTargetFrameworks)</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<Description>Basic redis server based on StackExchange.Redis</Description>
<AssemblyTitle>StackExchange.Redis</AssemblyTitle>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LibraryTargetFrameworks)</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<Description>High performance Redis client, incorporating both synchronous and asynchronous usage.</Description>
<AssemblyTitle>StackExchange.Redis.StrongName</AssemblyTitle>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
......@@ -13,7 +13,7 @@
<LangVersion>latest</LangVersion>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\StackExchange.Redis\StackExchange.Redis.csproj" />
</ItemGroup>
......
......@@ -189,9 +189,9 @@ public async Task GeoRadiusOverloads()
// Invalid overload
// Since this would throw ERR could not decode requested zset member, we catch and return something more useful to the user earlier.
var ex = Assert.Throws<ArgumentException>(() => db.GeoRadius(key, -1.759925, 52.19493, GeoUnit.Miles, 500, Order.Ascending, GeoRadiusOptions.WithDistance));
Assert.Equal("Member should not be a double, you likely want the GeoRadius(RedisKey, double, double, ...) overload.\r\nParameter name: member", ex.Message);
Assert.Equal("Member should not be a double, you likely want the GeoRadius(RedisKey, double, double, ...) overload." + Environment.NewLine + "Parameter name: member", ex.Message);
ex = await Assert.ThrowsAsync<ArgumentException>(() => db.GeoRadiusAsync(key, -1.759925, 52.19493, GeoUnit.Miles, 500, Order.Ascending, GeoRadiusOptions.WithDistance)).ForAwait();
Assert.Equal("Member should not be a double, you likely want the GeoRadius(RedisKey, double, double, ...) overload.\r\nParameter name: member", ex.Message);
Assert.Equal("Member should not be a double, you likely want the GeoRadius(RedisKey, double, double, ...) overload." + Environment.NewLine + "Parameter name: member", ex.Message);
// The good stuff
GeoRadiusResult[] result = db.GeoRadius(key, -1.759925, 52.19493, 500, unit: GeoUnit.Miles, order: Order.Ascending, options: GeoRadiusOptions.WithDistance);
......
......@@ -11,20 +11,20 @@ public class RedisFeaturesTests
var features = new RedisFeatures(new Version(2, 9));
var s = features.ToString();
Assert.True(features.ExecAbort);
Assert.StartsWith("Features in 2.9\r\n", s);
Assert.Contains("ExecAbort: True\r\n", s);
Assert.StartsWith("Features in 2.9" + Environment.NewLine, s);
Assert.Contains("ExecAbort: True" + Environment.NewLine, s);
features = new RedisFeatures(new Version(2, 9, 5));
s = features.ToString();
Assert.False(features.ExecAbort);
Assert.StartsWith("Features in 2.9.5\r\n", s);
Assert.Contains("ExecAbort: False\r\n", s);
Assert.StartsWith("Features in 2.9.5" + Environment.NewLine, s);
Assert.Contains("ExecAbort: False" + Environment.NewLine, s);
features = new RedisFeatures(new Version(3, 0));
s = features.ToString();
Assert.True(features.ExecAbort);
Assert.StartsWith("Features in 3.0\r\n", s);
Assert.Contains("ExecAbort: True\r\n", s);
Assert.StartsWith("Features in 3.0" + Environment.NewLine, s);
Assert.Contains("ExecAbort: True" + Environment.NewLine, s);
}
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>StackExchange.Redis.Tests</Description>
<TargetFrameworks>net462;netcoreapp2.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' == 'Windows_NT'">net462;netcoreapp2.0</TargetFrameworks>
<TargetFrameworks Condition="'$(OS)' != 'Windows_NT'">netcoreapp2.0</TargetFrameworks>
<AssemblyName>StackExchange.Redis.Tests</AssemblyName>
<GenerateRuntimeConfigurationFiles>true</GenerateRuntimeConfigurationFiles>
<GenerateDocumentationFile>false</GenerateDocumentationFile>
......
......@@ -623,7 +623,7 @@ private void LogLockedWithThreadPoolStats(TextWriter log, string message, out in
{
var sb = new StringBuilder();
sb.Append(message);
busyWorkerCount = GetThreadPoolStats(out string iocp, out string worker);
busyWorkerCount = PerfCounterHelper.GetThreadPoolStats(out string iocp, out string worker);
sb.Append(", IOCP: ").Append(iocp).Append(", WORKER: ").Append(worker);
LogLocked(log, sb.ToString());
}
......@@ -2177,16 +2177,16 @@ void add(string lk, string sk, string v)
// only add keyslot if its a valid cluster key slot
if (hashSlot != ServerSelectionStrategy.NoSlot)
{
add("Key-HashSlot", "keyHashSlot", message.GetHashSlot(this.ServerSelectionStrategy).ToString());
add("Key-HashSlot", "PerfCounterHelperkeyHashSlot", message.GetHashSlot(this.ServerSelectionStrategy).ToString());
}
int busyWorkerCount = GetThreadPoolStats(out string iocp, out string worker);
int busyWorkerCount = PerfCounterHelper.GetThreadPoolStats(out string iocp, out string worker);
add("ThreadPool-IO-Completion", "IOCP", iocp);
add("ThreadPool-Workers", "WORKER", worker);
data.Add(Tuple.Create("Busy-Workers", busyWorkerCount.ToString()));
if (IncludePerformanceCountersInExceptions)
{
add("Local-CPU", "Local-CPU", GetSystemCpuPercent());
add("Local-CPU", "Local-CPU", PerfCounterHelper.GetSystemCpuPercent());
}
sb.Append(" (Please take a look at this article for some common client-side issues that can cause timeouts: ");
......@@ -2222,33 +2222,6 @@ void add(string lk, string sk, string v)
}
}
internal static string GetThreadPoolAndCPUSummary(bool includePerformanceCounters)
{
GetThreadPoolStats(out string iocp, out string worker);
var cpu = includePerformanceCounters ? GetSystemCpuPercent() : "n/a";
return $"IOCP: {iocp}, WORKER: {worker}, Local-CPU: {cpu}";
}
private static string GetSystemCpuPercent()
{
return (PerfCounterHelper.TryGetSystemCPU(out float systemCPU))
? Math.Round(systemCPU, 2) + "%"
: "unavailable";
}
private static int GetThreadPoolStats(out string iocp, out string worker)
{
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxIoThreads);
ThreadPool.GetAvailableThreads(out int freeWorkerThreads, out int freeIoThreads);
ThreadPool.GetMinThreads(out int minWorkerThreads, out int minIoThreads);
int busyIoThreads = maxIoThreads - freeIoThreads;
int busyWorkerThreads = maxWorkerThreads - freeWorkerThreads;
iocp = $"(Busy={busyIoThreads},Free={freeIoThreads},Min={minIoThreads},Max={maxIoThreads})";
worker = $"(Busy={busyWorkerThreads},Free={freeWorkerThreads},Min={minWorkerThreads},Max={maxWorkerThreads})";
return busyWorkerThreads;
}
/// <summary>
/// Should exceptions include identifiable details? (key names, additional .Data annotations)
/// </summary>
......
......@@ -110,7 +110,7 @@ internal static Exception NoConnectionAvailable(bool includeDetail, bool include
if (includeDetail)
{
exceptionmessage.Append("; ").Append(ConnectionMultiplexer.GetThreadPoolAndCPUSummary(includePerformanceCounters));
exceptionmessage.Append("; ").Append(PerfCounterHelper.GetThreadPoolAndCPUSummary(includePerformanceCounters));
}
var ex = new RedisConnectionException(ConnectionFailureType.UnableToResolvePhysicalConnection, exceptionmessage.ToString(), innerException, message?.Status ?? CommandStatus.Unknown);
......
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
namespace StackExchange.Redis
{
......@@ -48,5 +49,33 @@ public static bool TryGetSystemCPU(out float value)
}
return false;
}
internal static string GetThreadPoolAndCPUSummary(bool includePerformanceCounters)
{
GetThreadPoolStats(out string iocp, out string worker);
var cpu = includePerformanceCounters ? GetSystemCpuPercent() : "n/a";
return $"IOCP: {iocp}, WORKER: {worker}, Local-CPU: {cpu}";
}
internal static string GetSystemCpuPercent()
{
return TryGetSystemCPU(out float systemCPU)
? Math.Round(systemCPU, 2) + "%"
: "unavailable";
}
internal static int GetThreadPoolStats(out string iocp, out string worker)
{
ThreadPool.GetMaxThreads(out int maxWorkerThreads, out int maxIoThreads);
ThreadPool.GetAvailableThreads(out int freeWorkerThreads, out int freeIoThreads);
ThreadPool.GetMinThreads(out int minWorkerThreads, out int minIoThreads);
int busyIoThreads = maxIoThreads - freeIoThreads;
int busyWorkerThreads = maxWorkerThreads - freeWorkerThreads;
iocp = $"(Busy={busyIoThreads},Free={freeIoThreads},Min={minIoThreads},Max={maxIoThreads})";
worker = $"(Busy={busyWorkerThreads},Free={freeWorkerThreads},Min={minWorkerThreads},Max={maxWorkerThreads})";
return busyWorkerThreads;
}
}
}
......@@ -213,7 +213,7 @@ public virtual bool SetResult(PhysicalConnection connection, Message message, Ra
unableToConnectError = true;
err = $"Endpoint {endpoint} serving hashslot {hashSlot} is not reachable at this point of time. Please check connectTimeout value. If it is low, try increasing it to give the ConnectionMultiplexer a chance to recover from the network disconnect. ";
}
err += ConnectionMultiplexer.GetThreadPoolAndCPUSummary(bridge.Multiplexer.IncludePerformanceCountersInExceptions);
err += PerfCounterHelper.GetThreadPoolAndCPUSummary(bridge.Multiplexer.IncludePerformanceCountersInExceptions);
}
}
}
......
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(LibraryTargetFrameworks)</TargetFrameworks>
<TargetFrameworks>netstandard2.0</TargetFrameworks>
<Description>High performance Redis client, incorporating both synchronous and asynchronous usage.</Description>
<AssemblyName>StackExchange.Redis</AssemblyName>
<AssemblyTitle>StackExchange.Redis</AssemblyTitle>
......@@ -17,7 +17,7 @@
<PropertyGroup Condition="'$(Configuration)' == 'Debug' and '$(Computername)'=='OCHO'">
<!--<DefineConstants>$(DefineConstants);LOGOUTPUT</DefineConstants>-->
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Pipelines.Sockets.Unofficial" Version="0.2.1-alpha.80" />
<PackageReference Include="System.Diagnostics.PerformanceCounter" Version="4.5.0" />
......
image: Visual Studio 2017
image:
- Visual Studio 2017
- Ubuntu
init:
- git config --global core.autocrlf input
......@@ -38,7 +40,18 @@ install:
redis-server.exe --service-install --service-name "redis-26380" "..\Sentinel\sentinel-26380.conf" --sentinel
cd ..\..
- ps: Start-Service redis-*
- sh: >-
cd RedisConfigs
chmod +x start-all.sh
./start-all.sh
cd ..
- ps: >-
if (Get-Command "Start-Service" -errorAction SilentlyContinue) {
Start-Service redis-*
}
skip_branch_with_pr: true
skip_tags: true
......
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