콘텐츠로 이동

한국어 | English

레퍼런스 목차

04. Eventing

이 category는 socket monitoring, 재사용 가능한 poller, standalone timer를 다룬다 — 각각 Socket.monitorOpen(...)(Sockets category)와 Zlink.createPoller()/Zlink.createTimer()(Core category)로 생성된다. 정확한 signature는 contracts/eventing/가 소유한다.


SocketMonitor

socket의 connection lifecycle event를 관찰하고 현재 상태를 읽는다.

try (SocketMonitor monitor = socket.monitorOpen(MonitorEventType.CONNECTED, MonitorEventType.DISCONNECTED)) {
    MonitorEvent event = monitor.recv(RecvFlags.NONE);
    MonitorStatus status = monitor.status();
}

Options.

Member 의미
recv(RecvFlags.DONT_WAIT) 다음 queued lifecycle event non-blocking pull
recv() / recv(RecvFlags flags) 다음 event를 가져옴; 둘 다 MonitorEvent를 직접 반환한다 — dotnet의 MonitorEvent?와 달리 Optional/nullable이 아니다
status() 시점 스냅샷 MonitorStatus를 반환
close() caller-owned monitor resource 해제

Completion result. 모든 member는 동기다. SocketMonitor extends AutoCloseable이다.

선택 기준. pull 기반 lifecycle-event drain loop엔 recv를 쓰고 시점 스냅샷엔 status()를 쓴다.


MonitorStatus

SocketMonitor.status()가 반환하는, socket의 monitored 상태와 auto-high-water-mark telemetry 스냅샷. Java record다 — 모든 component가 불변이며 record accessor로 접근한다(status.sndPendingMsgs(), get 접두 메서드가 아님).

Options. 인자 없음 — 직접 생성하지 않고 status()로 얻는다.

그룹 Component
ABI identity abiVersion, structSize(int)
Source/state sourceKind(MonitorSourceKind), stateFlags(EnumSet<MonitorStateFlags>), detailFlags(EnumSet<MonitorStatusDetailFlags>), isReady()(계산 method: stateFlags.contains(MonitorStateFlags.READY))
Pending count sndPendingMsgs, rcvPendingMsgs(long)
Auto-HWM 설정 autoHwmEnabled(boolean), autoHwmProfile(AutoHwmProfile), autoHwmRole, autoHwmPolicyClass(int), autoHwmUnitBudgetBytes, autoHwmSocketMessageSlots(long), autoHwmSizeCap(int)
Connection bucket autoHwmConnectionBucketEnabled(boolean), autoHwmConnectionBucketCount/Index/Hwm4K(int), autoHwmConnectionBucketHysteresisRetained(boolean)
Auto-HWM plan(byte) autoHwmEffectiveMessageBytes, autoHwmPlannedSendHwmBytes/PlannedRecvHwmBytes, autoHwmAppliedSendHwmBytes/AppliedRecvHwmBytes(long), autoHwmAppliedSndBuffer/AppliedRcvBuffer(int)
Auto-HWM recalc autoHwmLastRecalcMs(long), autoHwmLastRecalcReason(AutoHwmRecalcReason), autoHwmSendBlockedRatioPpm(int)
Auto-HWM deferred shrink autoHwmDeferredSendHwmBytes/DeferredRecvHwmBytes(long, 대응하는 autoHwmDeferredSendHwmValid/DeferredRecvHwmValid boolean이 true일 때만 유효)
In-flight/과금 sendBytesInFlight, recvBytesInFlight, minimumCoreMessageChargeBytes, oversizeMessageAdmissionCount, oversizeMessageAdmissionMaxBytes(long)

Completion result. 해당 없음 — 불변 record 스냅샷.

선택 기준. stateFlags를 직접 디코딩하는 대신 isReady()를 호출한다. socket의 실제 send/receive HWM이 설정한 CommonSocketOptions 값(Sockets category)과 다른 이유를 진단할 땐 connection-bucket과 auto-HWM-plan component를 쓴다.


Poller

