Add an effective storage level interface to BlockManager

There is currently no mechanism to specify a different put behavior
in BlockManager other than using a mock storage level and restoring
the original one specified by the user later. The refactor in this
commit allows BlockManager to take in both the original level and
an optional effective level. The latter is the level BlockManager
will actually use to handle the block.