MC2 key classes
Last updated at 2:53 pm UTC on 24 June 2007
By Colin Putney:
I'll take a stab at that. As Avi mentioned, design of MC2 follows from the idea that revision history would be attached to individual methods, rather than entire packages.
These play the same role as MethodReferences. They are references to specific parts of a Smalltalk program. They're more fine-grained than Definitions in MC1 - you'll see separate elements for each instance variable, for example, so that they can referred to directly, rather than by implication in a class reference.
A variant describes the state of a particular element. That state might be "not present in the image," in the case of a RemovalVariant, or the properties of the element, in the case of a DefinitionVariant. One of the things that we noticed with MC1 is that the exact components of a definition are most likely to change, so we encode them using a PropertyDictionary instead of dedicated objects.
This is a facade for the class structures of the image. It presents a protocol for querying the state of the image or modifying it using variants.
This is the central class of MC2. It represents the state of an element at a particular point in the evolution of the system. It combines a variant with list of versions that have come before it. Each version has what we call a Hashstamp - combination of SHA1 hash and timestamp which uniquely identifies the version. A version's ancestry is a set of hashstamps specifying which versions are part of this version's history.
A slice is sub-set of the elements in the image. It's main responsibility is to define which elements are part of the slice and which are not. Slices can be based on any set of criteria - PackageInfo, ChangeSets, an explicit collection, whatever. Slices can overlap. Elements can belong to more than one slice at the same time.
This is a set of Versions which "go together." A snapshot is equivalent to an MCVersion in MC1. It's the unit at which code is moved between images.
I'm not terribly happy with this name, but I can't think of a better one. It keeps track of the state of the image with respect to versioning. It knows, for example, which versions image is based on, and can perform tasks like creating new versions based on the state of the image, or loading existing versions into the image.
Repositories are similar to those in MC1, but have a different protocol and different performance characteristics. Conceptually, repositories are dictionaries, mapping hashstamps to versions or snapshots. This makes for a very fine-grained protocol - versions are loaded individually. That makes directory or HTTP repositories impractical, since loading a slice for a medium-size package would involve opening and reading hundreds of files. (A snapshot of OB, for example runs at over 600 versions).
A Memo isn't strictly needed for MC2's versioning model. Instead it's a performance enhancement for a very common case that arises when dealing with repositories. The problem is this: Imagine that you're going to update your image. You open a repository and get a list of the snapshots it contains. You browse this list until you find the snapshot you want, and then load it into your image.
Now, getting a list of snapshots from a repository is a pretty straightforward operation, but it doesn't give much information. All the metadata for the snapshot is stored separately. So building the list of snapshots to display to the user would involve two round trips to the repository - one to get the list of snapshots, and another to get all the metadata. A memo is just a bundling of that metadata in a form that's convenient for displaying to the user. By asking the repository for that information directly, the UI enables to repository to gather it in a way that's efficient for the repository implementation.