Skip to content

Commit d98fc0f

Browse files
authored
Python: add OBJECT IDLETIME command (#1474)
Python: add OBJECT IDLETIME command (#313)
1 parent b375b57 commit d98fc0f

File tree

5 files changed

+77
-15
lines changed

5 files changed

+77
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#### Changes
22
* Python: Added OBJECT ENCODING command ([#1471](https://github.com/aws/glide-for-redis/pull/1471))
33
* Python: Added OBJECT FREQ command ([#1472](https://github.com/aws/glide-for-redis/pull/1472))
4+
* Python: Added OBJECT IDLETIME command ([#1474](https://github.com/aws/glide-for-redis/pull/1474))
45

56
## 0.4.0 (2024-05-26)
67

python/python/glide/async_commands/core.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3545,7 +3545,7 @@ async def object_encoding(self, key: str) -> Optional[str]:
35453545
await self._execute_command(RequestType.ObjectEncoding, [key]),
35463546
)
35473547

3548-
async def object_freq(self, key: str) -> int:
3548+
async def object_freq(self, key: str) -> Optional[int]:
35493549
"""
35503550
Returns the logarithmic access frequency counter of a Redis object stored at `key`.
35513551
@@ -3555,14 +3555,35 @@ async def object_freq(self, key: str) -> int:
35553555
key (str): The key of the object to get the logarithmic access frequency counter of.
35563556
35573557
Returns:
3558-
int: If `key` exists, returns the logarithmic access frequency counter of the object stored at `key` as an
3558+
Optional[int]: If `key` exists, returns the logarithmic access frequency counter of the object stored at `key` as an
35593559
integer. Otherwise, returns None.
35603560
35613561
Examples:
35623562
>>> await client.object_freq("my_hash")
35633563
2 # The logarithmic access frequency counter of "my_hash" has a value of 2.
35643564
"""
35653565
return cast(
3566-
int,
3566+
Optional[int],
35673567
await self._execute_command(RequestType.ObjectFreq, [key]),
35683568
)
3569+
3570+
async def object_idletime(self, key: str) -> Optional[int]:
3571+
"""
3572+
Returns the time in seconds since the last access to the value stored at `key`.
3573+
3574+
See https://valkey.io/commands/object-idletime for more details.
3575+
3576+
Args:
3577+
key (str): The key of the object to get the idle time of.
3578+
3579+
Returns:
3580+
Optional[int]: If `key` exists, returns the idle time in seconds. Otherwise, returns None.
3581+
3582+
Examples:
3583+
>>> await client.object_idletime("my_hash")
3584+
13 # "my_hash" was last accessed 13 seconds ago.
3585+
"""
3586+
return cast(
3587+
Optional[int],
3588+
await self._execute_command(RequestType.ObjectIdleTime, [key]),
3589+
)

python/python/glide/async_commands/transaction.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2485,11 +2485,25 @@ def object_freq(self: TTransaction, key: str) -> TTransaction:
24852485
key (str): The key of the object to get the logarithmic access frequency counter of.
24862486
24872487
Command response:
2488-
int: If `key` exists, returns the logarithmic access frequency counter of the object stored at `key` as an
2488+
Optional[int]: If `key` exists, returns the logarithmic access frequency counter of the object stored at `key` as an
24892489
integer. Otherwise, returns None.
24902490
"""
24912491
return self.append_command(RequestType.ObjectFreq, [key])
24922492

2493+
def object_idletime(self: TTransaction, key: str) -> TTransaction:
2494+
"""
2495+
Returns the time in seconds since the last access to the value stored at `key`.
2496+
2497+
See https://valkey.io/commands/object-idletime for more details.
2498+
2499+
Args:
2500+
key (str): The key of the object to get the idle time of.
2501+
2502+
Command response:
2503+
Optional[int]: If `key` exists, returns the idle time in seconds. Otherwise, returns None.
2504+
"""
2505+
return self.append_command(RequestType.ObjectIdleTime, [key])
2506+
24932507

24942508
class Transaction(BaseTransaction):
24952509
"""

python/python/tests/test_async_client.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3409,10 +3409,23 @@ async def test_object_freq(self, redis_client: TRedisClient):
34093409
)
34103410
assert await redis_client.object_freq(non_existing_key) is None
34113411
assert await redis_client.set(key, "") == OK
3412-
assert await redis_client.object_freq(key) >= 0
3412+
freq = await redis_client.object_freq(key)
3413+
assert freq is not None and freq >= 0
34133414
finally:
34143415
await redis_client.config_set({maxmemory_policy_key: maxmemory_policy})
34153416

3417+
@pytest.mark.parametrize("cluster_mode", [True, False])
3418+
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
3419+
async def test_object_idletime(self, redis_client: TRedisClient):
3420+
string_key = get_random_string(10)
3421+
non_existing_key = get_random_string(10)
3422+
3423+
assert await redis_client.object_idletime(non_existing_key) is None
3424+
assert await redis_client.set(string_key, "foo") == OK
3425+
time.sleep(1)
3426+
idletime = await redis_client.object_idletime(string_key)
3427+
assert idletime is not None and idletime > 0
3428+
34163429

34173430
class TestMultiKeyCommandCrossSlot:
34183431
@pytest.mark.parametrize("cluster_mode", [True])

python/python/tests/test_transaction.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,6 @@ async def transaction_test(
6363

6464
transaction.set(key, value)
6565
args.append(OK)
66-
transaction.object_encoding(key)
67-
args.append("embstr")
6866
transaction.setrange(key, 0, value)
6967
args.append(len(value))
7068
transaction.get(key)
@@ -502,10 +500,13 @@ async def test_transaction_chaining_calls(self, redis_client: TRedisClient):
502500

503501
assert await redis_client.exec(transaction) == [OK, "value", 1]
504502

505-
# object_freq is not tested in transaction_test as it requires that we set and later restore the max memory policy
503+
# The object commands are tested here instead of transaction_test because they have special requirements:
504+
# - OBJECT FREQ and OBJECT IDLETIME require specific maxmemory policies to be set on the config
505+
# - we cannot reliably predict the exact response values for OBJECT FREQ, OBJECT IDLETIME, and OBJECT REFCOUNT
506+
# - OBJECT ENCODING is tested here since all the other OBJECT commands are tested here
506507
@pytest.mark.parametrize("cluster_mode", [True, False])
507508
@pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3])
508-
async def test_transaction_object_freq(
509+
async def test_transaction_object_commands(
509510
self, redis_client: TRedisClient, cluster_mode: bool
510511
):
511512
string_key = get_random_string(10)
@@ -515,16 +516,28 @@ async def test_transaction_object_freq(
515516

516517
try:
517518
transaction = ClusterTransaction() if cluster_mode else Transaction()
518-
transaction.config_set({maxmemory_policy_key: "allkeys-lfu"})
519519
transaction.set(string_key, "foo")
520+
transaction.object_encoding(string_key)
521+
# OBJECT FREQ requires a LFU maxmemory-policy
522+
transaction.config_set({maxmemory_policy_key: "allkeys-lfu"})
520523
transaction.object_freq(string_key)
524+
# OBJECT IDLETIME requires a non-LFU maxmemory-policy
525+
transaction.config_set({maxmemory_policy_key: "allkeys-random"})
526+
transaction.object_idletime(string_key)
521527

522528
response = await redis_client.exec(transaction)
523529
assert response is not None
524-
assert len(response) == 3
525-
assert response[0] == OK
526-
assert response[1] == OK
527-
frequency = cast(int, response[2])
528-
assert frequency >= 0
530+
assert response[0] == OK # transaction.set(string_key, "foo")
531+
assert response[1] == "embstr" # transaction.object_encoding(string_key)
532+
assert (
533+
response[2] == OK
534+
) # transaction.config_set({maxmemory_policy_key: "allkeys-lfu"})
535+
assert cast(int, response[3]) >= 0 # transaction.object_freq(string_key)
536+
assert (
537+
response[4] == OK
538+
) # transaction.config_set({maxmemory_policy_key: "allkeys-random"})
539+
assert (
540+
cast(int, response[5]) >= 0
541+
) # transaction.object_idletime(string_key)
529542
finally:
530543
await redis_client.config_set({maxmemory_policy_key: maxmemory_policy})

0 commit comments

Comments
 (0)