Skip to content

Commit a1e6e77

Browse files
authored
Update to v1.0.16. Fix disposal of migration sessions. (#530)
Problem When using KEYS option for slot migration, the migration session removal isn't disposing the session object. This leads to an out of memory exception when migrating a large number of keys. Fix Set slots correctly for the migrate operation. This helps to ensure the slots are correctly reset on removal of migration session. Also, removal of multiple outstanding session objects when node is removed for the FORGET command, will dispose each of those session objects.
1 parent dfc8d6d commit a1e6e77

File tree

6 files changed

+65
-20
lines changed

6 files changed

+65
-20
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 45) -- NOTE - these two values need to be the same
55
######################################
6-
name: 1.0.15
6+
name: 1.0.16
77
trigger:
88
branches:
99
include:

libs/cluster/Server/Migration/MigrateSessionTaskStore.cs

+37-3
Original file line numberDiff line numberDiff line change
@@ -129,23 +129,57 @@ public bool TryAddMigrateSession(
129129
return success;
130130
}
131131

132+
public bool TryRemove(MigrateSession mSession)
133+
{
134+
try
135+
{
136+
_lock.WriteLock();
137+
if (_disposed) return false;
138+
139+
foreach (var slot in mSession.GetSlots)
140+
{
141+
Debug.Assert(sessions[slot] == mSession, "MigrateSession not found in slot");
142+
sessions[slot] = null;
143+
}
144+
145+
mSession.Dispose();
146+
return true;
147+
}
148+
catch (Exception ex)
149+
{
150+
logger?.LogError(ex, "Error at TryRemove");
151+
return false;
152+
}
153+
finally
154+
{
155+
_lock.WriteUnlock();
156+
}
157+
}
158+
132159
public bool TryRemove(string targetNodeId)
133160
{
134161
try
135162
{
136163
_lock.WriteLock();
137164
if (_disposed) return false;
138-
MigrateSession mSession = null;
165+
HashSet<MigrateSession> mSessions = null;
139166
for (var i = 0; i < sessions.Length; i++)
140167
{
141168
var s = sessions[i];
142169
if (s != null && s.GetTargetNodeId.Equals(targetNodeId, StringComparison.Ordinal))
143170
{
144171
sessions[i] = null;
145-
mSession = s;
172+
mSessions ??= [];
173+
_ = mSessions.Add(s);
146174
}
147175
}
148-
mSession?.Dispose();
176+
177+
if (mSessions != null)
178+
{
179+
foreach (var session in mSessions)
180+
session.Dispose();
181+
}
182+
149183
return true;
150184
}
151185
catch (Exception ex)

libs/cluster/Server/Migration/MigrationManager.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ public bool TryAddMigrationTask(
8282
/// <param name="mSession"></param>
8383
/// <returns></returns>
8484
public bool TryRemoveMigrationTask(MigrateSession mSession)
85-
=> migrationTaskStore.TryRemove(mSession.GetTargetNodeId);
85+
=> migrationTaskStore.TryRemove(mSession);
8686

8787
/// <summary>
8888
/// Remove migration task associated with provided target nodeId

libs/cluster/Session/MigrateCommand.cs

+2
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,8 @@ private bool TryMIGRATE(int count, byte* ptr)
182182
// Add pointer of current parsed key
183183
if (!keys.TryAdd(new ArgSlice(keyPtr, ksize), KeyMigrationStatus.QUEUED))
184184
logger?.LogWarning($"Failed to add {{key}}", Encoding.ASCII.GetString(keyPtr, ksize));
185+
else
186+
_ = slots.Add(slot);
185187
}
186188
}
187189
else if (option.Equals("SLOTS", StringComparison.OrdinalIgnoreCase))

libs/host/GarnetServer.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public class GarnetServer : IDisposable
4343
protected StoreWrapper storeWrapper;
4444

4545
// IMPORTANT: Keep the version in sync with .azure\pipelines\azure-pipelines-external-release.yml line ~6.
46-
readonly string version = "1.0.15";
46+
readonly string version = "1.0.16";
4747

4848
/// <summary>
4949
/// Resp protocol version

test/Garnet.test.cluster/ClusterMigrateTests.cs

+23-14
Original file line numberDiff line numberDiff line change
@@ -1572,6 +1572,8 @@ Task<byte[]> WriteWorkload(IPEndPoint endPoint, byte[] key, int keyLen = 16)
15721572
}
15731573
}
15741574

1575+
[Test, Order(16)]
1576+
[Category("CLUSTER")]
15751577
public void ClusterMigrateForgetTest()
15761578
{
15771579
context.logger.LogDebug($"0. ClusterSimpleMigrateSlotsRanges started");
@@ -1585,23 +1587,30 @@ public void ClusterMigrateForgetTest()
15851587
var sourceNodeId = context.clusterTestUtils.ClusterMyId(sourceNodeIndex, context.logger);
15861588
var targetNodeId = context.clusterTestUtils.ClusterMyId(targetNodeIndex, context.logger);
15871589

1588-
var resp = context.clusterTestUtils.SetSlot(sourceNodeIndex, 0, "MIGRATING", targetNodeId, context.logger);
1589-
Assert.AreEqual("OK", resp);
1590-
1591-
var slotState = context.clusterTestUtils.SlotState(sourceNodeIndex, 0, context.logger);
1592-
Assert.AreEqual(3, slotState.Length);
1593-
Assert.AreEqual("0", slotState[0]);
1594-
Assert.AreEqual(">", slotState[1]);
1595-
Assert.AreEqual(targetNodeId, slotState[2]);
1590+
var numSlots = 3;
1591+
for (var slot = 0; slot < numSlots; slot++)
1592+
{
1593+
var migresp = context.clusterTestUtils.SetSlot(sourceNodeIndex, slot, "MIGRATING", targetNodeId, context.logger);
1594+
Assert.AreEqual("OK", migresp);
1595+
1596+
var slotState = context.clusterTestUtils.SlotState(sourceNodeIndex, slot, context.logger);
1597+
Assert.AreEqual(3, slotState.Length);
1598+
Assert.AreEqual(slot.ToString(), slotState[0]);
1599+
Assert.AreEqual(">", slotState[1]);
1600+
Assert.AreEqual(targetNodeId, slotState[2]);
1601+
}
15961602

1597-
resp = context.clusterTestUtils.ClusterForget(sourceNodeIndex, targetNodeId, 100, context.logger);
1603+
var resp = context.clusterTestUtils.ClusterForget(sourceNodeIndex, targetNodeId, 100, context.logger);
15981604
Assert.AreEqual("OK", resp);
15991605

1600-
slotState = context.clusterTestUtils.SlotState(sourceNodeIndex, 0, context.logger);
1601-
Assert.AreEqual(3, slotState.Length);
1602-
Assert.AreEqual("0", slotState[0]);
1603-
Assert.AreEqual("=", slotState[1]);
1604-
Assert.AreEqual(sourceNodeId, slotState[2]);
1606+
for (var slot = 0; slot < numSlots; slot++)
1607+
{
1608+
var slotState = context.clusterTestUtils.SlotState(sourceNodeIndex, slot, context.logger);
1609+
Assert.AreEqual(3, slotState.Length);
1610+
Assert.AreEqual(slot.ToString(), slotState[0]);
1611+
Assert.AreEqual("=", slotState[1]);
1612+
Assert.AreEqual(sourceNodeId, slotState[2]);
1613+
}
16051614
}
16061615
}
16071616
}

0 commit comments

Comments
 (0)