Skip to content

Commit

Permalink
Implement OBJECT REFCOUNT command
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanl-bq committed Apr 22, 2024
1 parent e9f7702 commit 4447db7
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 0 deletions.
1 change: 1 addition & 0 deletions glide-core/src/protobuf/redis_request.proto
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@ enum RequestType {
GeoAdd = 121;
GeoHash = 122;
ObjectEncoding = 123;
ObjectRefcount = 126;
}

message Command {
Expand Down
3 changes: 3 additions & 0 deletions glide-core/src/request_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ pub enum RequestType {
GeoAdd = 121,
GeoHash = 122,
ObjectEncoding = 123,
ObjectRefcount = 126,
}

fn get_two_word_command(first: &str, second: &str) -> Cmd {
Expand Down Expand Up @@ -265,6 +266,7 @@ impl From<::protobuf::EnumOrUnknown<ProtobufRequestType>> for RequestType {
ProtobufRequestType::GeoAdd => RequestType::GeoAdd,
ProtobufRequestType::GeoHash => RequestType::GeoHash,
ProtobufRequestType::ObjectEncoding => RequestType::ObjectEncoding,
ProtobufRequestType::ObjectRefcount => RequestType::ObjectRefcount,
}
}
}
Expand Down Expand Up @@ -395,6 +397,7 @@ impl RequestType {
RequestType::GeoAdd => Some(cmd("GEOADD")),
RequestType::GeoHash => Some(cmd("GEOHASH")),
RequestType::ObjectEncoding => Some(get_two_word_command("OBJECT", "ENCODING")),
RequestType::ObjectRefcount => Some(get_two_word_command("OBJECT", "REFCOUNT")),
}
}
}
7 changes: 7 additions & 0 deletions java/client/src/main/java/glide/api/BaseClient.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.MGet;
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
import static redis_request.RedisRequestOuterClass.RequestType.ObjectEncoding;
import static redis_request.RedisRequestOuterClass.RequestType.ObjectRefcount;
import static redis_request.RedisRequestOuterClass.RequestType.PExpire;
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
Expand Down Expand Up @@ -341,6 +342,12 @@ public CompletableFuture<String> objectEncoding(@NonNull String key) {
ObjectEncoding, new String[] {key}, this::handleStringOrNullResponse);
}

@Override
public CompletableFuture<Long> objectRefcount(@NonNull String key) {
return commandManager.submitNewCommand(
ObjectRefcount, new String[] {key}, this::handleLongOrNullResponse);
}

@Override
public CompletableFuture<Long> incr(@NonNull String key) {
return commandManager.submitNewCommand(Incr, new String[] {key}, this::handleLongResponse);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -389,4 +389,22 @@ CompletableFuture<Boolean> pexpireAt(
* }</pre>
*/
CompletableFuture<String> objectEncoding(String key);

/**
* Returns the reference count of the object stored at <code>key</code>.
*
* @see <a href="https://redis.io/commands/object-refcount/">redis.io</a> for details.
* @param key The <code>key</code> of the object to get the reference count of.
* @return If <code>key</code> exists, returns the reference count of the object stored at <code>
* key</code> as a <code>Long</code>. Otherwise, returns <code>null</code>.
* @example
* <pre>{@code
* Long refcount = client.objectRefcount("my_hash").get();
* assert refcount == 2L;
*
* refcount = client.objectRefcount("non_existing_key").get();
* assert refcount == null;
* }</pre>
*/
CompletableFuture<Long> objectRefcount(String key);
}
16 changes: 16 additions & 0 deletions java/client/src/main/java/glide/api/models/BaseTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.MGet;
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
import static redis_request.RedisRequestOuterClass.RequestType.ObjectEncoding;
import static redis_request.RedisRequestOuterClass.RequestType.ObjectRefcount;
import static redis_request.RedisRequestOuterClass.RequestType.PExpire;
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
Expand Down Expand Up @@ -2240,6 +2241,21 @@ public T objectEncoding(@NonNull String key) {
return getThis();
}

/**
* Returns the reference count of the object stored at <code>key</code>.
*
* @see <a href="https://redis.io/commands/object-refcount/">redis.io</a> for details.
* @param key The <code>key</code> of the object to get the reference count of.
* @return Command response - If <code>key</code> exists, returns the reference count of the
* object stored at <code>key</code> as a <code>Long</code>. Otherwise, returns <code>null
* </code>.
*/
public T objectRefcount(@NonNull String key) {
ArgsArray commandArgs = buildArgs(key);
protobufTransaction.addCommands(buildCommand(ObjectRefcount, commandArgs));
return getThis();
}

