private static boolean handleClientLocalVersionUpdate()

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;
    }