Process the queue of commands and dispatch them to the stream. This method is only called in the event loop
()
| 120 | * called in the event loop |
| 121 | */ |
| 122 | private void flush() { |
| 123 | try (TaskCloseable ignore = PerfMark.traceTask("WriteQueue.periodicFlush")) { |
| 124 | QueuedCommand cmd; |
| 125 | int i = 0; |
| 126 | boolean flushedOnce = false; |
| 127 | while ((cmd = queue.poll()) != null) { |
| 128 | cmd.run(channel); |
| 129 | if (++i == DEQUE_CHUNK_SIZE) { |
| 130 | i = 0; |
| 131 | // Flush each chunk so we are releasing buffers periodically. In theory this loop |
| 132 | // might never end as new events are continuously added to the queue, if we never |
| 133 | // flushed in that case we would be guaranteed to OOM. |
| 134 | try (TaskCloseable ignore2 = PerfMark.traceTask("WriteQueue.flush0")) { |
| 135 | channel.flush(); |
| 136 | } |
| 137 | flushedOnce = true; |
| 138 | } |
| 139 | } |
| 140 | // Must flush at least once, even if there were no writes. |
| 141 | if (i != 0 || !flushedOnce) { |
| 142 | try (TaskCloseable ignore2 = PerfMark.traceTask("WriteQueue.flush1")) { |
| 143 | channel.flush(); |
| 144 | } |
| 145 | } |
| 146 | } finally { |
| 147 | // Mark the write as done, if the queue is non-empty after marking trigger a new write. |
| 148 | scheduled.set(false); |
| 149 | if (!queue.isEmpty()) { |
| 150 | scheduleFlush(); |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | private static class RunnableCommand implements QueuedCommand { |
| 156 | private final Runnable runnable; |