Skip to content

Commit 683e0e4

Browse files
committed
Blocking pops should remove List/Set objects if entirely popped, just like non-blocking pops do.
1 parent 2ac963a commit 683e0e4

File tree

2 files changed

+36
-13
lines changed

2 files changed

+36
-13
lines changed

libs/server/Objects/ItemBroker/CollectionItemBroker.cs

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -457,12 +457,12 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession,
457457
dstKey = cmdArgs[0];
458458
}
459459

460+
var asKey = storageSession.scratchBufferManager.CreateArgSlice(key);
460461
// Create a transaction if not currently in a running transaction
461462
if (storageSession.txnManager.state != TxnState.Running)
462463
{
463464
Debug.Assert(storageSession.txnManager.state == TxnState.None);
464465
createTransaction = true;
465-
var asKey = storageSession.scratchBufferManager.CreateArgSlice(key);
466466
if (initial)
467467
storageSession.txnManager.SaveKeyEntryToLock(asKey, false, LockType.Exclusive);
468468
storageSession.txnManager.SaveKeyEntryToLock(asKey, true, LockType.Exclusive);
@@ -477,6 +477,7 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession,
477477
_ = storageSession.txnManager.Run(true);
478478
}
479479

480+
var lockableContext = storageSession.txnManager.LockableContext;
480481
var objectLockableContext = storageSession.txnManager.ObjectStoreLockableContext;
481482
IGarnetObject dstObj = null;
482483
byte[] arrDstKey = default;
@@ -490,10 +491,7 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession,
490491
if (!initial)
491492
return false;
492493

493-
var context = storageSession.txnManager.LockableContext;
494-
495-
var keySlice = storageSession.scratchBufferManager.CreateArgSlice(key);
496-
statusOp = storageSession.GET(keySlice, out ArgSlice _, ref context);
494+
statusOp = storageSession.GET(asKey, out ArgSlice _, ref lockableContext);
497495

498496
if (statusOp != GarnetStatus.NOTFOUND)
499497
{
@@ -511,7 +509,7 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession,
511509
return true;
512510
}
513511

514-
dstStatusOp = storageSession.GET(dstKey, out ArgSlice _, ref context);
512+
dstStatusOp = storageSession.GET(dstKey, out ArgSlice _, ref lockableContext);
515513
if (dstStatusOp != GarnetStatus.NOTFOUND)
516514
{
517515
result = new CollectionItemResult(GarnetStatus.WRONGTYPE);
@@ -543,13 +541,14 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession,
543541
if (currCount == 0)
544542
return false;
545543

544+
var isSuccessful = false;
546545
switch (command)
547546
{
548547
case RespCommand.BLPOP:
549548
case RespCommand.BRPOP:
550-
var isSuccessful = TryGetNextListItem(listObj, command, out var nextItem);
549+
isSuccessful = TryGetNextListItem(listObj, command, out var nextItem);
551550
result = new CollectionItemResult(key, nextItem);
552-
return isSuccessful;
551+
break;
553552
case RespCommand.BLMOVE:
554553
ListObject dstList;
555554
var newObj = false;
@@ -577,8 +576,7 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession,
577576
isSuccessful = storageSession.SET(arrDstKey, dstList, ref objectLockableContext) ==
578577
GarnetStatus.OK;
579578
}
580-
581-
return isSuccessful;
579+
break;
582580
case RespCommand.BLMPOP:
583581
var popDirection = (OperationDirection)cmdArgs[0].ReadOnlySpan[0];
584582
var popCount = *(int*)(cmdArgs[1].ptr);
@@ -592,11 +590,19 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession,
592590
}
593591

594592
result = new CollectionItemResult(key, items);
595-
return true;
593+
isSuccessful = true;
594+
break;
596595
default:
597596
result = new CollectionItemResult(GarnetStatus.WRONGTYPE);
598597
return initial;
599598
}
599+
600+
if (isSuccessful && listObj.LnkList.Count == 0)
601+
{
602+
_ = storageSession.EXPIRE(asKey, TimeSpan.Zero, out _, StoreType.Object, ExpireOption.None,
603+
ref lockableContext, ref objectLockableContext);
604+
}
605+
return isSuccessful;
600606
case SortedSetObject setObj:
601607
currCount = setObj.Count();
602608
if (objectType != GarnetObjectType.SortedSet)
@@ -607,8 +613,13 @@ private unsafe bool TryGetResult(byte[] key, StorageSession storageSession,
607613
if (currCount == 0)
608614
return false;
609615

610-
return TryGetNextSetObjects(key, setObj, currCount, command, cmdArgs, out result);
611-
616+
isSuccessful = TryGetNextSetObjects(key, setObj, currCount, command, cmdArgs, out result);
617+
if (isSuccessful && setObj.Count() == 0)
618+
{
619+
_ = storageSession.EXPIRE(asKey, TimeSpan.Zero, out _, StoreType.Object, ExpireOption.None,
620+
ref lockableContext, ref objectLockableContext);
621+
}
622+
return isSuccessful;
612623
default:
613624
result = new CollectionItemResult(GarnetStatus.WRONGTYPE);
614625
return initial;

test/Garnet.test/RespBlockingCollectionTests.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,11 @@ public void BlmpopBlockingWithCountTest()
414414
Task.WaitAll([blockingTask, pushingTask], TimeSpan.FromSeconds(10));
415415
ClassicAssert.IsTrue(blockingTask.IsCompletedSuccessfully);
416416
ClassicAssert.IsTrue(pushingTask.IsCompletedSuccessfully);
417+
418+
using var lightClientRequest = TestUtils.CreateRequest();
419+
var response = lightClientRequest.SendCommand($"EXISTS {key}");
420+
var expectedResponse = ":1\r\n";
421+
TestUtils.AssertEqualUpToExpectedLength(expectedResponse, response);
417422
}
418423

419424
[Test]
@@ -470,6 +475,9 @@ public void BzmpopReturnTest()
470475
ClassicAssert.AreEqual(2, pop[1][1].Length);
471476
ClassicAssert.AreEqual("two", pop[1][1][0].ToString());
472477
ClassicAssert.AreEqual(2, (int)(RedisValue)pop[1][1][1]);
478+
479+
ClassicAssert.IsFalse(db.KeyExists("a"));
480+
ClassicAssert.IsTrue(db.KeyExists("b"));
473481
}
474482

475483
[Test]
@@ -685,6 +693,10 @@ public void PopWrongTypeTest()
685693
Task.WaitAll([blockingLTask, blockingZTask], TimeSpan.FromSeconds(5));
686694
ClassicAssert.IsTrue(blockingLTask.IsCompletedSuccessfully);
687695
ClassicAssert.IsTrue(blockingZTask.IsCompletedSuccessfully);
696+
697+
response = lightClientRequest.SendCommand("EXISTS list");
698+
expectedResponse = ":0\r\n";
699+
TestUtils.AssertEqualUpToExpectedLength(expectedResponse, response);
688700
}
689701
}
690702
}

0 commit comments

Comments
 (0)