Skip to content

JAVA: Valkey 9 new commands HASH items expiration#4556

Merged
affonsov merged 24 commits intomainfrom
java/affonsov-hash-commands-with-expire
Aug 29, 2025
Merged

JAVA: Valkey 9 new commands HASH items expiration#4556
affonsov merged 24 commits intomainfrom
java/affonsov-hash-commands-with-expire

Conversation

@affonsov
Copy link
Copy Markdown
Collaborator

@affonsov affonsov commented Aug 6, 2025

Add Hash Field Expiration Commands Support for Java Client

Summary

This PR implements comprehensive support for hash field expiration commands in the Java client, adding new commands that enable fine-grained TTL management for individual hash fields. These commands are available in Valkey 9.0+ and provide powerful capabilities for managing field-level expiration in hash data structures.

New Commands Added

Core Commands

  • HSETEX - Set hash fields with expiration and conditional options
  • HGETEX - Get hash field values and optionally set/update their expiration
  • HEXPIRE - Set expiration time for hash fields (seconds)
  • HPEXPIRE - Set expiration time for hash fields (milliseconds)
  • HEXPIREAT - Set expiration time using Unix timestamp (seconds)
  • HPEXPIREAT - Set expiration time using Unix timestamp (milliseconds)
  • HPERSIST - Remove expiration from hash fields
  • HTTL - Get remaining TTL for hash fields (seconds)
  • HPTTL - Get remaining TTL for hash fields (milliseconds)
  • HEXPIRETIME - Get absolute expiration timestamp (seconds)
  • HPEXPIRETIME - Get absolute expiration timestamp (milliseconds)

Key Features

Flexible Expiration Options

  • Multiple time formats: seconds, milliseconds, Unix timestamps
  • Conditional expiration: NX (only if no expiry), XX (only if has expiry), GT (greater than current), LT (less than current)
  • Persist option: Remove expiration from fields
  • Keep existing TTL: Maintain current expiration when updating fields

