[SPARK-3795] Heuristics for dynamically scaling executors

This is part of a bigger effort to provide elastic scaling of executors within a Spark application ([SPARK-3174](https://issues.apache.org/jira/browse/SPARK-3174)). This PR does not provide any functionality by itself; it is a skeleton that is missing a mechanism to be added later in [SPARK-3822](https://issues.apache.org/jira/browse/SPARK-3822).

Comments and feedback are most welcome. For those of you reviewing this in detail, I highly recommend doing it through your favorite IDE instead of through the diff here.
I have some different proposals for these names here - ones that are more descriptive. Also, I think we tend to avoid having units in the name btw (e.g. "XSeconds") for other configs. It is a little concerning to me how hard it is to explain these configs... but maybe there is a simpler way. Also, did we ever consider having only a single interval here instead of two different ones?

```
// Number of seconds of backlog at which to add executors resources
spark.dynamicAllocation.backlogTimeout
// Timeout applied to continued backlog (i.e. once the initial backlogTimeout has been surpassed)
spark.dynamicAllocation.sustainedBacklogTimeout

// Length of time after which to remove idle executors
spark.dynamicAllocation.idleExecutorTimeout
```