Implements a memory manager that keeps a global context of how many ORC writers there are and manages the memory between them. For use cases with dynamic partitions, it is easy to end up with many writers in the same task. By managing the size of each allocation, we try to cut down the size of each
| 40 | * invocations are triggered from the same thread. |
| 41 | */ |
| 42 | public class MemoryManagerImpl implements MemoryManager { |
| 43 | |
| 44 | private final long totalMemoryPool; |
| 45 | private final Map<Path, WriterInfo> writerList = new HashMap<>(); |
| 46 | private final AtomicLong totalAllocation = new AtomicLong(0); |
| 47 | |
| 48 | private static class WriterInfo { |
| 49 | long allocation; |
| 50 | WriterInfo(long allocation) { |
| 51 | this.allocation = allocation; |
| 52 | } |
| 53 | } |
| 54 | |
| 55 | /** |
| 56 | * Create the memory manager. |
| 57 | * @param conf use the configuration to find the maximum size of the memory |
| 58 | * pool. |
| 59 | */ |
| 60 | public MemoryManagerImpl(Configuration conf) { |
| 61 | this(Math.round(ManagementFactory.getMemoryMXBean(). |
| 62 | getHeapMemoryUsage().getMax() * OrcConf.MEMORY_POOL.getDouble(conf))); |
| 63 | } |
| 64 | |
| 65 | /** |
| 66 | * Create the memory manager |
| 67 | * @param poolSize the size of memory to use |
| 68 | */ |
| 69 | public MemoryManagerImpl(long poolSize) { |
| 70 | totalMemoryPool = poolSize; |
| 71 | } |
| 72 | |
| 73 | /** |
| 74 | * Add a new writer's memory allocation to the pool. We use the path |
| 75 | * as a unique key to ensure that we don't get duplicates. |
| 76 | * @param path the file that is being written |
| 77 | * @param requestedAllocation the requested buffer size |
| 78 | */ |
| 79 | @Override |
| 80 | public synchronized void addWriter(Path path, long requestedAllocation, |
| 81 | Callback callback) throws IOException { |
| 82 | WriterInfo oldVal = writerList.get(path); |
| 83 | // this should always be null, but we handle the case where the memory |
| 84 | // manager wasn't told that a writer wasn't still in use and the task |
| 85 | // starts writing to the same path. |
| 86 | if (oldVal == null) { |
| 87 | oldVal = new WriterInfo(requestedAllocation); |
| 88 | writerList.put(path, oldVal); |
| 89 | totalAllocation.addAndGet(requestedAllocation); |
| 90 | } else { |
| 91 | // handle a new writer that is writing to the same path |
| 92 | totalAllocation.addAndGet(requestedAllocation - oldVal.allocation); |
| 93 | oldVal.allocation = requestedAllocation; |
| 94 | } |
| 95 | } |
| 96 | |
| 97 | /** |
| 98 | * Remove the given writer from the pool. |
| 99 | * @param path the file that has been closed |
nothing calls this directly
no outgoing calls
no test coverage detected