mansart-pool is a JDBC connection pool implemented in pure Java 25, with no external dependency, with a lock-free Semaphore + ConcurrentLinkedDeque and a housekeeper on a virtual thread. It is fully decoupled from the rest of Mansart: its only contract is javax.sql.DataSource.

Mission

  • Provide a performant, simple, configurable DataSource.

  • Be virtual-thread-native — no synchronized contention on the hot path.

  • Stay optional — the user can plug mansart-jakarta-data onto any DataSource (Hikari, Tomcat-JDBC, c3p0).

Position in the workspace

mansart-pool is a standalone peer of the other Mansart modules. It depends neither on mansart-jakarta-data nor on mansart-transactions. Conversely, mansart-jakarta-data and mansart-transactions may use it but do not depend on it at compile time.

Diagram

Modules

Sub-module Role

mansart-pool-api

PoolConfig, PoolConfig.Builder, PoolMetrics, PoolException, ValidationMode. Zero dependency.

mansart-pool-core

MansartDataSource (impl DataSource), the hand-written PooledConnection wrapper, housekeeper.

Public API

PoolConfig config = PoolConfig.builder()
    .jdbcUrl("jdbc:postgresql://db.local:5432/shop")
    .username("shop").password("...")
    .minIdle(4).maxSize(32)
    .acquireTimeout(Duration.ofSeconds(5))
    .idleTimeout(Duration.ofMinutes(10))
    .maxLifetime(Duration.ofMinutes(30))
    .validation(ValidationMode.ON_BORROW)
    .leakDetectionThreshold(Duration.ofSeconds(30))
    .build();

DataSource ds = MansartDataSource.of(config);
PoolMetrics metrics = ((MansartDataSource) ds).snapshot();

See Reference for the full property table.

Runtime architecture

MansartDataSource (impl DataSource)
    │
    ├── ConcurrentLinkedDeque<PooledEntry> idle   (lock-free LIFO)
    ├── Set<PooledEntry>                   inUse  (ConcurrentHashMap.newKeySet)
    ├── Semaphore                          permits (size = maxSize, fair=false)
    └── housekeeper                        (virtual thread)

Acquire (getConnection()):

  1. permits.acquire(acquireTimeout) — hard bound.

  2. idle.poll() — hot LIFO.

  3. If valid (ON_BORROW mode: validationQuery when set, else Connection.isValid) → inUse.add; otherwise → close physically + create new.

  4. Return: the PooledConnection wrapper, whose close() returns to the pool.

Release (Connection.close() on the wrapper):

  1. Restore defaults — rollback if dirty, autoCommit=true, default isolation.

  2. inUse.remove(entry).

  3. Still valid and younger than maxLifetime → idle.offerFirst(entry); otherwise → close physically.

  4. permits.release().

The wrapper is a plain hand-written PooledConnection implements Connection — not java.lang.reflect.Proxy (no per-call invoke overhead), not generated bytecode. close() returns the connection to the pool instead of closing it. See Internals.

Transactions integration

The pool carries no transactional context itself: JTA enlistment is the job of mansart-transactions (its JDBC bridge enlists the connection with the transaction manager). See mansart-transactions.

Metrics

PoolMetrics (lock-free snapshot via MansartDataSource.snapshot()):

  • active(), idle(), waiting().

  • totalBorrows(), totalTimeouts(), totalLeaks().

  • meanBorrowDuration().

Micrometer / Prometheus bridge on the backlog (MP3).

Leak detection

leakDetectionThreshold(Duration) records, on acquire, a stack trace inside the PooledConnection. If the connection stays borrowed longer than the threshold, the housekeeper logs a WARNING with the stack — immediate diagnosis of the offending code path. Enable in staging, disable in production if the overhead is measured.

Comparison vs HikariCP

  • Threading — Mansart virtual-thread-native, no pinning under Loom load. HikariCP uses synchronized blocks that pin.

  • Dependencies — Mansart zero-dep. HikariCP depends on SLF4J + javassist (transitively via micrometer).

  • AOT — Mansart compatible with GraalVM native-image and Leyden CDS without configuration. HikariCP needs --initialize-at-build-time for javassist.

  • API — very close (HikariConfig → PoolConfig). See Migration.

Numbers: see mansart-pool BENCH.md (2026-05-06 baseline vs HikariCP).

Roadmap

  • ✅ MP1 — API + skeleton.

  • ⏳ MP2 — Core implementation (MansartDataSource, semaphore, deque, validation).

  • ⏳ MP3 — Metrics + leak detection.

  • ⏳ MP4 — mansart-jakarta-data integration (transparent for the user).