PARQUET-108: Parquet Memory Management in Java

PARQUET-108: Parquet Memory Management in Java.
When Parquet tries to write very large "row groups", it may causes tasks to run out of memory during dynamic partitions when a reducer may have many Parquet files open at a given time.

This patch implements a memory manager to control the total memory size used by writers and balance their memory usage, which ensures that we don't run out of memory due to writing too many row groups within a single JVM.
We have both some logic in static variable and some logic based on MemoryManager being a singleton. We should pick one or the other. The way it is initialized in ParquetOutputFormat, there should no static members that are not final.
Please do the following:
- make ratio a constructor parameter.
- remove memoryPoolRatio and isRatioConfigured and [get|set]MemoryPoolRatio static members
- add some logic in ParquetOutputFormat to instantiate MemoryManager only once and throw an exception if the setting are not the same.