MODE-2043 Mechanism for programmatic steps during upgrades 

**_NOT READY FOR MERGING. Ready for initial review, but tests need to be added. It does work in clustered and non-clustered cases, both when the repository needs and does not need to be upgraded. However, these checks were done with logging enabled and by changing the code to force upgrading. Unit/integration tests need to be designed to test this functionality without such hacks or reliance upon logging._**

When ModeShapde code is upgraded, sometimes it is necessary to also upgrade stored content. For example, an upgrade might change a built-in node type and change the code that uses it, but the software cannot change any persisted nodes that use that old node type to reflect the new state. There are of course other examples.

This commit adds a new small system for performing upgrades. Each time a repository is started up, internal repository state is examined to learn which (if any) of the known upgrade steps (operations) need to be applied. If any are needed, those steps are applied and the repository state changed to reflect this. This is done efficiently (since most starts are done with the same software version) and in such a way that only one process in a cluster (the first to recognize the need to run upgrade steps) will perform such steps while additional processes wait (for a maximum of 10 minutes) until the first process completes the upgrade.

Internal inner classes are used to implement each upgrade steps, and upgrade steps are identified by a simple integer identifier. The steps are intended to be sequential applied, and thus a monotonically increasing integer ID is used. This highest ID of the upgrade step last applied to the repository is stored inside the repository state. If a new upgrade step is needed for a release, a new inner class is added and the existing ones kept as-is. This makes it easy to apply all of the upgrade steps needed to bring the repository content from being compatible with an earlier release to a state that is compatible with the most recent release. This ID mechanism is simple and completely independent of version numbers.

It is also very easy and quick to determine upon repository startup whether any upgrade steps need be performed. Most of the time the software version does not change and the repository's last-applied upgrade ID matches the highest upgrade step known to that software. Thus, a simple integer comparison is all that is required to completely bypass the upgrade process in clustered and non-clustered topologies.

Note that all newly-created repositories are pre-initialized with the highest available upgrade step ID, so that no upgrade operation never needs to be performed on a new repository.