Skip to content

Commit

Permalink
Implement OBJECT IDLETIME 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 ebe793e
Show file tree
Hide file tree
Showing 10 changed files with 113 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;
ObjectIdletime = 125;
}

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,
ObjectIdletime = 125,
}

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::ObjectIdletime => RequestType::ObjectIdletime,
}
}
}
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::ObjectIdletime => Some(get_two_word_command("OBJECT", "IDLETIME")),
}
}
}
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.ObjectIdletime;
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> objectIdletime(@NonNull String key) {
return commandManager.submitNewCommand(
ObjectIdletime, 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 time in seconds since the last access to the value stored at <code>key</code>.
*
* @see <a href="https://redis.io/commands/object-idletime/">redis.io</a> for details.
* @param key The <code>key</code> of the object to get the idle time of.
* @return If <code>key</code> exists, returns the idle time in seconds of the object at <code>key
* </code> as a <code>Long</code>. Otherwise, returns <code>null</code>.
* @example
* <pre>{@code
* Long idletime = client.objectIdletime("my_hash").get();
* assert idletime == 2L;
*
* idletime = client.objectIdletime("non_existing_key").get();
* assert idletime == null;
* }</pre>
*/
CompletableFuture<Long> objectIdletime(String key);
}
15 changes: 15 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.ObjectIdletime;
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,20 @@ public T objectEncoding(@NonNull String key) {
return getThis();
}

/**
* Returns the time in seconds since the last access to the value stored at <code>key</code>.
*
* @see <a href="https://redis.io/commands/object-idletime/">redis.io</a> for details.
* @param key The <code>key</code> of the object to get the idle time of.
* @return Command response - If <code>key</code> exists, returns the idle time in seconds of the
* object at <code>key</code> as a <code>Long</code>. Otherwise, returns <code>null</code>.
*/
public T objectIdletime(@NonNull String key) {
ArgsArray commandArgs = buildArgs(key);
protobufTransaction.addCommands(buildCommand(ObjectIdletime, 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.ObjectIdletime;
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 objectIdletime_returns_success() {
// setup
String key = "testKey";
Long idletime = 0L;
CompletableFuture<Long> testResponse = new CompletableFuture<>();
testResponse.complete(idletime);

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

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

// verify
assertEquals(testResponse, response);
assertEquals(idletime, 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.ObjectIdletime;
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.objectIdletime("key");
results.add(Pair.of(ObjectIdletime, 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 objectIdletime_returns_null(BaseClient client) {
String nonExistingKey = UUID.randomUUID().toString();
assertNull(client.objectIdletime(nonExistingKey).get());
}

@SneakyThrows
@ParameterizedTest(autoCloseArguments = false)
@MethodSource("getClients")
public void objectIdletime(BaseClient client) {
String key = UUID.randomUUID().toString();
assertEquals(OK, client.set(key, "").get());
assertTrue(client.objectIdletime(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 objectIdletime() {
// String objectIdletimeKey = "key";
// ClusterTransaction transaction = new ClusterTransaction();
// transaction.set(objectIdletimeKey, "");
// transaction.objectIdletime(objectIdletimeKey);
// 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 objectIdletime() {
String objectIdletimeKey = "key";
Transaction transaction = new Transaction();
transaction.set(objectIdletimeKey, "");
transaction.objectIdletime(objectIdletimeKey);
var response = client.exec(transaction).get();
assertEquals(OK, response[0]);
assertTrue((long) response[1] >= 0L);
}
}

0 comments on commit ebe793e

Please sign in to comment.