Etag Implementation
ETag Support
Garnet provides support for ETags on raw strings. By using the ETag-related commands outlined below, you can associate any string-based key-value pair inserted into Garnet with an automatically updated ETag.
Compatibility with non-ETag commands and the behavior of data inserted with ETags are detailed at the end of this document.
SETWITHETAG
Syntax
SETWITHETAG key value [RETAINETAG]
Inserts a key-value string pair into Garnet, associating an ETag that will be updated upon changes to the value.
Options:
- RETAINETAG -- Update the Etag associated with the previous key-value pair, while setting the new value for the key. If not etag existed for the previous key this will initialize one.
Response
- Integer reply: A response integer indicating the initial ETag value on success.
GETWITHETAG
Syntax
GETWITHETAG key
Retrieves the value and the ETag associated with the given key.
Response
One of the following:
- Array reply: An array of two items returned on success. The first item is an integer representing the ETag, and the second is the bulk string value of the key. If called on a key-value pair without ETag, the first item will be nil.
- Nil reply: If the key does not exist.
SETIFMATCH
Syntax
SETIFMATCH key value etag
Updates the value of a key if the provided ETag matches the current ETag of the key.
Response
One of the following:
- Integer reply: The updated ETag if the value was successfully updated.
- Nil reply: If the key does not exist.
- Simple string reply: If the provided ETag does not match the current ETag or If the command is called on a record without an ETag a simple string indicating ETag mismatch is returned.
GETIFNOTMATCH
Syntax
GETIFNOTMATCH key etag
Retrieves the value if the ETag associated with the key has changed; otherwise, returns a response indicating no change.
Response
One of the following:
- Array reply: If the ETag does not match, an array of two items is returned. The first item is the updated ETag, and the second item is the value associated with the key. If called on a record without an ETag the first item in the array will be nil.
- Nil reply: If the key does not exist.
- Simple string reply: if the provided ETag matches the current ETag, returns a simple string indicating the value is unchanged.
Compatibility and Behavior with Non-ETag Commands
Below is the expected behavior of ETag-associated key-value pairs when non-ETag commands are used.
-
MSET, BITOP: These commands will replace an existing ETag-associated key-value pair with a non-ETag key-value pair, effectively removing the ETag.
-
SET: Only if used with additional option "RETAINETAG" will calling SET update the etag while inserting the new key-value pair over the existing key-value pair.
-
RENAME: Renaming an ETag-associated key-value pair will reset the ETag to 0 for the renamed key. Unless the key being renamed to already existed before hand, in that case it will retain the etag of the existing key that was the target of the rename.
All other commands will update the etag internally if they modify the underlying data, and any responses from them will not expose the etag to the client. To the users the etag and it's updates remain hidden in non-etag commands.
BDN Benchmark
Main:
BenchmarkDotNet v0.14.0, Windows 11 (10.0.26100.2605) 11th Gen Intel Core i7-1185G7 3.00GHz, 1 CPU, 8 logical and 4 physical cores .NET SDK 8.0.404 [Host] : .NET 8.0.11 (8.0.1124.51707), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI .NET 8 : .NET 8.0.11 (8.0.1124.51707), X64 RyuJIT AVX-512F+CD+BW+DQ+VL+VBMI
Job=.NET 8 EnvironmentVariables=DOTNET_TieredPGO=0 Runtime=.NET 8.0 Server=True
| Method | Params | Mean | Error | StdDev | Allocated |
|---|---|---|---|---|---|
| Set | ACL | 11.735 us | 0.2305 us | 0.2043 us | - |
| SetEx | ACL | 15.301 us | 0.2862 us | 0.2677 us | - |
| SetNx | ACL | 14.980 us | 0.2668 us | 0.2495 us | - |
| SetXx | ACL | 15.254 us | 0.2690 us | 0.2516 us | - |
| GetFound | ACL | 11.159 us | 0.2177 us | 0.2037 us | - |
| GetNotFound | ACL | 8.026 us | 0.1052 us | 0.0985 us | - |
| Increment | ACL | 19.366 us | 0.2938 us | 0.2748 us | - |
| Decrement | ACL | 18.460 us | 0.3557 us | 0.3806 us | - |
| IncrementBy | ACL | 23.279 us | 0.4654 us | 0.4570 us | - |
| DecrementBy | ACL | 22.129 us | 0.3639 us | 0.3404 us | - |
| Set | AOF | 15.781 us | 0.2588 us | 0.2421 us | - |
| SetEx | AOF | 20.680 us | 0.4089 us | 0.4016 us | - |
| SetNx | AOF | 21.026 us | 0.1675 us | 0.1485 us | - |
| SetXx | AOF | 21.627 us | 0.3922 us | 0.3668 us | - |
| GetFound | AOF | 11.091 us | 0.1756 us | 0.1557 us | - |
| GetNotFound | AOF | 7.589 us | 0.0950 us | 0.0793 us | - |
| Increment | AOF | 22.896 us | 0.3682 us | 0.3264 us | - |
| Decrement | AOF | 23.581 us | 0.3896 us | 0.3253 us | - |
| IncrementBy | AOF | 27.897 us | 0.5329 us | 0.4985 us | - |
| DecrementBy | AOF | 27.829 us | 0.4111 us | 0.3644 us | - |
| Set | None | 11.485 us | 0.2180 us | 0.2141 us | - |
| SetEx | None | 15.975 us | 0.3095 us | 0.3440 us | - |
| SetNx | None | 15.019 us | 0.2740 us | 0.2429 us | - |
| SetXx | None | 16.084 us | 0.3172 us | 0.3896 us | - |
| GetFound | None | 11.096 us | 0.1555 us | 0.1454 us | - |
| GetNotFound | None | 7.524 us | 0.0766 us | 0.0716 us | - |
| Increment | None | 18.062 us | 0.3525 us | 0.3462 us | - |
| Decrement | None | 17.928 us | 0.1924 us | 0.1800 us | - |
| IncrementBy | None | 23.383 us | 0.2599 us | 0.2431 us | - |
| DecrementBy | None | 22.581 us | 0.4423 us | 0.4542 us | - |
ETag Implementation:
| Method | Params | Mean | Error | StdDev | Median | Allocated |
|---|---|---|---|---|---|---|
| Set | ACL | 11.986 us | 0.2302 us | 0.3150 us | 11.880 us | - |
| SetEx | ACL | 17.350 us | 0.3301 us | 0.5041 us | 17.337 us | - |
| SetNx | ACL | 16.401 us | 0.3277 us | 0.4905 us | 16.242 us | - |
| SetXx | ACL | 18.383 us | 0.3553 us | 0.4981 us | 18.357 us | - |
| GetFound | ACL | 12.432 us | 0.2478 us | 0.3307 us | 12.392 us | - |
| GetNotFound | ACL | 8.319 us | 0.1870 us | 0.5455 us | 8.131 us | - |
| Increment | ACL | 19.781 us | 0.2640 us | 0.2469 us | 19.702 us | - |
| Decrement | ACL | 20.177 us | 0.3827 us | 0.3758 us | 20.252 us | - |
| IncrementBy | ACL | 23.195 us | 0.4300 us | 0.3811 us | 23.150 us | - |
| DecrementBy | ACL | 23.727 us | 0.4257 us | 0.3982 us | 23.638 us | - |
| Set | AOF | 16.428 us | 0.3076 us | 0.2727 us | 16.388 us | - |
| SetEx | AOF | 21.378 us | 0.3864 us | 0.3615 us | 21.403 us | - |
| SetNx | AOF | 21.172 us | 0.4127 us | 0.4753 us | 21.178 us | - |
| SetXx | AOF | 22.839 us | 0.4535 us | 0.6788 us | 22.741 us | - |
| GetFound | AOF | 11.500 us | 0.2196 us | 0.2529 us | 11.434 us | - |
| GetNotFound | AOF | 7.708 us | 0.1173 us | 0.1097 us | 7.691 us | - |
| Increment | AOF | 23.786 us | 0.2764 us | 0.2450 us | 23.720 us | - |
| Decrement | AOF | 23.099 us | 0.2121 us | 0.1984 us | 23.120 us | - |
| IncrementBy | AOF | 28.006 us | 0.3353 us | 0.2972 us | 28.126 us | - |
| DecrementBy | AOF | 27.201 us | 0.5277 us | 0.5647 us | 27.435 us | - |
| Set | None | 11.524 us | 0.1969 us | 0.1842 us | 11.539 us | - |
| SetEx | None | 15.421 us | 0.2763 us | 0.2584 us | 15.543 us | - |
| SetNx | None | 15.511 us | 0.2100 us | 0.1964 us | 15.507 us | - |
| SetXx | None | 16.337 us | 0.3196 us | 0.3420 us | 16.414 us | - |
| GetFound | None | 11.511 us | 0.1451 us | 0.1286 us | 11.517 us | - |
| GetNotFound | None | 7.595 us | 0.0795 us | 0.0744 us | 7.610 us | - |
| Increment | None | 19.970 us | 0.3442 us | 0.3220 us | 19.932 us | - |
| Decrement | None | 19.623 us | 0.3816 us | 0.3918 us | 19.633 us | - |
| IncrementBy | None | 24.832 us | 0.4944 us | 0.6601 us | 24.827 us | - |
| DecrementBy | None | 24.584 us | 0.4909 us | 0.5844 us | 24.474 us | - |
BDN Benchmarking: https://github.com/hamdaankhalid/garnet/actions/runs/12703535967