Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

  1. the order of selection keys returned from a selector.poll call is undefined. in case the actual implementation uses a fixed order (say by increasing handle id?) and under prolonged memory pressure (so never enough memory to service all requests) this may lead to starvation of sockets that are always at the end of the iteration order. to overcome this the code shuffles the selection keys if memory is low.
  2. a strict pool (which adheres to its max size completely) will cause starvation of large requests under memory pressure (as they would never be able to allocate if there is a stream of small requests). to avoid this the pool implementation will allocate the requested amount of memory if it has any memory available (so if pool has 1 free byte and 1 MB is requested, 1MB will be returned and the number of available bytes in the pool will be negative). this means the actual bound on number of bytes outstanding is queued.max.bytes + socket.request.max.bytes - 1(socket.request.max.bytes representing the largest single request possible)
  3. if there is no memory available at all in Selector.poll() the select() call will return immediately with read-ready channels that we cannot service (because no memory available). this may cause the SocketServer.Processor.run() call (which calls into poll) to go into a tight loop where no progress can be made. it is my (Radai) opinion that in such a scenario there will very likely be progress to be made elsewhere in run() (for example processCompletedSends() - presumably memory is tight because a lot of requests are executing, some of them are very likely done). to avoid the tight loop code has been written to mute all channels when no memory is available (so the select() call will block for a while waiting for other things) and unmute them if/when memory becomes available in a future call to poll(). this code is available in a separate branch. issues with this implementation:
    1. when memory is unavailable channels will be muted until the next call to poll(). if no other channel activity is present except reads this means a 300ms wait at least (thats the current time a poll() call is set to wait)
    2. every such mute/unmute cycle (in response to memory becoming unavailable/available accordingly) is O(#channels), which seems excessive.
    perhaps a better alternative would be to have reads (as opposed to connects, disconnects and writes) be done by dedicated threads. such threads could actually block waiting for memory (something that currently SocketServer.Processor cannot do as it has more responsibilities beyond reads)

...