mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
do everything possible to cache the unchanged file content to revert in p4 offline mode (IDEA-79768)
This commit is contained in:
@@ -121,6 +121,7 @@ public class ContentRevisionCache {
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getOrLoadAsString(Project project,
|
||||
FilePath file,
|
||||
VcsRevisionNumber number,
|
||||
@@ -135,7 +136,7 @@ public class ContentRevisionCache {
|
||||
return CharsetToolkit.bytesToString(bytes, charset);
|
||||
}
|
||||
|
||||
private static String bytesToString(FilePath path, byte[] bytes) {
|
||||
private static String bytesToString(FilePath path, @NotNull byte[] bytes) {
|
||||
Charset charset = null;
|
||||
if (path.getVirtualFile() != null) {
|
||||
charset = path.getVirtualFile().getCharset();
|
||||
@@ -183,10 +184,13 @@ public class ContentRevisionCache {
|
||||
return bytes;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static String getOrLoadAsString(final Project project, FilePath path, VcsRevisionNumber number, @NotNull VcsKey vcsKey,
|
||||
@NotNull UniqueType type, final Throwable2Computable<byte[], VcsException, IOException> loader)
|
||||
throws VcsException, IOException {
|
||||
byte[] bytes = getOrLoadAsBytes(project, path, number, vcsKey, type, loader);
|
||||
if (bytes == null) return null;
|
||||
|
||||
return bytesToString(path, bytes);
|
||||
}
|
||||
|
||||
|
||||
@@ -47,6 +47,7 @@ import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.ui.EditorNotifications;
|
||||
import com.intellij.util.*;
|
||||
import com.intellij.util.concurrency.Semaphore;
|
||||
import com.intellij.util.containers.MultiMap;
|
||||
import com.intellij.util.continuation.ContinuationPause;
|
||||
import com.intellij.util.messages.Topic;
|
||||
@@ -447,6 +448,11 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for (VcsDirtyScope scope : scopes) {
|
||||
updateLastUnchangedContents(scope);
|
||||
}
|
||||
|
||||
myChangesViewManager.scheduleRefresh();
|
||||
}
|
||||
catch (DisposedException e) {
|
||||
@@ -620,6 +626,55 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
|
||||
}
|
||||
}
|
||||
|
||||
private void updateLastUnchangedContents(VcsDirtyScope scope) {
|
||||
scope.iterateExistingInsideScope(new Processor<VirtualFile>() {
|
||||
@Override
|
||||
public boolean process(VirtualFile file) {
|
||||
if (!file.isDirectory() && getStatus(file) == FileStatus.NOT_CHANGED) {
|
||||
LastUnchangedContentTracker.updateLastUnchangedContent(file);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void collectUnchangedFileContents(@Nullable ProgressIndicator indicator) {
|
||||
final ProjectLevelVcsManager vcsManager = ProjectLevelVcsManager.getInstance(myProject);
|
||||
for (VcsDirectoryMapping mapping : vcsManager.getDirectoryMappings()) {
|
||||
final AbstractVcs vcs = vcsManager.findVcsByName(mapping.getVcs());
|
||||
final VirtualFile file = LocalFileSystem.getInstance().findFileByPath(mapping.getDirectory());
|
||||
if (vcs != null && file != null) {
|
||||
if (indicator != null) {
|
||||
indicator.setText(mapping.getDirectory());
|
||||
}
|
||||
|
||||
final VcsDirtyScopeImpl scope = new VcsDirtyScopeImpl(vcs, myProject);
|
||||
scope.addDirtyDirRecursively(new FilePathImpl(file));
|
||||
updateLastUnchangedContents(scope);
|
||||
}
|
||||
}
|
||||
|
||||
for (LocalChangeList list : getChangeListsCopy()) {
|
||||
for (Change change : list.getChanges()) {
|
||||
final VirtualFile file = change.getVirtualFile();
|
||||
final ContentRevision before = change.getBeforeRevision();
|
||||
if (file != null && before != null && !LastUnchangedContentTracker.hasSavedContent(file)) {
|
||||
try {
|
||||
final String content = before.getContent();
|
||||
if (content != null) {
|
||||
LastUnchangedContentTracker.forceSavedContent(file, content);
|
||||
}
|
||||
}
|
||||
catch (VcsException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void checkIfDisposed() {
|
||||
if (myUpdater.isStopped()) throw new DisposedException();
|
||||
}
|
||||
@@ -1292,6 +1347,20 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
|
||||
@TestOnly
|
||||
public void waitUntilRefreshed() {
|
||||
myUpdater.waitUntilRefreshed();
|
||||
waitUpdateAlarm();
|
||||
}
|
||||
|
||||
// this is for perforce tests to ensure that LastSuccessfulUpdateTracker receives the event it needs
|
||||
private static void waitUpdateAlarm() {
|
||||
final Semaphore semaphore = new Semaphore();
|
||||
semaphore.down();
|
||||
ourUpdateAlarm.execute(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
semaphore.up();
|
||||
}
|
||||
});
|
||||
semaphore.waitFor();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1301,6 +1370,7 @@ public class ChangeListManagerImpl extends ChangeListManagerEx implements Projec
|
||||
final EnsureUpToDateFromNonAWTThread worker = new EnsureUpToDateFromNonAWTThread(myProject);
|
||||
worker.execute();
|
||||
myUpdater.waitUntilRefreshed();
|
||||
waitUpdateAlarm();
|
||||
return worker.isDone();
|
||||
}
|
||||
|
||||
|
||||
@@ -98,29 +98,10 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
|
||||
}
|
||||
|
||||
public void onAfterWorkerSwitch(@NotNull final ChangeListWorker previous) {
|
||||
final boolean somethingChanged = myDelta.step(previous.myIdx, myIdx);
|
||||
checkForMultipleCopiesNotMove();
|
||||
checkForMultipleCopiesNotMove(myDelta.step(previous.myIdx, myIdx));
|
||||
}
|
||||
|
||||
public boolean takeData(@NotNull final ChangeListWorker worker) {
|
||||
myMap.clear();
|
||||
myMap.putAll(worker.myMap);
|
||||
myDefault = worker.myDefault;
|
||||
|
||||
myListsToDisappear.clear();
|
||||
myListsToDisappear.addAll(worker.myListsToDisappear);
|
||||
|
||||
final boolean somethingChanged = myDelta.step(myIdx, worker.myIdx);
|
||||
myIdx = new ChangeListsIndexes(worker.myIdx);
|
||||
checkForMultipleCopiesNotMove();
|
||||
|
||||
myLocallyDeleted.takeFrom(worker.myLocallyDeleted);
|
||||
mySwitchedHolder.takeFrom(worker.mySwitchedHolder);
|
||||
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
private void checkForMultipleCopiesNotMove() {
|
||||
private void checkForMultipleCopiesNotMove(boolean somethingChanged) {
|
||||
final MultiMap<FilePath, Pair<Change, String>> moves = new MultiMap<FilePath, Pair<Change, String>>() {
|
||||
protected Collection<Pair<Change, String>> createCollection() {
|
||||
return new LinkedList<Pair<Change, String>>();
|
||||
@@ -139,7 +120,6 @@ public class ChangeListWorker implements ChangeListsWriteOperations {
|
||||
}
|
||||
}
|
||||
}
|
||||
boolean somethingChanged = false;
|
||||
for (FilePath filePath : moves.keySet()) {
|
||||
final List<Pair<Change, String>> copies = (List<Pair<Change, String>>) moves.get(filePath);
|
||||
if (copies.size() == 1) continue;
|
||||
|
||||
+141
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2000-2012 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.intellij.openapi.vcs.changes;
|
||||
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.vfs.VfsUtil;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.FileAttribute;
|
||||
import com.intellij.openapi.vfs.newvfs.ManagingFS;
|
||||
import com.intellij.openapi.vfs.newvfs.persistent.PersistentFS;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author peter
|
||||
*/
|
||||
public class LastUnchangedContentTracker {
|
||||
private static final Logger LOG = Logger.getInstance("#com.intellij.openapi.vcs.changes.LastUnchangedContentTracker");
|
||||
private static final Key<Long> LAST_TS_KEY = Key.create("LAST_TS_KEY");
|
||||
private static final FileAttribute LAST_TS_ATTR = new FileAttribute("LAST_TS_ATTR", 0, true);
|
||||
private static final FileAttribute ACQUIRED_CONTENT_ATTR = new FileAttribute("ACQUIRED_CONTENT_ATTR", 0, false);
|
||||
|
||||
public static void updateLastUnchangedContent(@NotNull VirtualFile file) {
|
||||
Long lastTs = getLastSavedStamp(file);
|
||||
final long stamp = file.getModificationStamp();
|
||||
if (lastTs != null && stamp == lastTs) {
|
||||
return;
|
||||
}
|
||||
|
||||
Integer oldContentId = getSavedContentId(file);
|
||||
if (oldContentId != null) {
|
||||
getFS().releaseContent(oldContentId);
|
||||
}
|
||||
|
||||
saveContentReference(file, getFS().acquireContent(file));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static byte[] getLastUnchangedContent(@NotNull VirtualFile file) {
|
||||
final Integer id = getSavedContentId(file);
|
||||
try {
|
||||
return id == null ? null : getFS().contentsToByteArray(id);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static PersistentFS getFS() {
|
||||
return (PersistentFS)ManagingFS.getInstance();
|
||||
}
|
||||
|
||||
private static void saveContentReference(VirtualFile file, int contentId) {
|
||||
if (ChangeListManagerImpl.DEBUG) {
|
||||
System.out.println("LastUnchangedContentTracker.saveCurrentContent");
|
||||
try {
|
||||
System.out.println("content = " + VfsUtil.loadText(file));
|
||||
}
|
||||
catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
long stamp = file.getModificationStamp();
|
||||
try {
|
||||
final DataOutputStream contentStream = ACQUIRED_CONTENT_ATTR.writeAttribute(file);
|
||||
contentStream.writeInt(contentId);
|
||||
contentStream.close();
|
||||
|
||||
final DataOutputStream tsStream = LAST_TS_ATTR.writeAttribute(file);
|
||||
tsStream.writeLong(stamp);
|
||||
tsStream.close();
|
||||
|
||||
file.putUserData(LAST_TS_KEY, stamp);
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean hasSavedContent(VirtualFile file) {
|
||||
return getSavedContentId(file) != null;
|
||||
}
|
||||
|
||||
public static void forceSavedContent(VirtualFile file, @NotNull String content) {
|
||||
saveContentReference(file, getFS().storeUnlinkedContent(content.getBytes(file.getCharset())));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Integer getSavedContentId(VirtualFile file) {
|
||||
Integer oldContentId = null;
|
||||
try {
|
||||
final DataInputStream stream = ACQUIRED_CONTENT_ATTR.readAttribute(file);
|
||||
if (stream != null) {
|
||||
oldContentId = stream.readInt();
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
return oldContentId;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static Long getLastSavedStamp(VirtualFile file) {
|
||||
Long l = file.getUserData(LAST_TS_KEY);
|
||||
if (l == null) {
|
||||
try {
|
||||
final DataInputStream stream = LAST_TS_ATTR.readAttribute(file);
|
||||
if (stream != null) {
|
||||
l = stream.readLong();
|
||||
stream.close();
|
||||
}
|
||||
}
|
||||
catch (IOException e) {
|
||||
LOG.info(e);
|
||||
}
|
||||
}
|
||||
return l;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user