Avoid logging all the blocks on each executor

SparkListenerExecutorsStateChange is refactored into two events:
SparkListenerBlockManagerGained and SparkListenerBlockManagerLost.
Both of these convey the minimum amount of information needed to
reconstruct the storage status (i.e. the BlockManagerId, and in the
registration case, the maximum memory associated with the block
manager).

Further, each executor state change no longer involves logging
storage statuses for ALL executors, when only one has been updated.