Advanced Conditional Logic

  • Hash-level conditions: NX (hash doesn't exist), XX (hash exists)
  • Field-level conditions: FNX (fields don't exist), FXX (all fields exist)
  • Smart validation: Prevents conflicting conditional combinations

Implementation Details

Core Infrastructure

  • Added HashFieldExpirationOptions class with builder pattern for flexible option configuration
  • Extended protobuf definitions with 10 new request types (617-627)
  • Updated Rust core with command mappings and request type handling
  • Validation logic for mutually exclusive options

Client Integration

  • Implemented all commands in BaseClient with both String and GlideString overloads
  • Added batch support in BaseBatch with generic type safety
  • Extensive unit tests covering all option combinations and edge cases
  • Integration tests validating real server behavior

Error Handling

  • Proper validation of conflicting conditional options
  • Type safety enforcement for binary vs string parameters
  • Error messages for invalid option combinations
  • Graceful handling of non-existent keys and fields

Testing Coverage

Unit Tests

  • HashFieldExpirationOptionsTest - 15+ test cases covering all option combinations
  • HashFieldExpirationCommandsTest - Validation logic and edge cases
  • BatchTests - Batch operation functionality
  • GlideClientTest - Client method integration

Integration Tests

  • Basic functionality tests for all commands
  • Conditional options testing (NX, XX, GT, LT, FNX, FXX)
  • Binary parameter support validation
  • Batch operations with atomic and non-atomic modes
  • Error handling and edge cases
  • Mixed field scenarios (some with expiry, some without)
  • Immediate deletion with past timestamps/zero values

Issue link

This Pull Request is linked to issue (URL): #4496

Checklist

Before submitting the PR make sure the following are checked:

  • This Pull Request is related to one issue.
  • Commit message has a detailed description of what changed and why.
  • Tests are added or updated.
  • CHANGELOG.md and documentation files are updated.
  • Destination branch is correct - main or release
  • Create merge commit if merging release branch into main, squash otherwise.

@affonsov affonsov requested a review from a team as a code owner August 6, 2025 23:29
@affonsov affonsov force-pushed the java/affonsov-hash-commands-with-expire branch from e64d86b to 6197a11 Compare August 7, 2025 20:40
@yipin-chen yipin-chen requested a review from edlng August 8, 2025 17:23
@yipin-chen yipin-chen mentioned this pull request Aug 8, 2025
4 tasks
Copy link
Copy Markdown
Collaborator

@edlng edlng left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As we discussed in #4554 (comment), let's wait until RC is released and rerun CI to test before merging

Copy link
Copy Markdown

@Yury-Fridlyand Yury-Fridlyand left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, but
We can't merge until test. We can't test without valkey 9 (or 9 RC) in CI.
CI updates should be merged in another PR ahead of this one.

@edlng
Copy link
Copy Markdown
Collaborator

edlng commented Aug 18, 2025

Copy link
Copy Markdown
Collaborator

@yipin-chen yipin-chen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Add support for HSETEX command in Java client.

- Add HashFieldExpirationOptions class with builder pattern for command options

- Implement hash field expiration methods in HashBaseCommands interface

- Add unit tests for all new commands and options

- Add integration tests to verify command functionality

- Update protobuf definitions and Rust request types

- Add batch operation support for all new commands

This implementation provides full support for hash field expiration functionality.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Add support for the HGETEX command which retrieves hash field values
and optionally sets their expiration or removes it.

Changes:
- Add HGetex request type to protobuf and Rust core
- Implement hgetex() methods in BaseClient and HashBaseCommands
- Add batch support for hgetex operations
- Extend HashFieldExpirationOptions with Persist() option
- Add comprehensive integration tests covering:
  * Basic functionality with expiry setting
  * PERSIST option to remove field expiration
  * Binary parameter support (GlideString)
  * Batch operation support

The implementation supports both String and GlideString parameters
and includes proper validation for the PERSIST option which cannot
be combined with conditional options.

Requires Valkey 9.0.0 or higher.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Add support for the HEXPIRE command which sets expiration time in seconds
for specified fields in a hash. This command is available in Valkey 9.0+.

Changes:
- Add HExpire (619) to protobuf command request types
- Implement hexpire() methods in BaseClient and HashBaseCommands
- Support both String and GlideString parameter variants
- Add batch operation support in BaseBatch
- Include test coverage for:
  * Basic functionality with multiple fields
  * Conditional expiration options (NX, XX, GT, LT)
  * Immediate deletion with 0 seconds
  * Binary parameter support
  * Batch operation functionality

The implementation follows existing patterns and maintains compatibility
with the HashFieldExpirationOptions for conditional expiration logic.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Add support for the HPERSIST command which removes expiration time from
hash fields, making them persistent.

Changes:
- Add HPersist request type to protobuf and core request handling
- Implement hpersist() methods in BaseClient and HashBaseCommands
- Add batch support for HPERSIST operations
- Support both String and GlideString parameter types
- Add test coverage including edge cases and binary support

Requires Valkey 9.0.0 or higher.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
…conds

- Add HPEXPIRE request type (621) to protobuf and Rust request handling
- Implement HPEXPIRE in Java BaseClient and HashBaseCommands interface
- Add batch support for HPEXPIRE operations
- Include comprehensive integration tests covering:
  * Basic functionality with multiple fields
  * Conditional expiration options (NX, XX, GT, LT)
  * Immediate deletion with 0ms expiration
  * Binary parameter support with GlideString
  * Batch operation functionality

This complements the existing HEXPIRE command by providing millisecond
precision for hash field expiration, following Valkey 9.0+ specifications.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Add support for the HEXPIREAT command which sets expiration time for hash
fields using absolute Unix timestamps in seconds. This complements the
existing HEXPIRE command by allowing timestamp-based expiration.

Changes:
- Add HExpireAt (622) request type to protobuf and Rust core
- Implement hexpireat() methods in BaseClient and HashBaseCommands
- Add batch support for hexpireat operations
- Support both String and GlideString parameter variants
- Include test coverage for all scenarios

Features:
- Sets expiration using Unix timestamp in seconds
- Supports HashFieldExpirationOptions for conditional expiration
- Handles immediate deletion for past timestamps
- Creates hash if it doesn't exist
- Returns Boolean array indicating success per field

Requires Valkey 9.0.0 or higher.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Add support for HPEXPIREAT command which sets expiration time for hash
fields using Unix timestamp in milliseconds, complementing the existing
HEXPIREAT command that uses seconds.

Changes:
- Add HPExpireAt (623) request type to protobuf and Rust core
- Implement hpexpireat() methods in BaseClient and BaseBatch classes
- Add interface documentation with examples
- Support both String and GlideString parameter variants
- Include full integration test coverage for all scenarios

The implementation follows the same patterns as existing hash expiration
commands and requires Valkey 9.0.0 or higher.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Add support for the HTTL command to query remaining time-to-live
of hash fields in seconds. This command is available in Valkey 9.0+.

Changes:
- Add HTtl request type (624) to protobuf and core request handling
- Implement httl() methods in BaseClient and BaseBatch for both
  String and GlideString parameter types
- Add comprehensive test coverage including basic functionality,
  expired fields, mixed field scenarios, and batch operations
- Support for non-existent keys and fields with proper return codes
  (-1 for no expiration, -2 for non-existent fields)

The implementation follows existing patterns for hash field expiration
commands and maintains consistency with the codebase architecture.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
…IME, HPEXPIRETIME)

Add support for Valkey 9.0+ hash field expiration query commands:

- HPTTL: Get remaining TTL of hash fields in milliseconds
- HEXPIRETIME: Get absolute expiration timestamp of hash fields in seconds
- HPEXPIRETIME: Get absolute expiration timestamp of hash fields in milliseconds

Changes include:
* Add new RequestType enums (HPTtl=625, HExpireTime=626, HPExpireTime=627)
* Implement client methods in BaseClient with String and GlideString support
* Add comprehensive interface definitions in HashBaseCommands
* Support batch operations in BaseBatch
* Add extensive integration tests covering:
  - Basic functionality with mixed field states
  - Non-existent keys and expired fields
  - Binary parameter support
  - Batch operation testing

All commands return Long[] arrays with standard Redis semantics:
- Positive values: TTL/timestamp for fields with expiration
- -1: Field exists but has no expiration
- -2: Field does not exist

Requires Valkey 9.0.0 or higher.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
- Rename HSetex/HGetex to HSetEx/HGetEx for consistent PascalCase naming
- Change return types from Boolean[] to Long[] for hash expiration commands
  to match Valkey server response format:
  * 1: expiration successfully set/removed
  * 0: condition not met
  * -1: field exists but has no expiration (hpersist)
  * -2: field/key does not exist
  * 2: called with 0 seconds/milliseconds
- Update documentation and examples to reflect new return value semantics
- Fix command string casing in request_type.rs (HSetEx/HGetEx instead of HSETEX/HGETEX)
- Add FIELDS_VALKEY_API constant for consistent "FIELDS" keyword usage
- Update integration tests to verify correct return values and TTL behavior
- Rename test file from HashFieldExpirationCommandsTest to HashFieldExpirationOptionsCommandsTest
- Use ExpireOptions enum instead of custom ExpirationCondition enum for consistency

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
…tations

- Fix HSETEX/HGETEX command names in request_type.rs (uppercase)
- Use FIELDS_VALKEY_API constant in Java batch operations
- Correct HSETEX return value expectations in tests (returns 1 on success)
- Update conditional options to use FNX/FXX instead of NX/XX
- Fix TTL assertions to match actual expiration times
- Add proper type casting for batch operation results

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
…fic options classes

- Replace monolithic HashFieldExpirationOptions with focused classes:
  * HSetExOptions for HSETEX command with field conditionals and expiry
  * HGetExOptions for HGETEX command with PERSIST support
  * HExpireOptions, HPExpireOptions for HEXPIRE/HPEXPIRE commands
  * HExpireAtOptions, HPExpireAtOptions for HEXPIREAT/HPEXPIREAT commands

- Add supporting classes:
  * ExpirySet for standard expiry configurations (EX/PX/EXAT/PXAT/KEEPTTL)
  * HGetExExpiry for HGETEX-specific expiry (supports PERSIST, excludes KEEPTTL)
  * FieldConditionalChange for FXX/FNX field existence conditions

- Make options parameters nullable for better usability
- Update method signatures across BaseClient, HashBaseCommands, and BaseBatch
- Enhance JavaDoc with improved examples and clearer parameter descriptions
- Improve compile-time safety by preventing invalid option combinations

This refactor provides better type safety, clearer APIs, and prevents
runtime errors from incompatible option combinations between different
hash field expiration commands.

Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Signed-off-by: affonsov <67347924+affonsov@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

java ☕ issues and fixes related to the java client

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants