commitAndRunReadAction from a progress should not hang forever (IDEA-173613)

Signed-off-by: peter <peter@jetbrains.com>
This commit is contained in:
peter
2017-06-02 19:47:44 +02:00
parent 3ac9eea8bb
commit 25d1b0acb6
2 changed files with 40 additions and 6 deletions
@@ -506,8 +506,8 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
});
if (executed) break;
final Semaphore semaphore = new Semaphore();
semaphore.down();
TransactionId contextTransaction = TransactionGuard.getInstance().getContextTransaction();
Semaphore semaphore = new Semaphore(1);
application.invokeLater(() -> {
if (myProject.isDisposed()) {
// committedness doesn't matter anymore; give clients a chance to do checkCanceled
@@ -515,7 +515,7 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
return;
}
performWhenAllCommitted(() -> semaphore.up());
performWhenAllCommitted(() -> semaphore.up(), contextTransaction);
}, ModalityState.any());
semaphore.waitFor();
}
@@ -528,6 +528,10 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
*/
@Override
public boolean performWhenAllCommitted(@NotNull final Runnable action) {
return performWhenAllCommitted(action, TransactionGuard.getInstance().getContextTransaction());
}
private boolean performWhenAllCommitted(@NotNull Runnable action, @Nullable TransactionId context) {
ApplicationManager.getApplication().assertIsDispatchThread();
checkWeAreOutsideAfterCommitHandler();
@@ -543,13 +547,12 @@ public abstract class PsiDocumentManagerBase extends PsiDocumentManager implemen
}
actions.add(action);
TransactionId current = TransactionGuard.getInstance().getContextTransaction();
if (current != ModalityState.NON_MODAL) {
if (context != null) {
// re-add all uncommitted documents into the queue with this new modality
// because this client obviously expects them to commit even inside modal dialog
for (Document document : myUncommittedDocuments) {
myDocumentCommitProcessor.commitAsynchronously(myProject, document,
"re-added with modality "+current+" because performWhenAllCommitted("+current+") was called", current);
"re-added with context "+context+" because performWhenAllCommitted("+context+") was called", context);
}
}
return false;
@@ -37,6 +37,10 @@ import com.intellij.openapi.fileEditor.FileEditorManager;
import com.intellij.openapi.fileEditor.OpenFileDescriptor;
import com.intellij.openapi.fileTypes.PlainTextLanguage;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.progress.ProgressIndicator;
import com.intellij.openapi.progress.ProgressManager;
import com.intellij.openapi.progress.Task;
import com.intellij.openapi.progress.util.ProgressWindow;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.project.ex.ProjectManagerEx;
import com.intellij.openapi.ui.DialogWrapper;
@@ -793,6 +797,33 @@ public class PsiDocumentManagerImplTest extends PlatformTestCase {
assertEquals(PlainTextLanguage.INSTANCE, file2.getLanguage());
}
public void testAsyncCommitHappensInProgressStartedFromTransaction() throws IOException {
PsiFile file = getPsiManager().findFile(getVirtualFile(createTempFile("X.txt", "")));
Document document = file.getViewProvider().getDocument();
Semaphore semaphore = new Semaphore(1);
TransactionGuard.submitTransaction(getTestRootDisposable(), () -> {
WriteCommandAction.runWriteCommandAction(myProject, () -> {
document.insertString(0, "x");
ProgressManager.getInstance().runProcessWithProgressAsynchronously(new Task.Backgroundable(myProject, "Title", false) {
@Override
public void run(@NotNull ProgressIndicator indicator) {
getPsiDocumentManager().commitAndRunReadAction(() -> semaphore.up());
}
}, new ProgressWindow(false, myProject));
});
});
int iteration = 0;
while (!semaphore.waitFor(10)) {
UIUtil.dispatchAllInvocationEvents();
if (++iteration > 3000) {
printThreadDump();
fail("Couldn't wait for commit");
}
}
}
private static void assertLargeFileContentLimited(@NotNull String content, @NotNull VirtualFile vFile, @NotNull Document document) {
Charset charset = EncodingManager.getInstance().getEncoding(vFile, false);
float bytesPerChar = charset == null ? 2 : charset.newEncoder().averageBytesPerChar();