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

Code before:
            }
        }
        registrations = new IntObjectHashMap<>();
        eventfd = Native.newBlockingEventFd();
        eventfdReadBuf = PlatformDependent.allocateMemory(8);
        this.timeoutMemoryAddress = PlatformDependent.allocateMemory(KERNEL_TIMESPEC_SIZE);

        // We buffer a maximum of 2 * CompletionQueue.ringSize completions before we drain them in batches.
        // Also as we never submit an udata which is 0L we use this as the tombstone marker.
        completionBuffer = new CompletionBuffer(ringBuffer.ioUringCompletionQueue().ringSize * 2, 0);
    }

    @Override
    public void initialize() {
        ringBuffer.enable();
    }

    @Override
    public int run(IoExecutorContext context) {
        processedPerRun = 0;
        SubmissionQueue submissionQueue = ringBuffer.ioUringSubmissionQueue();
        CompletionQueue completionQueue = ringBuffer.ioUringCompletionQueue();
        if (!completionQueue.hasCompletions() && context.canBlock()) {
            if (eventfdReadSubmitted == 0) {
                submitEventFdRead();
            }
            long timeoutNanos = context.deadlineNanos() == -1 ? -1 : context.delayNanos(System.nanoTime());
            submitAndWaitWithTimeout(submissionQueue, false, timeoutNanos);
        } else {
            submissionQueue.submit();
        }
        // we might call submitAndRunNow() while processing stuff in the completionArray we need to
        // add the processed completions to processedPerRun as this might also be updated by submitAndRunNow()
        processedPerRun += drainAndProcessAll(completionQueue, this::handle);

        // Let's submit one more time as the completions might have added things to the submission queue.
        submissionQueue.submit();

        return processedPerRun;
    }

    private void submitAndRunNow() {
        SubmissionQueue submissionQueue = ringBuffer.ioUringSubmissionQueue();
        CompletionQueue completionQueue = ringBuffer.ioUringCompletionQueue();
        if (submissionQueue.submit() > 0) {
            processedPerRun += drainAndProcessAll(completionQueue, this::handle);
        }
    }

    private int drainAndProcessAll(CompletionQueue completionQueue, CompletionCallback callback) {
        int processed = 0;

Review comment (suggestion):
@chrisvest @franz1981 This change is important and fixes the 10 - 15 % perf drop I was seeing and why I did https://github.com/netty/netty/pull/14711 in the first place. 

Code after:

        // We buffer a maximum of 2 * CompletionQueue.ringSize completions before we drain them in batches.
        // Also as we never submit an udata which is 0L we use this as the tombstone marker.
        completionBuffer = new CompletionBuffer(ringBuffer.ioUringCompletionQueue().ringSize * 2, 0);
    }

    @Override
    public void initialize() {
        ringBuffer.enable();
    }

    @Override
    public int run(IoExecutorContext context) {
        int processedPerRun = 0;
        SubmissionQueue submissionQueue = ringBuffer.ioUringSubmissionQueue();
        CompletionQueue completionQueue = ringBuffer.ioUringCompletionQueue();
        if (!completionQueue.hasCompletions() && context.canBlock()) {
            if (eventfdReadSubmitted == 0) {
                submitEventFdRead();
            }
            long timeoutNanos = context.deadlineNanos() == -1 ? -1 : context.delayNanos(System.nanoTime());
            submitAndWaitWithTimeout(submissionQueue, false, timeoutNanos);
        } else {
            submissionQueue.submit();
        }
        for (;;) {
            // we might call submitAndRunNow() while processing stuff in the completionArray we need to
            // add the processed completions to processedPerRun.
            int processed = drainAndProcessAll(completionQueue, this::handle);
            processedPerRun += processed;

            // Let's submit again.
            // If we were not able to submit anything and there was nothing left in the completionBuffer we will
            // break out of the loop and return to the caller.
            if (submissionQueue.submit() == 0 && processed == 0) {
                break;
            }
        }

        return processedPerRun;
    }

    void submitAndRunNow(long udata) {
        SubmissionQueue submissionQueue = ringBuffer.ioUringSubmissionQueue();
        CompletionQueue completionQueue = ringBuffer.ioUringCompletionQueue();
        if (submissionQueue.submit() > 0) {
            completionBuffer.drain(completionQueue);
            completionBuffer.processOneNow(this::handle, udata);
        }
    }