mirror of https://github.com/OpenIdentityPlatform/OpenDJ.git

Valery Kharseko
5 hours ago a77994116fdc36bff765e79f85fdb29027259f32
refs
author Valery Kharseko <vharseko@3a-systems.ru>
Monday, November 2, 2026 09:21 +0100
committer GitHub <noreply@github.com>
Monday, November 2, 2026 09:21 +0100
commita77994116fdc36bff765e79f85fdb29027259f32
tree 3c0a21dce8ac0b01a1e4a9b92930befadbdf41a5 tree | zip | gz
parent c3e63df192c7ea16efeeda75a0603de2b617cf65 view | diff
[#1250] Report unexpected replication stream EOF as a bad disconnection (#1254)

Fixes #1250

A replication server reports an unexpected end of a peer's stream at
NOTICE, while a reset is reported as a bad disconnection at ERROR. After
#1248, the reader's NOTICE is the only record when the peer closes
without a `StopMsg` and the read reaches EOF.

`Session.read()` now throws `EOFException`. For protocol V4 and later,
`ServerReader` logs the existing badly-disconnected error (211 for a
directory server, 181 for a replication server), unless the handler is
shutting down or this side has initiated the session close. Those
local-close and shutdown cases retain NOTICE 53. Older peers also retain
the NOTICE, since they do not send `StopMsg`. An actual `StopMsg` still
ends the reader without a disconnection report. Where a log record
includes the exception class, EOF now appears as `EOFException: no more
data` instead of `IOException: no more data`; external log parsers
matching the old text may need updating.

A peer whose session has recorded an error, including an abort by the
stop watchdog or heartbeat monitor, sends no `StopMsg`. EOF from such a
V4+ peer is intentionally reported at ERROR. The convergence filter
continues to reject 181/211 in a graceful restart window; admitting them
would also hide failures that already produced a reset. The reader and
writer comments describe the session-error exception and the
local-close/shutdown conditions.

The reader tests use a real `Session` and controlled input streams.
Eight cases cover EOF at the V4 boundary and at the current protocol
version, EOF during a frame, an older peer, shutdown, local close before
reading, local close while reading is blocked, and `StopMsg`. The
shutdown case requires exactly one NOTICE 53; the `StopMsg` case
requires neither ERROR 211 nor NOTICE 53. The concurrent case releases
EOF only after local close; it uses bounded waits, propagates reader
failures through a future, and checks no ERROR 211 and exactly one
NOTICE 53.

**Validation**

On the current revision, JDK 21:

```sh
mvn -o -Pprecommit verify -pl opendj-server-legacy -am \
-Dit.test=ServerReaderDisconnectTest,ServerWriterDisconnectTest,SessionTest \
-Dfailsafe.failIfNoSpecifiedTests=false
```

All 18 selected tests pass: 8 reader, 4 writer and 6 session tests.
Reactor verify succeeds.

The eight reader cases were also run directly with TestNG on the
reactor's test classpath, using separately compiled reader variants. The
unmodified reader passes all eight. Each of these mutations fails
exactly the corresponding test, with the other seven passing:

- Restrict the EOF error guard to protocol V4 (`==` instead of `>=`):
`eofFromCurrentPeerIsReported` fails because ERROR 211 is missing.
- Suppress the EOF record during shutdown:
`eofDuringShutdownIsNotReportedAsBadDisconnection` fails because NOTICE
53 is missing.
- Throw from the `StopMsg` arm:
`stopMessageIsNotReportedAsBadDisconnection` fails on the unexpected
NOTICE 53.

The mutation classes were built outside the reactor output directories;
the final reactor verify used the unmodified production code.

Earlier head `af6ec1301b` passed [CI run
41065150477](https://github.com/OpenIdentityPlatform/OpenDJ/actions/runs/41065150477),
including all four convergence rows and Docker default/alpine. That
result does not establish coverage of the abort path. Convergence and
Docker replication were not run locally for this revision.
3 files modified
1 files added
273 ■■■■■ changed files
opendj-server-legacy/src/main/java/org/opends/server/replication/protocol/Session.java 3 ●●●●● diff | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/replication/server/ServerReader.java 18 ●●●●● diff | view | raw | blame | history
opendj-server-legacy/src/main/java/org/opends/server/replication/server/ServerWriter.java 6 ●●●●● diff | view | raw | blame | history
opendj-server-legacy/src/test/java/org/opends/server/replication/server/ServerReaderDisconnectTest.java 246 ●●●●● diff | view | raw | blame | history