/** Build protobuf {@link Command} object for given command and arguments. */
protected Command buildCommand(RequestType requestType) {
return buildCommand(requestType, buildArgs());
Expand Down
23 changes: 23 additions & 0 deletions java/client/src/test/java/glide/api/RedisClientTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.MGet;
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
import static redis_request.RedisRequestOuterClass.RequestType.ObjectEncoding;
import static redis_request.RedisRequestOuterClass.RequestType.ObjectRefcount;
import static redis_request.RedisRequestOuterClass.RequestType.PExpire;
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
Expand Down Expand Up @@ -3282,4 +3283,26 @@ public void objectEncoding_returns_success() {
assertEquals(testResponse, response);
assertEquals(encoding, payload);
}

@SneakyThrows
@Test
public void objectRefcount_returns_success() {
// setup
String key = "testKey";
Long refcount = 0L;
CompletableFuture<Long> testResponse = new CompletableFuture<>();
testResponse.complete(refcount);

// match on protobuf request
when(commandManager.<Long>submitNewCommand(eq(ObjectRefcount), eq(new String[] {key}), any()))
.thenReturn(testResponse);

// exercise
CompletableFuture<Long> response = service.objectRefcount(key);
Long payload = response.get();

// verify
assertEquals(testResponse, response);
assertEquals(refcount, payload);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@
import static redis_request.RedisRequestOuterClass.RequestType.MGet;
import static redis_request.RedisRequestOuterClass.RequestType.MSet;
import static redis_request.RedisRequestOuterClass.RequestType.ObjectEncoding;
import static redis_request.RedisRequestOuterClass.RequestType.ObjectRefcount;
import static redis_request.RedisRequestOuterClass.RequestType.PExpire;
import static redis_request.RedisRequestOuterClass.RequestType.PExpireAt;
import static redis_request.RedisRequestOuterClass.RequestType.PTTL;
Expand Down Expand Up @@ -512,6 +513,9 @@ InfScoreBound.NEGATIVE_INFINITY, new ScoreBoundary(3, false), new Limit(1, 2)),
transaction.objectEncoding("key");
results.add(Pair.of(ObjectEncoding, buildArgs("key")));

transaction.objectRefcount("key");
results.add(Pair.of(ObjectRefcount, buildArgs("key")));

var protobufTransaction = transaction.getProtobufTransaction().build();

for (int idx = 0; idx < protobufTransaction.getCommandsCount(); idx++) {
Expand Down
17 changes: 17 additions & 0 deletions java/integTest/src/test/java/glide/SharedCommandTests.java
Original file line number Diff line number Diff line change
Expand Up @@ -2715,4 +2715,21 @@ public void objectEncoding_returns_stream(BaseClient client) {
assertNotNull(client.xadd(streamKey, Map.of("field", "value")));
assertEquals("stream", client.objectEncoding(streamKey).get());
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
public void objectRefcount_returns_null(BaseClient client) {
String nonExistingKey = UUID.randomUUID().toString();
assertNull(client.objectRefcount(nonExistingKey).get());
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
public void objectRefcount(BaseClient client) {
String key = UUID.randomUUID().toString();
assertEquals(OK, client.set(key, "").get());
assertTrue(client.objectRefcount(key).get() >= 0L);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,17 @@ public void lastsave() {
var response = clusterClient.exec(new ClusterTransaction().lastsave()).get();
assertTrue(Instant.ofEpochSecond((long) response[0]).isAfter(yesterday));
}

// TODO: Enable when https://github.com/amazon-contributing/redis-rs/pull/138 is merged.
// @Test
// @SneakyThrows
// public void objectRefcount() {
// String objectRefcountKey = "key";
// ClusterTransaction transaction = new ClusterTransaction();
// transaction.set(objectRefcountKey, "");
// transaction.objectRefcount(objectRefcountKey);
// var response = clusterClient.exec(transaction).get();
// assertEquals(OK, response[0]);
// assertTrue((long) response[1] >= 0L);
// }
}
Original file line number Diff line number Diff line change
Expand Up @@ -121,4 +121,16 @@ public void lastsave() {
var response = client.exec(new Transaction().lastsave()).get();
assertTrue(Instant.ofEpochSecond((long) response[0]).isAfter(yesterday));
}

@Test
@SneakyThrows
public void objectRefcount() {
String objectRefcountKey = "key";
Transaction transaction = new Transaction();
transaction.set(objectRefcountKey, "");
transaction.objectRefcount(objectRefcountKey);
var response = client.exec(transaction).get();
assertEquals(OK, response[0]);
assertTrue((long) response[1] >= 0L);
}
}

0 comments on commit 4447db7

Please sign in to comment.