Skip to content

Commit 311f898

Browse files
Support OBJECT REFCOUNT (#2087)
https://redis.io/commands/object-refcount/ (#2055) Co-authored-by: Nick Craver <[email protected]>
1 parent 9047c5b commit 311f898

File tree

11 files changed

+72
-1
lines changed

11 files changed

+72
-1
lines changed

docs/ReleaseNotes.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
- Adds: Support for `SINTERCARD` with `.SetIntersectionLength()`/`.SetIntersectionLengthAsync()` ([#2078 by Avital-Fine](https://github.com/StackExchange/StackExchange.Redis/pull/2078))
1616
- Adds: Support for `LPOS` with `.ListPosition()`/`.ListPositionAsync()` and `.ListPositions()`/`.ListPositionsAsync()` ([#2080 by slorello89](https://github.com/StackExchange/StackExchange.Redis/pull/2080))
1717
- Fix: For streams, properly hash `XACK`, `XCLAIM`, and `XPENDING` in cluster scenarios to eliminate `MOVED` retries ([#2085 by nielsderdaele](https://github.com/StackExchange/StackExchange.Redis/pull/2085))
18+
- Adds: Support for `OBJECT REFCOUNT` with `.KeyRefCount()`/`.KeyRefCountAsync()` ([#2087 by Avital-Fine](https://github.com/StackExchange/StackExchange.Redis/pull/2087))
1819

1920
## 2.5.61
2021

src/StackExchange.Redis/Interfaces/IDatabase.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,15 @@ public interface IDatabase : IRedis, IDatabaseAsync
620620
/// <remarks>https://redis.io/commands/randomkey</remarks>
621621
RedisKey KeyRandom(CommandFlags flags = CommandFlags.None);
622622

623+
/// <summary>
624+
/// Returns the reference count of the object stored at <paramref name="key"/>.
625+
/// </summary>
626+
/// <param name="key">The key to get a reference count for.</param>
627+
/// <param name="flags">The flags to use for this operation.</param>
628+
/// <returns>The number of references (<see langword="Null"/> if the key does not exist).</returns>
629+
/// <remarks>https://redis.io/commands/object-refcount</remarks>
630+
long? KeyRefCount(RedisKey key, CommandFlags flags = CommandFlags.None);
631+
623632
/// <summary>
624633
/// Renames <paramref name="key"/> to <paramref name="newKey"/>.
625634
/// It returns an error when the source and destination names are the same, or when key does not exist.

src/StackExchange.Redis/Interfaces/IDatabaseAsync.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -596,6 +596,15 @@ public interface IDatabaseAsync : IRedisAsync
596596
/// <remarks>https://redis.io/commands/randomkey</remarks>
597597
Task<RedisKey> KeyRandomAsync(CommandFlags flags = CommandFlags.None);
598598

599+
/// <summary>
600+
/// Returns the reference count of the object stored at <paramref name="key"/>.
601+
/// </summary>
602+
/// <param name="key">The key to get a reference count for.</param>
603+
/// <param name="flags">The flags to use for this operation.</param>
604+
/// <returns>The number of references (<see langword="Null"/> if the key does not exist).</returns>
605+
/// <remarks>https://redis.io/commands/object-refcount</remarks>
606+
Task<long?> KeyRefCountAsync(RedisKey key, CommandFlags flags = CommandFlags.None);
607+
599608
/// <summary>
600609
/// Renames <paramref name="key"/> to <paramref name="newKey"/>.
601610
/// It returns an error when the source and destination names are the same, or when key does not exist.

src/StackExchange.Redis/KeyspaceIsolation/DatabaseWrapper.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,9 @@ public bool KeyPersist(RedisKey key, CommandFlags flags = CommandFlags.None) =>
164164
public RedisKey KeyRandom(CommandFlags flags = CommandFlags.None) =>
165165
throw new NotSupportedException("RANDOMKEY is not supported when a key-prefix is specified");
166166

167+
public long? KeyRefCount(RedisKey key, CommandFlags flags = CommandFlags.None) =>
168+
Inner.KeyRefCount(ToInner(key), flags);
169+
167170
public bool KeyRename(RedisKey key, RedisKey newKey, When when = When.Always, CommandFlags flags = CommandFlags.None) =>
168171
Inner.KeyRename(ToInner(key), ToInner(newKey), when, flags);
169172

src/StackExchange.Redis/KeyspaceIsolation/WrapperBase.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,9 @@ public Task<bool> KeyPersistAsync(RedisKey key, CommandFlags flags = CommandFlag
174174
public Task<RedisKey> KeyRandomAsync(CommandFlags flags = CommandFlags.None) =>
175175
throw new NotSupportedException("RANDOMKEY is not supported when a key-prefix is specified");
176176

177+
public Task<long?> KeyRefCountAsync(RedisKey key, CommandFlags flags = CommandFlags.None) =>
178+
Inner.KeyRefCountAsync(ToInner(key), flags);
179+
177180
public Task<bool> KeyRenameAsync(RedisKey key, RedisKey newKey, When when = When.Always, CommandFlags flags = CommandFlags.None) =>
178181
Inner.KeyRenameAsync(ToInner(key), ToInner(newKey), when, flags);
179182

src/StackExchange.Redis/PublicAPI.Shipped.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,7 @@ StackExchange.Redis.IDatabase.KeyMigrate(StackExchange.Redis.RedisKey key, Syste
531531
StackExchange.Redis.IDatabase.KeyMove(StackExchange.Redis.RedisKey key, int database, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool
532532
StackExchange.Redis.IDatabase.KeyPersist(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool
533533
StackExchange.Redis.IDatabase.KeyRandom(StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> StackExchange.Redis.RedisKey
534+
StackExchange.Redis.IDatabase.KeyRefCount(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> long?
534535
StackExchange.Redis.IDatabase.KeyRename(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisKey newKey, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> bool
535536
StackExchange.Redis.IDatabase.KeyRestore(StackExchange.Redis.RedisKey key, byte[]! value, System.TimeSpan? expiry = null, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> void
536537
StackExchange.Redis.IDatabase.KeyTimeToLive(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.TimeSpan?
@@ -731,6 +732,7 @@ StackExchange.Redis.IDatabaseAsync.KeyMigrateAsync(StackExchange.Redis.RedisKey
731732
StackExchange.Redis.IDatabaseAsync.KeyMoveAsync(StackExchange.Redis.RedisKey key, int database, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<bool>!
732733
StackExchange.Redis.IDatabaseAsync.KeyPersistAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<bool>!
733734
StackExchange.Redis.IDatabaseAsync.KeyRandomAsync(StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<StackExchange.Redis.RedisKey>!
735+
StackExchange.Redis.IDatabaseAsync.KeyRefCountAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<long?>!
734736
StackExchange.Redis.IDatabaseAsync.KeyRenameAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.RedisKey newKey, StackExchange.Redis.When when = StackExchange.Redis.When.Always, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<bool>!
735737
StackExchange.Redis.IDatabaseAsync.KeyRestoreAsync(StackExchange.Redis.RedisKey key, byte[]! value, System.TimeSpan? expiry = null, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task!
736738
StackExchange.Redis.IDatabaseAsync.KeyTimeToLiveAsync(StackExchange.Redis.RedisKey key, StackExchange.Redis.CommandFlags flags = StackExchange.Redis.CommandFlags.None) -> System.Threading.Tasks.Task<System.TimeSpan?>!

src/StackExchange.Redis/RedisDatabase.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -827,6 +827,18 @@ public Task<RedisKey> KeyRandomAsync(CommandFlags flags = CommandFlags.None)
827827
return ExecuteAsync(msg, ResultProcessor.RedisKey);
828828
}
829829

830+
public long? KeyRefCount(RedisKey key, CommandFlags flags = CommandFlags.None)
831+
{
832+
var msg = Message.Create(Database, flags, RedisCommand.OBJECT, RedisLiterals.REFCOUNT, key);
833+
return ExecuteSync(msg, ResultProcessor.NullableInt64);
834+
}
835+
836+
public Task<long?> KeyRefCountAsync(RedisKey key, CommandFlags flags = CommandFlags.None)
837+
{
838+
var msg = Message.Create(Database, flags, RedisCommand.OBJECT, RedisLiterals.REFCOUNT, key);
839+
return ExecuteAsync(msg, ResultProcessor.NullableInt64);
840+
}
841+
830842
public bool KeyRename(RedisKey key, RedisKey newKey, When when = When.Always, CommandFlags flags = CommandFlags.None)
831843
{
832844
WhenAlwaysOrNotExists(when);

src/StackExchange.Redis/RedisLiterals.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,13 @@ public static readonly RedisValue
9292
PX = "PX",
9393
PXAT = "PXAT",
9494
RANK = "RANK",
95-
RIGHT = "RIGHT",
95+
REFCOUNT = "REFCOUNT",
9696
REPLACE = "REPLACE",
9797
RESET = "RESET",
9898
RESETSTAT = "RESETSTAT",
9999
REV = "REV",
100100
REWRITE = "REWRITE",
101+
RIGHT = "RIGHT",
101102
SAVE = "SAVE",
102103
SEGFAULT = "SEGFAULT",
103104
SET = "SET",

tests/StackExchange.Redis.Tests/DatabaseWrapperTests.cs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -317,6 +317,13 @@ public void KeyRandom()
317317
Assert.Throws<NotSupportedException>(() => wrapper.KeyRandom());
318318
}
319319

320+
[Fact]
321+
public void KeyRefCount()
322+
{
323+
wrapper.KeyRefCount("key", CommandFlags.None);
324+
mock.Verify(_ => _.KeyRefCount("prefix:key", CommandFlags.None));
325+
}
326+
320327
[Fact]
321328
public void KeyRename()
322329
{

tests/StackExchange.Redis.Tests/Keys.cs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,5 +264,22 @@ public async Task TouchIdleTimeAsync()
264264
Assert.True(idleTime1 < idleTime);
265265
}
266266
}
267+
268+
[Fact]
269+
public async Task KeyRefCount()
270+
{
271+
using var muxer = Create();
272+
var key = Me();
273+
var db = muxer.GetDatabase();
274+
db.KeyDelete(key, CommandFlags.FireAndForget);
275+
db.StringSet(key, "new value", flags: CommandFlags.FireAndForget);
276+
277+
Assert.Equal(1, db.KeyRefCount(key));
278+
Assert.Equal(1, await db.KeyRefCountAsync(key));
279+
280+
var keyNotExists = key + "no-exist";
281+
Assert.Null(db.KeyRefCount(keyNotExists));
282+
Assert.Null(await db.KeyRefCountAsync(keyNotExists));
283+
}
267284
}
268285
}

0 commit comments

Comments
 (0)