Skip to content

Commit eb40cd9

Browse files
authored
Reuse Large Buffers in MigrateSession (#623)
* add buffer pool to migration manager * expose separate receive and send buffers from NetworkHandler * add network buffers wrapper to gcs * push NetworkBuffers to NetworkHandler * add networkBuffers instance in migration manager * add constructor * reuse buffer for replication communication * consolidate network buffer pool * nit * add gc collect for migration buffer pool * add ACL test for MIGRATEGC * make migrategc management commands * add verbose logging for IOCallback * expose maxEntries from NetworkBuffers.Allocate * configure GarnetClient for Failover * cleanup ReplicationManager * Cancel cts before disposing in AofSyncTask * consolidate buffer pool purge under a single command * purge without disposing pool * introduce info bpstats metrics * ensure shared bp uses correct allocation size for send and recv * fix bp stats call * change format of info bpstats * fix out of bounds level request for LFBP * introduce purge for server buffer pool * move PURGEBP in server namespace * fix migrate bench keys option * fix formatting * add outOfBound allocation request metric * augment migrate bench * separate pool definition from buffer spec * rename to NetworkBufferSettings * rename NetworkBuffers to NetworkBufferSettings * revert dispose order * revert replication networkSettings * add timeout to dispose of LFBP * add timeout in cluster test TearDown * addressing review comments * add constants for NetworkBufferSettings in ReplicationManager * rename types for purgebp * rename to createBufferPool * bump Garnet version * add comments to LFBP * remove unused variables
1 parent 9e45dec commit eb40cd9

File tree

57 files changed

+835
-190
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+835
-190
lines changed

.azure/pipelines/azure-pipelines-external-release.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
# 1) update the name: string below (line 6) -- this is the version for the nuget package (e.g. 1.0.0)
44
# 2) update \libs\host\GarnetServer.cs readonly string version (~line 53) -- NOTE - these two values need to be the same
55
######################################
6-
name: 1.0.28
6+
name: 1.0.29
77
trigger:
88
branches:
99
include:

benchmark/Resp.benchmark/Program.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ static void Main(string[] args)
195195

196196
static void WaitForServer(Options opts)
197197
{
198-
using var client = new GarnetClientSession(opts.Address, opts.Port, opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
198+
using var client = new GarnetClientSession(opts.Address, opts.Port, new(), tlsOptions: opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
199199
while (true)
200200
{
201201
try

benchmark/Resp.benchmark/RespOnlineBench.cs

+8-4
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ private void InitializeClients()
157157
{
158158
gcsPool = new AsyncPool<GarnetClientSession>(opts.NumThreads.First(), () =>
159159
{
160-
var c = new GarnetClientSession(address, port, opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
160+
var c = new GarnetClientSession(address, port, new(), tlsOptions: opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
161161
c.Connect();
162162
if (auth != null)
163163
{
@@ -573,8 +573,8 @@ public async void OpRunnerGarnetClientSession(int thread_id)
573573
client = new GarnetClientSession(
574574
address,
575575
port,
576-
opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null,
577-
bufferSize: Math.Max(bufferSizeValue, opts.ValueLength * opts.IntraThreadParallelism));
576+
new(Math.Max(bufferSizeValue, opts.ValueLength * opts.IntraThreadParallelism)),
577+
tlsOptions: opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
578578
client.Connect();
579579
if (auth != null)
580580
{
@@ -669,7 +669,11 @@ public async void OpRunnerGarnetClientSessionParallel(int thread_id, int paralle
669669
GarnetClientSession client = null;
670670
if (!opts.Pool)
671671
{
672-
client = new GarnetClientSession(address, port, opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null, null, null, Math.Max(131072, opts.IntraThreadParallelism * opts.ValueLength));
672+
client = new GarnetClientSession(
673+
address,
674+
port,
675+
new NetworkBufferSettings(Math.Max(131072, opts.IntraThreadParallelism * opts.ValueLength)),
676+
tlsOptions: opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
673677
client.Connect();
674678
if (auth != null)
675679
{

benchmark/Resp.benchmark/RespPerfBench.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,7 @@ private void GarnetClientSessionOperateThreadRunner(int NumOps, OpType opType, R
407407
default:
408408
throw new Exception($"opType: {opType} benchmark not supported with GarnetClientSession!");
409409
}
410-
var c = new GarnetClientSession(opts.Address, opts.Port, opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
410+
var c = new GarnetClientSession(opts.Address, opts.Port, new(), tlsOptions: opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
411411
c.Connect();
412412
if (opts.Auth != null)
413413
{

benchmark/Resp.benchmark/TxnPerfBench.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ public void Run()
107107
{
108108
gcsPool = new AsyncPool<GarnetClientSession>(opts.NumThreads.First(), () =>
109109
{
110-
var c = new GarnetClientSession(address, port, opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
110+
var c = new GarnetClientSession(address, port, new(), tlsOptions: opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
111111
c.Connect();
112112
if (auth != null)
113113
{
@@ -325,7 +325,7 @@ public void OpRunnerSERedis(int thread_id)
325325
public void LoadData()
326326
{
327327
var req = new OnlineReqGen(0, opts.DbSize, true, opts.Zipf, opts.KeyLength, opts.ValueLength);
328-
GarnetClientSession client = new(address, port, opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
328+
GarnetClientSession client = new(address, port, new(), tlsOptions: opts.EnableTLS ? BenchUtils.GetTlsOptions(opts.TlsHost, opts.CertFileName, opts.CertPassword) : null);
329329
client.Connect();
330330
if (auth != null)
331331
{

libs/client/ClientSession/GarnetClientSession.cs

+45-12
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ public sealed unsafe partial class GarnetClientSession : IServerHook, IMessageCo
2323
{
2424
readonly string address;
2525
readonly int port;
26-
readonly int bufferSize;
2726
readonly int bufferSizeDigits;
2827
INetworkSender networkSender;
2928
readonly ElasticCircularBuffer<TaskType> tasksTypes = new();
@@ -61,8 +60,6 @@ public sealed unsafe partial class GarnetClientSession : IServerHook, IMessageCo
6160
/// </summary>
6261
public bool IsConnected => socket != null && socket.Connected && !Disposed;
6362

64-
readonly LimitedFixedBufferPool networkPool;
65-
6663
/// <summary>
6764
/// Username to authenticate the session on the server.
6865
/// </summary>
@@ -73,6 +70,21 @@ public sealed unsafe partial class GarnetClientSession : IServerHook, IMessageCo
7370
/// </summary>
7471
readonly string authPassword = null;
7572

73+
/// <summary>
74+
/// Indicating whether this instance is using its own network pool or one that was provided
75+
/// </summary>
76+
readonly bool usingManagedNetworkPool = false;
77+
78+
/// <summary>
79+
/// Instance of network buffer settings describing the send and receive buffer sizes
80+
/// </summary>
81+
readonly NetworkBufferSettings networkBufferSettings;
82+
83+
/// <summary>
84+
/// NetworkPool used to allocate send and receive buffers
85+
/// </summary>
86+
readonly LimitedFixedBufferPool networkPool;
87+
7688
/// <summary>
7789
/// Create client instance
7890
/// </summary>
@@ -81,16 +93,29 @@ public sealed unsafe partial class GarnetClientSession : IServerHook, IMessageCo
8193
/// <param name="tlsOptions">TLS options</param>
8294
/// <param name="authUsername">Username to authenticate with</param>
8395
/// <param name="authPassword">Password to authenticate with</param>
84-
/// <param name="bufferSize">Network buffer size</param>
96+
/// <param name="networkBufferSettings">Settings for send and receive network buffers</param>
97+
/// <param name="networkPool">Buffer pool to use for allocating send and receive buffers</param>
8598
/// <param name="networkSendThrottleMax">Max outstanding network sends allowed</param>
8699
/// <param name="logger">Logger</param>
87-
public GarnetClientSession(string address, int port, SslClientAuthenticationOptions tlsOptions = null, string authUsername = null, string authPassword = null, int bufferSize = 1 << 17, int networkSendThrottleMax = 8, ILogger logger = null)
100+
public GarnetClientSession(
101+
string address,
102+
int port,
103+
NetworkBufferSettings networkBufferSettings,
104+
LimitedFixedBufferPool networkPool = null,
105+
SslClientAuthenticationOptions tlsOptions = null,
106+
string authUsername = null,
107+
string authPassword = null,
108+
int networkSendThrottleMax = 8,
109+
ILogger logger = null)
88110
{
89-
this.networkPool = new LimitedFixedBufferPool(bufferSize, logger: logger);
90111
this.address = address;
91112
this.port = port;
92-
this.bufferSize = bufferSize;
93-
this.bufferSizeDigits = NumUtils.NumDigits(bufferSize);
113+
114+
this.usingManagedNetworkPool = networkPool != null;
115+
this.networkBufferSettings = networkBufferSettings;
116+
this.networkPool = networkPool ?? networkBufferSettings.CreateBufferPool();
117+
this.bufferSizeDigits = NumUtils.NumDigits(this.networkBufferSettings.sendBufferSize);
118+
94119
this.logger = logger;
95120
this.sslOptions = tlsOptions;
96121
this.networkSendThrottleMax = networkSendThrottleMax;
@@ -107,7 +132,15 @@ public GarnetClientSession(string address, int port, SslClientAuthenticationOpti
107132
public void Connect(int timeoutMs = 0, CancellationToken token = default)
108133
{
109134
socket = GetSendSocket(address, port, timeoutMs);
110-
networkHandler = new GarnetClientSessionTcpNetworkHandler(this, socket, networkPool, sslOptions != null, this, networkSendThrottleMax, logger);
135+
networkHandler = new GarnetClientSessionTcpNetworkHandler(
136+
this,
137+
socket,
138+
networkBufferSettings,
139+
networkPool,
140+
sslOptions != null,
141+
messageConsumer: this,
142+
networkSendThrottleMax: networkSendThrottleMax,
143+
logger: logger);
111144
networkHandler.StartAsync(sslOptions, $"{address}:{port}", token).ConfigureAwait(false).GetAwaiter().GetResult();
112145
networkSender = networkHandler.GetNetworkSender();
113146
networkSender.GetResponseObject();
@@ -159,7 +192,7 @@ public void Dispose()
159192
networkSender?.ReturnResponseObject();
160193
socket?.Dispose();
161194
networkHandler?.Dispose();
162-
networkPool.Dispose();
195+
if (!usingManagedNetworkPool) networkPool.Dispose();
163196
}
164197

165198
/// <summary>
@@ -259,8 +292,8 @@ public void ExecuteClusterAppendLog(string nodeId, long previousAddress, long cu
259292
}
260293
offset = curr;
261294

262-
if (payloadLength > bufferSize)
263-
throw new Exception($"Payload length {payloadLength} is larger than bufferSize {bufferSize} bytes");
295+
if (payloadLength > networkBufferSettings.sendBufferSize)
296+
throw new Exception($"Payload length {payloadLength} is larger than bufferSize {networkBufferSettings.sendBufferSize} bytes");
264297

265298
while (!RespWriteUtils.WriteBulkString(new Span<byte>((void*)payloadPtr, payloadLength), ref curr, end))
266299
{

libs/client/ClientSession/GarnetClientSessionTcpNetworkHandler.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ namespace Garnet.client
1010
{
1111
sealed class GarnetClientSessionTcpNetworkHandler : TcpNetworkHandlerBase<GarnetClientSession, GarnetTcpNetworkSender>
1212
{
13-
public GarnetClientSessionTcpNetworkHandler(GarnetClientSession serverHook, Socket socket, LimitedFixedBufferPool networkPool, bool useTLS, IMessageConsumer messageConsumer, int networkSendThrottleMax = 8, ILogger logger = null)
14-
: base(serverHook, new GarnetTcpNetworkSender(socket, networkPool, networkSendThrottleMax), socket, networkPool, useTLS, messageConsumer, logger)
13+
public GarnetClientSessionTcpNetworkHandler(GarnetClientSession serverHook, Socket socket, NetworkBufferSettings networkBufferSettings, LimitedFixedBufferPool networkPool, bool useTLS, IMessageConsumer messageConsumer, int networkSendThrottleMax = 8, ILogger logger = null)
14+
: base(serverHook, new GarnetTcpNetworkSender(socket, networkBufferSettings, networkPool, networkSendThrottleMax), socket, networkBufferSettings, networkPool, useTLS, messageConsumer: messageConsumer, logger: logger)
1515
{
1616
}
1717

libs/client/ClientTcpNetworkSender.cs

+3-2
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,11 @@ public class ClientTcpNetworkSender : GarnetTcpNetworkSender
2222
/// </summary>
2323
/// <param name="socket"></param>
2424
/// <param name="callback"></param>
25+
/// <param name="networkBufferSettings"></param>
2526
/// <param name="networkPool"></param>
2627
/// <param name="networkSendThrottleMax"></param>
27-
public ClientTcpNetworkSender(Socket socket, Action<object> callback, LimitedFixedBufferPool networkPool, int networkSendThrottleMax)
28-
: base(socket, networkPool, networkSendThrottleMax)
28+
public ClientTcpNetworkSender(Socket socket, Action<object> callback, NetworkBufferSettings networkBufferSettings, LimitedFixedBufferPool networkPool, int networkSendThrottleMax)
29+
: base(socket, networkBufferSettings, networkPool, networkSendThrottleMax)
2930
{
3031
this.callback = callback;
3132
this.reusableSaea = new SimpleObjectPool<SocketAsyncEventArgs>(() =>

libs/client/GarnetClient.cs

+5-2
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ public sealed partial class GarnetClient : IServerHook, IMessageConsumer, IDispo
4747
readonly string address;
4848
readonly int port;
4949
readonly int sendPageSize;
50+
readonly int bufferSize;
5051
readonly int maxOutstandingTasks;
5152
NetworkWriter networkWriter;
5253
INetworkSender networkSender;
@@ -133,6 +134,7 @@ public GarnetClient(
133134
string authUsername = null,
134135
string authPassword = null,
135136
int sendPageSize = 1 << 21,
137+
int bufferSize = 1 << 17,
136138
int maxOutstandingTasks = 1 << 19,
137139
int timeoutMilliseconds = 0,
138140
MemoryPool<byte> memoryPool = null,
@@ -144,6 +146,7 @@ public GarnetClient(
144146
this.address = address;
145147
this.port = port;
146148
this.sendPageSize = (int)Utility.PreviousPowerOf2(sendPageSize);
149+
this.bufferSize = bufferSize;
147150
this.authUsername = authUsername;
148151
this.authPassword = authPassword;
149152

@@ -186,7 +189,7 @@ public GarnetClient(
186189
public void Connect(CancellationToken token = default)
187190
{
188191
socket = GetSendSocket(timeoutMilliseconds);
189-
networkWriter = new NetworkWriter(this, socket, 1 << 17, sslOptions, out networkHandler, sendPageSize, networkSendThrottleMax, logger);
192+
networkWriter = new NetworkWriter(this, socket, bufferSize, sslOptions, out networkHandler, sendPageSize, networkSendThrottleMax, logger);
190193
networkHandler.StartAsync(sslOptions, $"{address}:{port}", token).ConfigureAwait(false).GetAwaiter().GetResult();
191194
networkSender = networkHandler.GetNetworkSender();
192195

@@ -219,7 +222,7 @@ public void Connect(CancellationToken token = default)
219222
public async Task ConnectAsync(CancellationToken token = default)
220223
{
221224
socket = GetSendSocket(timeoutMilliseconds);
222-
networkWriter = new NetworkWriter(this, socket, 1 << 17, sslOptions, out networkHandler, sendPageSize, networkSendThrottleMax, logger);
225+
networkWriter = new NetworkWriter(this, socket, bufferSize, sslOptions, out networkHandler, sendPageSize, networkSendThrottleMax, logger);
223226
await networkHandler.StartAsync(sslOptions, $"{address}:{port}", token).ConfigureAwait(false);
224227
networkSender = networkHandler.GetNetworkSender();
225228

libs/client/GarnetClientTcpNetworkHandler.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@ namespace Garnet.client
1111
{
1212
sealed class GarnetClientTcpNetworkHandler : TcpNetworkHandlerBase<GarnetClient, ClientTcpNetworkSender>
1313
{
14-
public GarnetClientTcpNetworkHandler(GarnetClient serverHook, Action<object> callback, Socket socket, LimitedFixedBufferPool networkPool, bool useTLS, IMessageConsumer messageConsumer, int networkSendThrottleMax = 8, ILogger logger = null)
15-
: base(serverHook, new ClientTcpNetworkSender(socket, callback, networkPool, networkSendThrottleMax), socket, networkPool, useTLS, messageConsumer, logger)
14+
public GarnetClientTcpNetworkHandler(GarnetClient serverHook, Action<object> callback, Socket socket, NetworkBufferSettings networkBufferSettings, LimitedFixedBufferPool networkPool, bool useTLS, IMessageConsumer messageConsumer, int networkSendThrottleMax = 8, ILogger logger = null)
15+
: base(serverHook, new ClientTcpNetworkSender(socket, callback, networkBufferSettings, networkPool, networkSendThrottleMax), socket, networkBufferSettings, networkPool, useTLS, messageConsumer: messageConsumer, logger: logger)
1616
{
1717
}
1818

libs/client/NetworkWriter.cs

+5-3
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ internal sealed class NetworkWriter : IDisposable
7272
/// </summary>
7373
CompletionEvent FlushEvent;
7474

75+
readonly NetworkBufferSettings networkBufferSettings;
7576
readonly LimitedFixedBufferPool networkPool;
7677
readonly GarnetClientTcpNetworkHandler networkHandler;
7778

@@ -80,10 +81,11 @@ internal sealed class NetworkWriter : IDisposable
8081
/// </summary>
8182
public NetworkWriter(GarnetClient serverHook, Socket socket, int messageBufferSize, SslClientAuthenticationOptions sslOptions, out GarnetClientTcpNetworkHandler networkHandler, int sendPageSize, int networkSendThrottleMax, ILogger logger = null)
8283
{
83-
this.networkPool = new LimitedFixedBufferPool(messageBufferSize, logger: logger);
84+
this.networkBufferSettings = new NetworkBufferSettings(messageBufferSize, messageBufferSize);
85+
this.networkPool = networkBufferSettings.CreateBufferPool(logger: logger);
8486

8587
if (BufferSize > PageOffset.kPageMask) throw new Exception();
86-
this.networkHandler = networkHandler = new GarnetClientTcpNetworkHandler(serverHook, AsyncFlushPageCallback, socket, networkPool, sslOptions != null, serverHook, networkSendThrottleMax, logger);
88+
this.networkHandler = networkHandler = new GarnetClientTcpNetworkHandler(serverHook, AsyncFlushPageCallback, socket, networkBufferSettings, networkPool, sslOptions != null, serverHook, networkSendThrottleMax: networkSendThrottleMax, logger: logger);
8789
networkSender = networkHandler.GetNetworkSender();
8890

8991
FlushEvent.Initialize();
@@ -109,7 +111,7 @@ public void Dispose()
109111
FlushEvent.Dispose();
110112
epoch.Dispose();
111113
networkHandler.Dispose();
112-
networkPool.Dispose();
114+
networkPool?.Dispose();
113115
}
114116

115117
/// <summary>

libs/cluster/Server/ClusterProvider.cs

+13
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,19 @@ public MetricsItem[] GetGossipStats(bool metricsDisabled)
272272
];
273273
}
274274

275+
public MetricsItem[] GetBufferPoolStats()
276+
=> [new("migration_manager", migrationManager.GetBufferPoolStats()), new("replication_manager", replicationManager.GetBufferPoolStats())];
277+
278+
public void PurgeBufferPool(ManagerType managerType)
279+
{
280+
if (managerType == ManagerType.MigrationManager)
281+
migrationManager.Purge();
282+
else if (managerType == ManagerType.ReplicationManager)
283+
replicationManager.Purge();
284+
else
285+
throw new GarnetException();
286+
}
287+
275288
internal ReplicationLogCheckpointManager GetReplicationLogCheckpointManager(StoreType storeType)
276289
{
277290
Debug.Assert(serverOptions.EnableCluster);

libs/cluster/Server/ClusterUtils.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,8 @@ public static void IOCallback(this ILogger logger, uint errorCode, uint numBytes
9595
{
9696
if (errorCode != 0)
9797
{
98-
string errorMessage = new Win32Exception((int)errorCode).Message;
99-
logger.LogError("OverlappedStream GetQueuedCompletionStatus error: {errorCode} msg: {errorMessage}", errorCode, errorMessage);
98+
var errorMessage = new Win32Exception((int)errorCode).Message;
99+
logger.LogError("[ClusterUtils] OverlappedStream GetQueuedCompletionStatus error: {errorCode} msg: {errorMessage}", errorCode, errorMessage);
100100
}
101101
((SemaphoreSlim)context).Release();
102102
}

0 commit comments

Comments
 (0)