Repository: netty/netty
File: transport-classes-io_uring/src/main/java/io/netty/channel/uring/IoUringIoHandler.java (Java)

Code before:
    public void prepareToDestroy() {
        shuttingDown = true;
        CompletionQueue completionQueue = ringBuffer.ioUringCompletionQueue();
        SubmissionQueue submissionQueue = ringBuffer.ioUringSubmissionQueue();

        List<DefaultIoUringIoRegistration> copy = new ArrayList<>(registrations.values());

        for (DefaultIoUringIoRegistration registration: copy) {
            registration.close();
        }

        // Write to the eventfd to ensure that if we submitted a read for the eventfd we will see the completion event.
        Native.eventFdWrite(eventfd.intValue(), 1L);

        // Ensure all previously submitted IOs get to complete before tearing down everything.
        long udata = UserData.encode(RINGFD_ID, Native.IORING_OP_NOP, (short) 0);
        submissionQueue.addNop((byte) Native.IOSQE_IO_DRAIN, udata);

        // Submit everything and wait until we could drain i.
        submissionQueue.submitAndWait();
        while (completionQueue.hasCompletions()) {
            completionQueue.process(this::handle);

            if (submissionQueue.count() > 0) {
                submissionQueue.submit();
            }
        }
    }

    @Override
    public void destroy() {
        SubmissionQueue submissionQueue = ringBuffer.ioUringSubmissionQueue();
        CompletionQueue completionQueue = ringBuffer.ioUringCompletionQueue();
        drainEventFd();
        if (submissionQueue.remaining() < 2) {
            // We need to submit 2 linked operations. Since they are linked, we cannot allow a submit-call to
            // separate them. We don't have enough room (< 2) in the queue, so we submit now to make more room.
            submissionQueue.submit();
        }
        // Try to drain all the IO from the queue first...
        long udata = UserData.encode(RINGFD_ID, Native.IORING_OP_NOP, (short) 0);
        // We need to also specify the Native.IOSQE_LINK flag for it to work as otherwise it is not correctly linked
        // with the timeout.
        // See:
        // - https://man7.org/linux/man-pages/man2/io_uring_enter.2.html
        // - https://git.kernel.dk/cgit/liburing/commit/?h=link-timeout&id=bc1bd5e97e2c758d6fd975bd35843b9b2c770c5a
        submissionQueue.addNop((byte) (Native.IOSQE_IO_DRAIN | Native.IOSQE_LINK), udata);
        // ... but only wait for 200 milliseconds on this
        submitAndWaitWithTimeout(submissionQueue, true, TimeUnit.MILLISECONDS.toNanos(200));
        completionQueue.process(this::handle);
        for (IoUringBufferRing ioUringBufferRing : registeredIoUringBufferRing.values()) {

Review comment (suggestion):
So this was, before, just submitting (if any) new requests without draining any new completion(s)?
That can make the memory to grow larger and larger ....

Whilst with this one here, it means that it process completions whilst submitting new requests reducing the amount of unprocessed completions. It looks nice to me @normanmaurer if I got it right

Code after:
    @Override
    public void prepareToDestroy() {
        shuttingDown = true;
        CompletionQueue completionQueue = ringBuffer.ioUringCompletionQueue();
        SubmissionQueue submissionQueue = ringBuffer.ioUringSubmissionQueue();

        List<DefaultIoUringIoRegistration> copy = new ArrayList<>(registrations.values());

        for (DefaultIoUringIoRegistration registration: copy) {
            registration.close();
        }

        // Write to the eventfd to ensure that if we submitted a read for the eventfd we will see the completion event.
        Native.eventFdWrite(eventfd.intValue(), 1L);

        // Ensure all previously submitted IOs get to complete before tearing down everything.
        long udata = UserData.encode(RINGFD_ID, Native.IORING_OP_NOP, (short) 0);
        submissionQueue.addNop((byte) Native.IOSQE_IO_DRAIN, udata);

        // Submit everything and wait until we could drain i.
        submissionQueue.submitAndGet();
        while (completionQueue.hasCompletions()) {
            completionQueue.process(this::handle);

            if (submissionQueue.count() > 0) {
                submissionQueue.submitAndGetNow();
            }
        }
    }

    @Override
    public void destroy() {
        SubmissionQueue submissionQueue = ringBuffer.ioUringSubmissionQueue();
        CompletionQueue completionQueue = ringBuffer.ioUringCompletionQueue();
        drainEventFd();
        if (submissionQueue.remaining() < 2) {
            // We need to submit 2 linked operations. Since they are linked, we cannot allow a submit-call to
            // separate them. We don't have enough room (< 2) in the queue, so we submit now to make more room.
            submissionQueue.submit();
        }
        // Try to drain all the IO from the queue first...
        long udata = UserData.encode(RINGFD_ID, Native.IORING_OP_NOP, (short) 0);
        // We need to also specify the Native.IOSQE_LINK flag for it to work as otherwise it is not correctly linked
        // with the timeout.
        // See:
        // - https://man7.org/linux/man-pages/man2/io_uring_enter.2.html
        // - https://git.kernel.dk/cgit/liburing/commit/?h=link-timeout&id=bc1bd5e97e2c758d6fd975bd35843b9b2c770c5a
        submissionQueue.addNop((byte) (Native.IOSQE_IO_DRAIN | Native.IOSQE_LINK), udata);
        // ... but only wait for 200 milliseconds on this
        submitAndWaitWithTimeout(submissionQueue, true, TimeUnit.MILLISECONDS.toNanos(200));
        completionQueue.process(this::handle);