socket, file descriptor, timer를 하나의 재사용 가능한 wait로 multiplex한다.

try (Poller poller = Zlink.createPoller()) {
    poller.add(dealer, 1L, PollEventFlags.POLLIN);
    poller.add(timer, 2L);
    PollEvents events = new PollEvents(8);
    int ready = poller.wait(events, Duration.ofSeconds(1));
    for (int i = 0; i < events.readyCount(); i++) {
        PollEvent event = events.eventAt(i);
    }
}

Options.

Member 의미
add(Socket socket, long slot, PollEventFlags... events) socket을 등록; slot은 대응하는 poll 결과로 그대로 되돌아오는 caller token — 인자 순서(slot이 varargs events보다 앞)를 참고
addFd(int fd, long slot, PollEventFlags... events) raw file descriptor를 등록, 같은 slot/varargs 형태
add(ZlinkTimer timer, long slot) timer를 socket/fd와 함께 multiplex하도록 등록
modify(Socket socket, PollEventFlags... events) 이미 등록된 socket의 감시 event를 교체
modifyFd(int fd, PollEventFlags... events) 이미 등록된 fd의 감시 event를 교체
remove(Socket) / remove(int fd) / remove(ZlinkTimer) source 등록을 해제; boolean 반환, 실제로 등록돼 있었으면 true
clear() 모든 source를 한 번에 등록 해제
size() int, 현재 등록된 source 개수
wait(PollEvents events, Duration timeout) timeout까지 block하며 events를 그 자리에서 채움

Completion result. 등록/제거 member는 동기다. waittimeout까지 block하며, events를 그 자리에서 채우고 준비된 개수를 반환한다(이후 events.readyCount()로도 읽을 수 있다).

선택 기준. 서비스 수명 전체에서 poller 하나를 쓴다. 감시하는 event만 바뀔 땐 remove + add 대신 modify를 선호한다. wait 호출마다 새로 할당하는 대신, receive에 Received를 재사용하는 것과 같은 방식으로 PollEvents buffer 하나를 재사용한다.


PollEvents

poller wait를 위한, capacity까지 준비된 event를 담는 미리 할당된 결과 buffer — dotnet의 Span<PollEvent>/cpp의 raw pointer-and-capacity 쌍과 구별되는 Java 고유 설계다.

PollEvents events = new PollEvents(16);
poller.wait(events, Duration.ofMillis(500));
for (int i = 0; i < events.readyCount(); i++) {
    if (events.hasEvent(i, PollEventFlags.POLLIN)) { /* ... */ }
}

Options. public 생성자 PollEvents(int capacity)(capacity <= 0이면 IllegalArgumentException). 아래 모든 accessor는 capacity()가 아니라 readyCount()에 대해 bounds-check되며 범위를 벗어나면 IndexOutOfBoundsException을 던진다.

Member 의미
capacity() 생성자에 넘긴 고정 용량
readyCount() 마지막 wait 이후 몇 개 slot이 준비된 event를 담고 있는지
sourceKind(int index) 해당 index의 준비된 source 종류
slot(int index) 그 source 등록 시 넘긴 caller token
revents(int index) 해당 index의 raw int poll-event bitmask
hasEvent(int index, PollEventFlags event) revents(index)에 대한 편의 bit-test
fd(int index) 해당 index의 file descriptor, FD kind source에서만 채워짐
eventAt(int index) 해당 index의 PollEvent record를 materialize

Completion result. 모든 accessor는 동기다. Poller.wait(...)는 package-private markReadyCount/markEvent를 통해 PollEvents instance를 그 자리에서 변경한다 — public contract 표면이 아니다.

선택 기준. revents(index)를 손으로 bit-test하는 대신 hasEvent(index, flag)를 선호한다. caller가 진짜로 boxed PollEvent record가 필요할 때만 eventAt(index)를 쓴다 — 개별 accessor를 순회하면 hot polling loop에서 그 할당을 피할 수 있다.


PollEvent

PollEvents.eventAt(index)가 필요 시 materialize하는, poller wait가 보고하는 준비된 source 하나. Java record다.

