-
Notifications
You must be signed in to change notification settings - Fork 543
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Compatibility] Add hash expiration - HEXPIRE, HPEXPIRE, HEXPIREAT, HPEXPIREAT, HTTL, HPTTL, HEXPIRETIME, HPEXPIRETIME, HPERSIST and HCOLLECT #864
base: main
Are you sure you want to change the base?
Conversation
@badrishc Can you quick look at this draft PR and let me know if I am going on the right path? Also, you will see a lot of TODO comments, I would like to get your opinion and help on some of those. Add your comments on those TODO items if possible. Thanks |
For maintaining the performance bar, we may need to: (1) Have a separate small PR to main, that adds BDN for more of the hash APIs for perf test (i.e., the ones that this PR might potentially regress). We only have one right now here: (2) Use those BDNs to compare main versus this PR, to ensure that there is no regression |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a great start! See my comments, thank you. Let me know if anything is still unclear.
I think it's ready for review. Let the review comments flood it 😄 @badrishc I am working on creating a separate PR for adding more hash APIs in BDN |
main branch results as of commit
this PR branch results as of commit
Difference
For me, Variant looks minimal with the PR but I like to know your opinion. I will analyze why there is an additional allocation for HKeys, HGetAll, HVals commands |
I have to remove the This PR as of
Difference
For me, HMSet is the only one that looks outstanding. Update: Not sure what's going on in HMSet commands. Even after reverting everything back in HMSet commands flow, the performance is still slower than the main. But changing other parts of the code affects its performance like using |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work. Please find my comments below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comments
Fixed all review comments except the one where we need to find the size of the new objects |
Please rereview this PR, closed all outstanding items from my end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for this extensive contribution. Added a few comments.
libs/resources/RespCommandsInfo.json
Outdated
@@ -1546,6 +1546,31 @@ | |||
} | |||
] | |||
}, | |||
{ | |||
"Command": "HCOLLECT", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be added to GarnetCommandsInfo.json (in CommandInfoUpdater)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
libs/resources/RespCommandsDocs.json
Outdated
@@ -2751,6 +2751,12 @@ | |||
} | |||
] | |||
}, | |||
{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be added to GarnetCommandsDocs.json (in CommandInfoUpdater)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
if (!isExpired) | ||
{ | ||
hash.Add(item, value); | ||
InitializeExpirationStructures(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why call this method at every iteration? Have an _isExpirationStructuresInitialized field to indicate if this has been previously called.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This method has AggressiveInlining
, inside that it will only initialize after checking a null check. Performance vice this if(expirationTimes is null)
and if(_isExpirationStructuresInitialized)
will have unmeasurable difference.
@@ -57,6 +58,33 @@ public void CanSetAndGetOnePair() | |||
ClassicAssert.AreEqual("Tsavorite", r); | |||
} | |||
|
|||
[Test] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since you've added serialization logic for a hash object with expiration values, it would be good to test taking a checkpoint of that object + test proper recovery
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does the CanDoHashExpireLTM
Test not suffice? I took reference from another test in Garnet that tested serialization logic like this. I have added breakpoint and make sure that test always hits serialization logic. If it's not suffice, then do you have any other test for reference?
|
||
private bool Remove(byte[] key, out byte[] value) | ||
{ | ||
DeleteExpiredItems(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why call this at every remove, add etc? The overhead is not necessary at every call, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is as per the original design by @badrishc, I also agree with this design. If there is no item to expire then there is no overhead with this design.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be useful to check BDN with and without aggressive expire to verify this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@badrishc I have test the same, Didn't find any measurable difference
SendAndReset(); | ||
break; | ||
default: | ||
while (!RespWriteUtils.WriteError(CmdStrings.RESP_ERR_HCOLLECT_ALREADY_IN_PROGRESS, ref dcurr, dend)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Where in the implementation do you return a different value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the first line of HashCollect method in HashOps.cs
libs/server/StoreWrapper.cs
Outdated
{ | ||
if (token.IsCancellationRequested) return; | ||
|
||
if (objectStore is null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be outside of the while loop
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
@@ -2,6 +2,8 @@ | |||
// Licensed under the MIT license. | |||
|
|||
using System; | |||
using System.Diagnostics; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unnecessary using
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
libs/server/StoreWrapper.cs
Outdated
@@ -17,6 +17,7 @@ | |||
|
|||
namespace Garnet.server | |||
{ | |||
using static System.Reflection.Metadata.BlobBuilder; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Mistake?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
libs/server/StoreWrapper.cs
Outdated
await Task.Delay(TimeSpan.FromSeconds(hashCollectFrequencySecs), token); | ||
} | ||
} | ||
catch (TaskCanceledException ex) when (token.IsCancellationRequested) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Token cancellation does not mean we've reached an error state, it just means that the store wrapper was disposed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you suggest to log in that case? Just suppress the exception?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For now, I have suppressed
@TalZaccai Fixed the review comments with some points to discuss |
Adding support for field-specific expiration in hash set. This PR adds HEXPIRE, HPEXPIRE, HEXPIREAT, HPEXPIREAT, HTTL, HPTTL, HEXPIRETIME, HPEXPIRETIME, HPERSIST and HCOLLECT commands to garnet to support this feature.
Fixes: #857