Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion libs/cluster/Server/Gossip/GarnetServerNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ internal sealed class GarnetServerNode
/// </summary>
const int defaultMaxOutstandingTask = 8;

internal static int GetClientTimeoutMilliseconds(int clusterTimeoutSeconds)
=> clusterTimeoutSeconds <= 0 ? 0 : (int)Math.Min((long)clusterTimeoutSeconds * 1000, int.MaxValue);

/// <summary>
/// GarnetServerNode constructor
/// </summary>
Expand All @@ -83,7 +86,7 @@ public GarnetServerNode(ClusterProvider clusterProvider, EndPoint endpoint, SslC
tlsOptions,
sendPageSize: opts.DisablePubSub ? defaultSendPageSize : Math.Max(defaultSendPageSize, (int)opts.PubSubPageSizeBytes()),
maxOutstandingTasks: defaultMaxOutstandingTask,
timeoutMilliseconds: opts.ClusterTimeout <= 0 ? 0 : TimeSpan.FromSeconds(opts.ClusterTimeout).Milliseconds,
timeoutMilliseconds: GetClientTimeoutMilliseconds(opts.ClusterTimeout),
authUsername: clusterProvider.clusterManager.clusterProvider.ClusterUsername,
authPassword: clusterProvider.clusterManager.clusterProvider.ClusterPassword,
epoch: epoch,
Expand Down
2 changes: 1 addition & 1 deletion libs/server/Servers/GarnetServerOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ public class GarnetServerOptions : ServerOptions
/// <summary>
/// Frequency (in seconds) of logging (used for tracking progress of long running operations e.g. migration)
/// </summary>
public int LoggingFrequency = TimeSpan.FromSeconds(5).Seconds;
public int LoggingFrequency = 5;

/// <summary>
/// Metrics sampling frequency
Expand Down
47 changes: 47 additions & 0 deletions test/cluster/Garnet.test.cluster/GarnetServerNodeTimeoutTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.

using Garnet.cluster;
using NUnit.Framework;
using NUnit.Framework.Legacy;

namespace Garnet.test.cluster
{
/// <summary>
/// Regression tests for the gossip-connection client timeout computation
/// (<see cref="GarnetServerNode.GetClientTimeoutMilliseconds(int)"/>), which previously used
/// <c>TimeSpan.Milliseconds</c> (sub-second component) instead of the full millisecond total.
/// </summary>
[TestFixture]
public class GarnetServerNodeTimeoutTests : TestBase
{
[Test]
[TestCase(1, 1_000)]
[TestCase(5, 5_000)]
[TestCase(60, 60_000)] // production default; buggy code yielded 0 here
[TestCase(3600, 3_600_000)]
public void ClientTimeoutUsesTotalMilliseconds(int clusterTimeoutSeconds, int expectedMilliseconds)
{
var actual = GarnetServerNode.GetClientTimeoutMilliseconds(clusterTimeoutSeconds);
ClassicAssert.AreEqual(expectedMilliseconds, actual);
}

[Test]
[TestCase(0)]
[TestCase(-1)]
public void NonPositiveClusterTimeoutDisablesClientTimeout(int clusterTimeoutSeconds)
{
var actual = GarnetServerNode.GetClientTimeoutMilliseconds(clusterTimeoutSeconds);
ClassicAssert.AreEqual(0, actual);
}

[Test]
[TestCase(2_147_484)] // *1000 overflows int; naive cast would wrap negative and disable the timeout
[TestCase(int.MaxValue)]
public void LargeClusterTimeoutClampsToIntMaxValue(int clusterTimeoutSeconds)
{
var actual = GarnetServerNode.GetClientTimeoutMilliseconds(clusterTimeoutSeconds);
ClassicAssert.AreEqual(int.MaxValue, actual);
}
}
}
4 changes: 2 additions & 2 deletions test/standalone/Garnet.test.scripting/RespAofTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ public async Task AofExpiryRMWStoreRecoverTestAsync()
// Verify 2nd string ttl
var recoveredValueTtl = db.KeyTimeToLive("AofExpiryRMWStoreRecoverTestKey2");
ClassicAssert.IsTrue(recoveredValueTtl.HasValue);
ClassicAssert.Less(recoveredValueTtl.Value.Milliseconds, 8500);
ClassicAssert.LessOrEqual(recoveredValueTtl.Value.TotalMilliseconds, 10_000);
ClassicAssert.Greater(recoveredValueTtl.Value.TotalSeconds, 0);
}

Expand Down Expand Up @@ -409,7 +409,7 @@ public async Task AofExpiryUpsertStoreRecoverTestAsync()
// Verify 2nd string ttl
var recoveredValueTtl = db.KeyTimeToLive("AofExpiryUpsertStoreRecoverTestKey2");
ClassicAssert.IsTrue(recoveredValueTtl.HasValue);
ClassicAssert.Less(recoveredValueTtl.Value.Milliseconds, 8500);
ClassicAssert.LessOrEqual(recoveredValueTtl.Value.TotalMilliseconds, 10_000);
ClassicAssert.Greater(recoveredValueTtl.Value.TotalSeconds, 0);
}

Expand Down
Loading