Options. 인자 없음 — 직접 생성하지 않고 PollEvents.eventAt(...)으로 얻는다.

Component 타입 의미
sourceKind PollSourceKind source가 SOCKET/FD/TIMER 중 무엇인지
slot long 등록 시 제공한 caller token
revents int raw poll-event bitmask
fd int file descriptor, FD kind source에서만 채워짐

Completion result. 해당 없음 — 불변 record.

선택 기준. sourceKind()/slot()으로 분기해 각 결과를 대응하는 socket·descriptor·timer로 연결한다.


ZlinkTimer

interval마다 fire하며 (recv로) poll하거나 poller를 통해 구동할 수 있는 standalone timer.

try (ZlinkTimer timer = Zlink.createTimer()) {
    timer.start(Duration.ofSeconds(1), 0L);
    long count = timer.recv();
}

Options.

Member 의미
start(Duration interval, long repeatCount) interval마다 fire를 시작; repeatCount == 0은 무제한
stop() fire를 멈춤; start로 재시작 가능
recv() long을 직접 반환 — 누적 fire count; dotnet의 ulong?/cpp의 std::optional<uint64_t>와 달리 소스에선 nullable/optional이 아니다
반복 recv() pull surface에서 cumulative fire count drain

Completion result. 모든 member는 동기다. ZlinkTimer extends AutoCloseable이다.

선택 기준. 만료를 pull하려면 recv를 쓰고 socket과 함께 하나의 wait에서 multiplex하려면 Poller.add(ZlinkTimer, long)로 등록한다.


Handler functional interface

Interface 등록하는 곳 Signature
MonitorEvent SocketMonitor.recv(...) monitor queue가 반환하는 caller-owned value
long fire count ZlinkTimer.recv() timer queue가 반환하는 cumulative count

Eventing enum

위 모든 항목에서 참조하는 공유 enum.

Enum 사용처
MonitorEventType Socket.monitorOpen(MonitorEventType...)(Sockets category), MonitorEvent.event() CONNECTED, CONNECT_DELAYED, CONNECT_RETRIED, LISTENING, BIND_FAILED, ACCEPTED, ACCEPT_FAILED, CLOSED, CLOSE_FAILED, DISCONNECTED, MONITOR_STOPPED, HANDSHAKE_FAILED_NO_DETAIL, CONNECTION_READY, HANDSHAKE_FAILED_PROTOCOL, HANDSHAKE_FAILED_AUTH, PEER_WEIGHT_CHANGED, ALL — varargs 집합을 raw mask로 OR하는 static combine(MonitorEventType...) helper가 있음
MonitorSourceKind MonitorStatus.sourceKind() SOCKET
MonitorStateFlags MonitorStatus.stateFlags()(EnumSet으로) READY, BOUND_READY, CLOSED
MonitorStatusDetailFlags MonitorStatus.detailFlags()(EnumSet으로) SEND_PENDING_MESSAGES, RECEIVE_PENDING_MESSAGES, AUTO_HWM_BUDGET, AUTO_HWM_BUFFERS
PollSourceKind PollEvent.sourceKind(), PollEvents.sourceKind(int) SOCKET, FD, TIMER
PollEventFlags Poller.add/modify/wait, PollEvents.hasEvent(...) POLLIN, POLLOUT, POLLERR, POLLPRI, POLLCOMPLETIONNONE member가 없다(빈 상태는 그냥 flag를 하나도 주지 않는 것이지 열거자가 아니다)

선택 기준. Java는 bitmask 형태의 MonitorStateFlags/ MonitorStatusDetailFlags/PollEventFlags[Flags]가 붙은 enum(dotnet)이나 비트 OR 가능한 flag class(cpp)가 아니라, EnumSet/varargs로 소비되는 순수 enum 타입으로 노출한다 — enum 상수 자체에 비트 OR를 하는 게 아니라 여러 개를 varargs로 넘기거나 EnumSet으로 되읽어서 결합한다.


contracts/eventing/Java 바인딩 스펙에서 전체 근거를 확인한다.