Flush join indexes when memory is constrained

Add a separate limit for index memory usage that is independent of the task
memory limit. This removes the risk of the flushable memory usage causing
another operator to run out of memory.

Loader will attempt to load new data and add to existing cache.  If that
fails, it flushes the cache and tries again.  If that fails, it loads only
the single required request for the loader thread.
we should probably skip doing this if the previous requests was just a singleton list of our own request. This will likely happen in quite a few cases.