in source/com.microsoft.tfs.core/src/com/microsoft/tfs/core/clients/versioncontrol/internal/localworkspace/LocalDataAccessLayer.java [4189:4355]
private static boolean handleClientLocalVersionUpdate(
final LocalWorkspaceProperties wp,
final WorkspaceVersionTable lv,
final LocalPendingChangesTable pc,
final ClientLocalVersionUpdate update,
final boolean setFileTimeToCheckin,
final Set<byte[]> displacedBaselines) {
Check.isTrue(update.isFullyPopulated(setFileTimeToCheckin), "update.isFullyPopulated(setFileTimeToCheckin)"); //$NON-NLS-1$
final WorkspaceLocalItem lvExisting = lv.getByServerItem(update.getSourceServerItem(), update.isCommitted());
boolean updateMissingBaseline = false;
if (update.getTargetLocalItem() != null && update.getTargetLocalItem().length() > 0) {
// If we are calling ULV for an uncommitted slot in the table,
// ensure that we actually
// have a pending change row. This is for the case where you are
// undoing both a parent
// rename and a child add simultaneously.
if (!update.isCommitted() && null == pc.getByTargetServerItem(update.getSourceServerItem())) {
return updateMissingBaseline;
}
// Displace the baseline (if it exists) for the local version entry
// which collides with us on local path.
final WorkspaceLocalItem lvLocalPathCollision = lv.getByLocalItem(update.getTargetLocalItem());
// If the entry which collides with us on local path is the same
// entry that collides with us
// on the primary key (ServerItem, IsCommitted), then there's no
// work to do. But if we have
// no collision on primary key at all, or the colliding entries are
// different, then we need
// displace the local path collision's entry.
if (null != lvLocalPathCollision && (null == lvExisting || lvLocalPathCollision != lvExisting)) {
if (null != lvLocalPathCollision.getBaselineFileGUID()) {
displacedBaselines.add(lvLocalPathCollision.getBaselineFileGUID());
}
lv.removeByServerItem(lvLocalPathCollision.getServerItem(), lvLocalPathCollision.isCommitted(), false);
}
final WorkspaceLocalItem lvEntry = new WorkspaceLocalItem();
lvEntry.setServerItem(update.getSourceServerItem());
lvEntry.setVersion(update.getVersionLocal());
lvEntry.setLocalItem(update.getTargetLocalItem());
lvEntry.setItemID(update.getItemID());
lvEntry.setHashValue(update.getBaselineHashValue());
lvEntry.setEncoding(update.getEncoding());
lvEntry.setBaselineFileGUID(update.getBaselineFileGUID());
lvEntry.setPendingReconcile(true);
lvEntry.setLength(update.getBaselineFileLength());
lvEntry.setCheckinDate(update.getVersionLocalDate());
lvEntry.setPropertyValues(update.getPropertyValues());
if (null != lvExisting && lvExisting.hasBaselineFileGUID()) {
if (!lvEntry.hasBaselineFileGUID()
&& -1 != lvExisting.getLength()
&& lvExisting.getLength() == lvEntry.getLength()
&& lvExisting.hasHashValue()
&& lvEntry.hasHashValue()
&& Arrays.equals(lvExisting.getHashValue(), lvEntry.getHashValue())) {
// The update request did not contain a baseline file GUID,
// but the existing entry
// has a baseline and the metadata about the baseline shows
// it is identical. We'll
// preserve the existing baseline in the new local version
// entry.
lvEntry.setBaselineFileGUID(lvExisting.getBaselineFileGUID());
} else if (!lvEntry.hasBaselineFileGUID()
|| !Arrays.equals(lvExisting.getBaselineFileGUID(), lvEntry.getBaselineFileGUID())) {
// The update request contains a baseline file GUID and it's
// different from the
// one on the current local version entry.
wp.deleteBaseline(lvExisting.getBaselineFileGUID());
}
}
if (VersionControlConstants.ENCODING_FOLDER != update.getEncoding()
&& update.getTargetLocalItem() != null
&& update.getTargetLocalItem().length() > 0) {
final File file = new File(update.getTargetLocalItem());
if (-1 != update.getLastModifiedDate()) {
// The caller has provided an explicit last modified date
// value.
lvEntry.setLastModifiedTime(update.getLastModifiedDate());
} else if (file.exists()) {
// Fetch the last modified time from the disk.
final FileSystemAttributes attrs = FileSystemUtils.getInstance().getAttributes(file);
if (attrs != null && attrs.getModificationTime() != null) {
lvEntry.setLastModifiedTime(attrs.getModificationTime().getWindowsFilesystemTime());
}
}
}
if (null != lvEntry.getBaselineFileGUID()) {
// We might have re-added a reference to a displaced baseline.
// If we did, remove it from the set of displaced baselines.
displacedBaselines.remove(lvEntry.getBaselineFileGUID());
} else if (VersionControlConstants.ENCODING_FOLDER != lvEntry.getEncoding() &&
// If the item is uncommitted, we don't need to download a
// baseline
// for it, unless EnsureUpdatesFullyPopulated has already
// stuffed a
// download URL into the update for us (for example on a branch,
// edit)
(0 != lvEntry.getVersion() || null != update.getDownloadURL())) {
// We're about to save out a local version entry with no
// baseline file GUID!
// Instead, create a GUID and we'll put this
// ClientLocalVersionUpdate in the return value of this method.
// The caller will be responsible for downloading the baseline
// content.
update.generateNewBaselineFileGUID();
lvEntry.setBaselineFileGUID(update.getBaselineFileGUID());
updateMissingBaseline = true;
}
lv.add(lvEntry);
} else if (null != lvExisting) {
// We have an existing local version entry for this item, and we're
// trying to remove it from the table.
if (update.getKeepLocalVersionEntryOnDelete()) {
lv.markAsDeleted(lvExisting.getServerItem(), lvExisting.isCommitted(), true);
} else {
lv.removeByServerItem(lvExisting.getServerItem(), lvExisting.isCommitted(), true);
if (null != lvExisting.getBaselineFileGUID()) {
wp.deleteBaseline(lvExisting.getBaselineFileGUID());
}
}
}
// Logic in support of partial scanner correctness. If a caller is using
// UpdateLocalVersion and has provided a WorkspaceLock to the
// transaction (as opposed to having the transaction create its own
// lock) then we assume that the on-disk operations are being performed
// under the protection of that lock (as in ProcessGetOperations). This
// means that asynchronous scans are not occurring in response to these
// actions while their local version updates are still outstanding. If
// the opposite is the case -- that there is no lock and
// UpdateLocalVersion is being used directly (i.e. an
// UpdateLocalVersionQueue that you just new up and start using), then
// we need to send the paths that we are touching to the scanner.
if (LocalWorkspaceTransaction.getCurrent().ownsWorkspaceLock()) {
if (null != lvExisting
&& null != lvExisting.getLocalItem()
&& !LocalPath.equals(lvExisting.getLocalItem(), update.getTargetLocalItem())) {
LocalWorkspaceTransaction.getCurrent().getWorkspace().getWorkspaceWatcher().markPathChanged(
lvExisting.getLocalItem());
}
if (null != update.getTargetLocalItem()
&& (null == lvExisting
|| null == lvExisting.getLocalItem()
|| !LocalPath.equals(lvExisting.getLocalItem(), update.getTargetLocalItem()))) {
LocalWorkspaceTransaction.getCurrent().getWorkspace().getWorkspaceWatcher().markPathChanged(
update.getTargetLocalItem());
}
}
return updateMissingBaseline;
}