When a StarTeam Server is MPX-enabled, information about changes to the repository is broadcast in an encrypted format through a publish/subscribe channel to MPX-enabled StarTeam clients.
The StarTeam SDK uses the information broadcast in MPX messages to keep its internal caches up-to-date. This allows refresh operations to be serviced with very little overhead. For applications that perform frequent refresh operations, the resulting performance benefits are significant.
Instant refresh is described in detail in the following subsections:
In general, the SDK's APIs are MPX-enabled. Thus, when an SDK application is MPX-enabled, it automatically benefits from instant refresh. For example, consider the following code fragment:
// Populate all Files in the View. f = view.getRootFolder(); f.populateNow(typename, null, -1); . . . // Refresh Files to reflect recent changes. f.refreshItems(typename, null, -1); |
The call to refreshes all Items of the given type to reflect recent changes to the repository. In a non-MPX application, this could be a very expensive operation. In an MPX-enabled application, the refresh operation is nearly instantaneous.
An SDK object represents a snapshot of some piece of information from the StarTeam repository, as of some point in time. When that information is changed in the repository, the changes are never visible to the SDK application until they are explicitly requested via a operation. From the SDK's point of view, "instant refresh" does not mean that changes are visible as soon as they are made on the server; it simply means that when MPX is enabled, refresh operations can be performed very efficiently.
In the common case where MPX is enabled and nothing has changed, is optimized to be as close to a no-op as possible. One implication is that operations do not create new objects when there are no changes required. In fact, operations always modify existing objects in place whenever possible. This behavior is now a documented part of the refresh APIs, and is true even if MPX is not enabled.
Each of the SDK's methods has a corresponding method. returns true if the method called at the same instant in time might have resulted in changes to the objects in question.
For example:
bChanges = f.isRefreshItemsRequired(typename, null, -1); |
This determines whether or not it may be necessary to refresh any items of the given type to reflect recent changes to the repository.
may return false positives; that is, it may return true in some cases where no relevant changes were made to the repository. For example, may return true when a new item is added, even though the new item is not visible in the current security context. If MPX is not enabled, always returns true.
is not intended to be used merely to avoid unnecessary calls to . For example:
// An inefficient use of isRefreshRequired().
if (f.isRefreshItemsRequired(typename, null, -1)) {
f.refreshItems(typename, null, -1);
}
|
This is actually slower than simply calling by itself. On the other hand, is very useful in the following situation:
// Proper use of isRefreshRequired().
if (f.isRefreshItemsRequired(typename, null, -1)) {
f.refreshItems(typename, null, -1);
doSomethingExpensive();
}
|
Here, is used to avoid unnecessary calls to an expensive application-specific method that must be called whenever the item list changes.
The SDK's methods free up objects in various internal caches. If, for example, the properties of an Item are discarded, the next reference to any property of the Item will cause all of its properties to be re-fetched from the server. is called by an application to help control memory usage.
It is not uncommon to see an SDK application do the following:
f.discardItems(typename, -1); f.populateNow(typename, null, -1); |
when what was really intended is:
f.refreshItems(typename, null, -1); |
Although this was never strictly correct, it really didn't result in any unexpected behavior in older, non-MPX aware versions of the SDK.
In an MPX-aware version of the SDK, these two code fragments have very different behaviors. always causes the relevant items to be removed from the SDK's internal cache. Thus, the subsequent call will always require that the Item data be re-fetched from the server, even when MPX is enabled.
An MPX-enabled operation, on the other hand, will only issue server commands in a relatively small set of situations. In addition, when a server command is required, it will usually fetch a much smaller set of data than a full refresh would have required.
For these reasons, it is important to ensure that MPX-enabled applications use for memory management only, and not where would have been more appropriate.
operations always modify existing objects in place whenever possible. This behavior is now a documented part of the refresh APIs.
In older, non-MPX aware versions of the SDK, operations always created new objects, even when no changes were required. Applications that incorrectly rely on this behavior will not work when upgrading to an MPX-aware version of the SDK.
For example, consider the following code fragment:
// Find a specific item.
item1 = view.findItem(type, id);
// Refresh the items.
// Any changes to item1 will be made in place.
f = view.getRootFolder();
f.refreshItems(type.getName(), null, -1);
// Find the item again.
// item1 and item2 are the same object!
item2 = view.findItem(type, id);
// Call application-specific code to
// compare the two items.
if (myItemHasChanged(item1, item2)) {
// We should never get here, because
// the two items are the same physical object.
}
|
This code fragment makes an incorrect assumption about the behavior of , and will not work when running against an MPX-aware version of the SDK. In order to compare the state of an item before and after a operation, an application should make a copy of the item before the refresh, and then compare the copy to the original after the refresh. The SDK provides and methods to facilitate this. For example:
// Find a specific item.
item1 = view.findItem(type, id);
// Make a copy of the item in its current state.
item2 = item1.copy();
// Refresh the items.
// Any changes to item1 will be made in place.
f = view.getRootFolder();
f.refreshItems(type.getName(), null, -1);
// Compare the two items.
if (!item1.isEqualTo(item2)) {
// We'll get here if the item changed
// during the refresh operation.
}
|
The method always ensures that the properties of the item are fully populated before making the copy. compares all the properties of the item.
|
|