A cross-platform C++17 implementation of the Infinispan Hot Rod protocol client.
π Smart client - hash-aware routing, automatic failover, full CRUD + metadata ops, typed error handling and user-decided retry (keyed & keyless), and SASL/SCRAM authentication (SCRAM-SHA-1/256/512).
See the complete working example in examples/quickstart/:
cd examples/quickstart
./start-server.sh # Start Infinispan 16.2
mkdir build && cd build
cmake .. && make
./quickstart # Run the exampleExample output:
=== Hot Rod C++ Client Quickstart ===
Connecting to Infinispan server...
Connected successfully!
--- PUT Operations ---
PUT: greeting = Hello, Infinispan!
PUT: language = C++17
PUT: version = 1.0.0
--- GET Operations ---
GET: greeting = Hello, Infinispan!
GET: language = C++17
GET: version = 1.0.0
--- REMOVE Operations ---
REMOVE: language deleted successfully
=== Quickstart Complete ===
The quickstart demonstrates:
- Connecting to Infinispan
- PUT operations (storing key-value pairs)
- GET operations (reading values)
- REMOVE operations (deleting entries)
- Clean disconnect
A second example, retry.cpp, demonstrates the user-decided retry loop
(cache.excluding(e) on a caught HotRodClientException) for both keyed
operations and keyless ping.
See examples/quickstart/README.md for full documentation.
Build Requirements:
- C++17 compatible compiler (GCC 7+, Clang 6+, MSVC 19.20+)
- CMake 3.15+
- OpenSSL 1.1.1+ or 3.x
- Google Test (for testing)
Runtime Requirements:
- Infinispan Server 16.0+ (tested with 16.2)
- Docker (for integration tests and quickstart example)
# Install dependencies
sudo dnf install cmake gcc-c++ openssl-devel gtest-devel
# Build
mkdir build && cd build
cmake ..
make -j$(nproc)
# Run tests
ctest --output-on-failure# Install dependencies
sudo apt install cmake g++ libssl-dev libgtest-dev
# Build
mkdir build && cd build
cmake ..
make -j$(nproc)
# Run tests
ctest --output-on-failure# Install dependencies via vcpkg
vcpkg install openssl gtest
# Build
mkdir build
cd build
cmake .. -DCMAKE_TOOLCHAIN_FILE=[path-to-vcpkg]/scripts/buildsystems/vcpkg.cmake
cmake --build . --config Release
# Run tests
ctest -C Release --output-on-failurecd build
./unit_tests
# Or via CTest
ctest -R UnitTests --output-on-failureRequires Docker to run Infinispan server:
cd build
# Run all integration tests (starts server automatically) β representative subset:
./ping_integration_tests
./get_integration_tests
./put_integration_tests
./remove_integration_tests
./topology_integration_tests # Multi-node cluster tests
./hash_aware_routing_integration_tests # Smart routing tests
./retryview_integration_tests # User-decided retry (keyed)
./pingretry_integration_tests # User-decided retry (keyless ping)
# Or run all via CTest
ctest --output-on-failureNote: Integration tests use Docker Compose to manage multi-node Infinispan clusters (up to 4 nodes). Tests verify failover, rebalancing, and hash-aware routing.
π Live status lives in docs/STATUS.md β start there after any break. Design rationale is in docs/DECISIONS.md.
Current Progress: Full CRUD (PING/GET/PUT/REMOVE) + SCRAM auth + topology
awareness + hash-aware routing + async multiplexing + metadata/version-based
operations (Step 10) + typed error handling and user-decided retry, keyed and
keyless (Step 11) + Hot Rod URI support (RemoteCache::fromUri, issue #9) β all
shipped. Next: bulk operations (Step 12) or multiplexing benchmarks. See
docs/STATUS.md for live status.
Per-step milestone history (frozen at Step 9) is archived at
docs/archive/PROGRESS.md.
(Step numbers follow ../hotrod-foundry/ROADMAP.md;
docs/STATUS.md is authoritative for which steps are done β not
any headline count.)
Test Results (verified 2026-10-09):
- Unit Tests: 250/250 passing β
- Integration Tests: 92/92 passing β across 19 suites (against live Infinispan via Docker)
- β Cross-platform support (Linux + Windows)
- β Wire format primitives (vInt, vLong, strings, byte arrays)
- β Protocol 4.0 headers (complete spec with all conditional fields)
- β Client Intelligence 0x03 (HASH_DISTRIBUTION_AWARE)
- β Hash-aware routing (keys route directly to primary owner)
- β Automatic failover (primary β backup owners β any server)
- β Topology awareness (cluster rebalancing, updates)
- β Consistent hashing (MurmurHash3 x64_32, segment-based routing)
- β Connection pooling (one connection per server)
- β Multiplexed connections (concurrent async operations on single connection per server)
- β
Async operations (all operations return
std::futurefor non-blocking execution) - β PING operation (server connectivity check)
- β GET operation (read from cache with failover)
- β PUT operation (write to cache with lifespan/maxIdle)
- β REMOVE operation (delete from cache)
- β
Metadata / version-based operations (
getWithMetadata,putIfAbsent,replace,containsKey,removeWithVersion,replaceWithVersion) (Step 10) - β
Typed error handling (
HotRodClientExceptionwith phase / server status / tried nodes) +isTransient/outcomeUncertainclassification (Step 11a) - β
User-decided retry (
cache.excluding(e)bound view) for keyed ops and keylessping, with automatic before-send failover (Step 11b/11c) - β
SASL/SCRAM authentication (
setAuthentication(...)) β end-to-end for the SCRAM family (SCRAM-SHA-1/SCRAM-SHA-256/SCRAM-SHA-512), applied to every connection; seedocumentation/topics/security.adoc - β
Hot Rod URI (
RemoteCache::fromUri("hotrod://...")) β build a client from a connection string (hosts, credentials,sasl_mechanism/client_intelligence/protocol_versionparams);hotrod://only for now (TLS and more in issue #10) - β Integration test framework (GoogleTest + Docker + multi-node clusters)
// Connect with hash-aware routing
RemoteCache cache("localhost", 11222, "my-cache");
cache.setClientIntelligence(ClientIntelligence::HASH_DISTRIBUTION_AWARE);
cache.connect();
// All operations are async (return std::future) and can run concurrently
// Multiple operations share a single multiplexed connection per server
// CREATE/UPDATE - routes to primary owner
auto putFuture = cache.put(key, value, lifespan, maxIdle);
// READ - automatic failover to backup if primary fails
auto getFuture = cache.get(key);
// DELETE - with automatic failover
auto removeFuture = cache.remove(key);
// PING
auto pingFuture = cache.ping();
// Wait for results when needed
auto result = getFuture.get(); // blocks until complete
if (result.has_value()) {
ByteArray value = result.value();
}
// Or fire-and-forget for max throughput
for (int i = 0; i < 1000; i++) {
cache.put(keys[i], values[i]); // returns immediately, executes concurrently
}// hotrod://[user:password@]host1[:port1][,host2[:port2]...][?k=v&...]
// Returns a configured, not-yet-connected client (RemoteCache owns a mutex, so
// it is non-movable β unique_ptr). Call connect() yourself.
auto cache = RemoteCache::fromUri(
"hotrod://user:pass@node1:11222,node2:11222"
"?sasl_mechanism=SCRAM-SHA-256&client_intelligence=hash_distribution_aware",
"my-cache");
cache->connect();
// v1 supports hotrod:// only; the first host seeds the topology, credentials
// enable SCRAM, and sasl_mechanism/client_intelligence/protocol_version (Java
// "4.0"/"4.1" form) are honoured. Userinfo and query values are percent-decoded
// (RFC 3986), so a reserved character in a password is written encoded β e.g. a
// password of p@ss is "...://admin:p%40ss@host". hotrods:// (TLS), timeouts, and
// other parameters throw for now (see issue #10).π The full, authoritative backlog lives in docs/STATUS.md β π Backlog, and the 1β3 immediate items in β Next steps. This is just a summary.
- β
Step 10 β Metadata / version-based operations (shipped):
getWithMetadata,replaceWithVersion,removeWithVersion,putIfAbsent,replace,containsKey - β Step 11 β Error handling (shipped): ERROR response parsing, typed exception, user-decided retry (keyed + keyless)
- Step 12 β Bulk operations (next):
GET_ALL,PUT_ALL,BULK_GET - Also: multiplexing benchmarks, TLS/SSL support
cpp17-client/
βββ CMakeLists.txt # Build configuration
βββ README.md # This file
βββ LICENSE # Apache 2.0
βββ include/hotrod/ # Public API headers
β βββ Types.h # Type definitions
β βββ Codec.h # Wire format primitives
β βββ HeaderCodec.h # Protocol 4.0 headers
β βββ Connection.h # TCP connection
β βββ RemoteCache.h # High-level API (with hash-aware routing)
β βββ TopologyInfo.h # Cluster tracking
β βββ ConsistentHash.h # Smart routing
β βββ MurmurHash3.h # Hash function
βββ src/ # Implementation
β βββ codec/ # Encoding/decoding
β βββ transport/ # Network I/O
β βββ topology/ # Cluster tracking
β βββ hash/ # MurmurHash3 + consistent hashing
β βββ operations/ # Hot Rod operations (with failover)
βββ tests/ # Test suite
β βββ unit/ # 223 unit tests
β βββ integration/ # 92 integration tests, 19 suites (multi-node clusters)
βββ documentation/ # AsciiDoc user guide (index.adoc + topics/)
βββ examples/ # Usage examples
β βββ quickstart/ # Simple GET/PUT/REMOVE + retry + auth examples
βββ scripts/ # Test infrastructure
β βββ start_cluster.sh # Start multi-node cluster
β βββ add_cluster_node.sh # Add node dynamically
β βββ remove_cluster_node.sh # Remove node for failover tests
βββ test-configs/ # Server configurations
βββ docker-compose-cluster.yml # Multi-node setup
βββ infinispan-cluster.xml # No-auth config
π Working on this project? Read docs/WORKFLOW.md β the per-session workflow (how to re-orient after a break, what to update before you stop, and which protocol sources are authoritative). It's built for intermittent, solo work.
This implementation follows the hotrod-foundry incremental approach:
- Test-driven development - Test vectors β Unit tests β Implementation
- Java reference - Study Java implementation for each step (MANDATORY) β it is the authoritative source for behavior and semantics (what each op does, statuses, edge cases)
- Byte-level validation - Compare with test vectors and the Kaitai wire-format schema (authoritative for byte layout); if the two disagree, stop and investigate
- Cross-platform - Linux + Windows support required
- Infrastructure-first - Steps 0-5 (foundation), then operations
See hotrod-foundry/ROADMAP.md for the complete step-by-step plan.
The authoritative source for protocol behavior and semantics β study it first for each step (see workflow above).
- Local:
/home/rigazilla/git/infinispan/client/hotrod-client/ - Public: https://github.com/infinispan/infinispan/tree/main/client/hotrod-client
- Infinispan Project: https://infinispan.org/
- Hot Rod Foundry: ../hotrod-foundry/
- Java Client Source (authoritative for behavior/semantics): local
/home/rigazilla/git/infinispan/client/hotrod-client/Β· public https://github.com/infinispan/infinispan/tree/main/client/hotrod-client - Protocol Specification: https://infinispan.org/docs/stable/titles/hotrod_protocol/
- Wire-format schema (Kaitai, protocol 4.0/4.1): https://github.com/rigazilla/hotrod-dissector/tree/main/schemas β an independent, machine-readable encoding of the protocol; use it to double-check byte layouts against the Java client.
Apache 2.0 (matching Infinispan project)
Start with docs/WORKFLOW.md β the per-session workflow. In short, following the hotrod-foundry porting guidelines:
- One step at a time (complete step N before step N+1)
- Update docs/STATUS.md before you stop each session (next steps + date)
- Log design decisions in docs/DECISIONS.md as you make them
- Validate against test vectors
- Ensure cross-platform compatibility
- β v0.1.0 (2026-06-11): Foundation complete (Steps 0-5)
- β v0.2.0 (2026-06-12): PING operation complete (Step 6)
- β v0.3.0 (2026-06-12): GET operation complete (Step 7)
- β v0.4.0 (2026-06-12): PUT operation complete (Step 8)
- β v0.5.0 (2026-06-12): REMOVE operation complete (Step 9) - Full CRUD!
- β v0.6.0 (2026-06-17): Topology awareness (Step 4)
- β v0.7.0 (2026-06-17): Hash-aware routing with failover - Smart Client!
- β v0.8.0 (2026-09-20): Metadata / version-based operations (Step 10)
- β v0.9.0 (2026-09-25): Typed error handling + user-decided retry, keyed & keyless (Step 11)
- π― v0.10.0 (upcoming): Bulk operations (Step 12)
Maintained by: rigazilla
Status: Active development
Current Step: Error handling + user-decided retry complete (Step 11, keyed &
keyless). Next: bulk operations (Step 12). β