Skip to content

[cleanup][test] Remove PortManager and use kernel-assigned ports everywhere#25694

Open
merlimat wants to merge 3 commits intoapache:masterfrom
merlimat:cleanup/remove-port-manager
Open

[cleanup][test] Remove PortManager and use kernel-assigned ports everywhere#25694
merlimat wants to merge 3 commits intoapache:masterfrom
merlimat:cleanup/remove-port-manager

Conversation

@merlimat
Copy link
Copy Markdown
Contributor

@merlimat merlimat commented May 6, 2026

Motivation

PortManager (in pulsar-common) and the inner BasePortManager of LocalBookkeeperEnsemble allocated "free" ports via ServerSocket(0) and tracked them in a JVM-level lock set. The lock was JVM-only, so the OS-level port could still be grabbed by another process between allocation and bind, producing flaky BindExceptions in tests (most recently ShadowTopicRealBkTest.setup).

The class has outlived its usefulness — modern BookKeeper identifies bookies by bookieId, not host:port, so kernel-assigned ports (port 0) work across the board. The "lock" never actually prevented OS-level collisions anyway.

Modifications

Removed

  • pulsar-common/.../PortManager.java and its test.
  • pulsar-package-management/.../test/PortManager.java (unused duplicate).
  • BasePortManager inner class in LocalBookkeeperEnsemble.
  • All bkBasePort constructor variants of LocalBookkeeperEnsemble.
  • The Supplier<Integer> portManager parameter from LocalBookkeeperEnsemble — every caller was passing () -> 0. Bookies now always bind to kernel-assigned ports internally.
  • --bookkeeper-port CLI option from pulsar standalone (and its setter, getter, builder method, plus the test calls). Multi-bookie standalone gets kernel-assigned ports.
  • useDynamicBrokerPorts() toggle in MultiBrokerBaseTest (now always dynamic).
  • bkPort field in BKCluster.BKClusterConf.

Refactored

  • BKCluster: bookies bind to port 0; bookieId is derived from the data dir hash so multiple cluster instances on a shared metadata store don't collide on cookie validation, while restarts on the same dir keep cookies stable. The unused cookie-parsing port-recovery logic is dropped.
  • MultiBrokerBaseTest: mainBrokerPort and additionalBrokerPorts are populated post-start from pulsar.getBrokerListenPort() instead of pre-allocated.
  • PulsarTestContext.handlePreallocatePorts: inlined ServerSocket(0) allocation. Still needed by tests that build advertised-listener URLs before the broker starts (those URLs require a known port up front).
  • 17 test files updated: PortManager.nextLockedFreePort() calls replaced with 0 (let kernel pick) or inline ServerSocket(0) (only where pre-allocation is genuinely required, e.g. for advertised-listener URLs).
  • PulsarStandaloneTest.testStandaloneWithRocksDB: assertion switched from getBookiePort() (now returns kernel-assigned ports that change per restart) to getBookieId() (the persistent BK identity).

Behavior change

--bookkeeper-port is gone from pulsar standalone. Bookies get kernel-assigned ports — no impact for normal usage since clients only connect to the broker, not directly to bookies.

Verifying this change

Locally exercised the affected tests:

  • LocalBookkeeperEnsembleTest (2/2)
  • ShadowTopicRealBkTest (1/1)
  • PulsarStandaloneTest (5/5)
  • EndToEndTest for BKCluster (10 passed, 1 skipped)
  • AdvertisedListenersTest, LoadManagerFailFastTest, AdvertisedListenersMultiBrokerLeaderElectionTest

Full compileJava and compileTestJava clean.

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): no
  • The public API: removes --bookkeeper-port CLI option from pulsar standalone
  • The schema: no
  • The default values of configurations: no
  • The threading model: no
  • The binary protocol: no
  • The REST endpoints: no
  • The admin CLI options: --bookkeeper-port removed from pulsar standalone
  • The metrics: no
  • Anything that affects deployment: no

merlimat added 2 commits May 5, 2026 18:36
…ywhere

`PortManager` (in pulsar-common) and the inner `BasePortManager` of
`LocalBookkeeperEnsemble` allocated "free" ports via `ServerSocket(0)` and
tracked them in a JVM-level lock set. The lock was JVM-only, so the OS-level
port could still be grabbed by another process between allocation and bind,
producing flaky `BindException`s in tests. The class has outlived its
usefulness — modern BookKeeper identifies bookies by `bookieId`, not host:port,
so port 0 (kernel-assigned) is fine across the board.

Removed:
- `pulsar-common/...PortManager.java` and its test.
- `pulsar-package-management/...test/PortManager.java` (unused duplicate).
- `BasePortManager` inner class in `LocalBookkeeperEnsemble`.
- `bkBasePort` constructor variants of `LocalBookkeeperEnsemble` (no callers
  left after the standalone change).
- `--bookkeeper-port` CLI option from `PulsarStandalone` (and its setter,
  getter, builder method, plus 3 test calls). Multi-bookie standalone now
  always uses kernel-assigned ports — bookies are identified by `bookieId`.
- `useDynamicBrokerPorts()` toggle in `MultiBrokerBaseTest` (now always true
  in spirit; ports come from `getBrokerListenPort()` after start).
- `bkPort` field in `BKCluster.BKClusterConf`.

Refactored:
- `BKCluster`: bookies bind to port 0; `bookieId` is derived from the data dir
  hash so multiple cluster instances on a shared metadata store don't collide
  on cookie validation, while restarts on the same dir keep cookies stable.
  The unused cookie-parsing port-recovery logic is dropped.
- `MultiBrokerBaseTest`: `mainBrokerPort` and `additionalBrokerPorts` are
  populated post-start from `pulsar.getBrokerListenPort()` instead of
  pre-allocated.
- `PulsarTestContext.handlePreallocatePorts`: inlined `ServerSocket(0)`
  allocation. Still needed by tests that build advertised-listener URLs
  before the broker starts.
- 17 test files: `PortManager.nextLockedFreePort()` calls replaced with
  `0` (let kernel pick) or inline `ServerSocket(0)` (only where pre-allocation
  is genuinely needed, e.g. for advertised-listener URLs).
- `PulsarStandaloneTest.testStandaloneWithRocksDB`: assertion switched from
  `getBookiePort()` (now returns kernel-assigned ports that change per restart)
  to `getBookieId()` (the persistent identity).

Behavior change: `--bookkeeper-port` is gone from `pulsar standalone`. Bookies
get kernel-assigned ports — no impact for normal usage since clients only
connect to the broker.
Now that all callers pass () -> 0, the supplier is dead weight. Remove it
from LocalBookkeeperEnsemble entirely; bookies always bind to port 0.
Updated all 41 call sites accordingly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants