From d1cf540decc930d49d5e63c39aad35bd35cad92c Mon Sep 17 00:00:00 2001 From: Kirill Likhodedov Date: Fri, 18 May 2018 23:02:49 +0300 Subject: [PATCH] vcs: fix atomicity of getting patched revision content volatile wasn't protecting from multiple getContent() invocations. --- .../patch/LazyPatchContentRevision.java | 58 ++++++++++++------- 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/LazyPatchContentRevision.java b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/LazyPatchContentRevision.java index b8c302ee9b5e..904ff6048c90 100644 --- a/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/LazyPatchContentRevision.java +++ b/platform/vcs-impl/src/com/intellij/openapi/vcs/changes/patch/LazyPatchContentRevision.java @@ -20,50 +20,56 @@ import com.intellij.openapi.diff.impl.patch.TextFilePatch; import com.intellij.openapi.diff.impl.patch.apply.GenericPatchApplier; import com.intellij.openapi.editor.Document; import com.intellij.openapi.fileEditor.FileDocumentManager; +import com.intellij.openapi.util.AtomicNotNullLazyValue; import com.intellij.openapi.vcs.FilePath; import com.intellij.openapi.vcs.changes.ContentRevision; import com.intellij.openapi.vcs.history.VcsRevisionNumber; import com.intellij.openapi.vfs.VirtualFile; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class LazyPatchContentRevision implements ContentRevision { - private volatile String myContent; private final VirtualFile myVf; private final FilePath myNewFilePath; private final String myRevision; private final TextFilePatch myPatch; - private volatile boolean myPatchApplyFailed; + + private final AtomicNotNullLazyValue myData; public LazyPatchContentRevision(final VirtualFile vf, final FilePath newFilePath, final String revision, final TextFilePatch patch) { myVf = vf; myNewFilePath = newFilePath; myRevision = revision; myPatch = patch; + + myData = AtomicNotNullLazyValue.createValue(() -> loadContent()); } - public String getContent() { - if (myContent == null) { - final String localContext = ReadAction.compute(() -> { - final Document doc = FileDocumentManager.getInstance().getDocument(myVf); - return doc == null ? null : doc.getText(); - }); - if (localContext == null) { - myPatchApplyFailed = true; - return null; - } - - GenericPatchApplier.AppliedPatch appliedPatch = GenericPatchApplier.apply(localContext, myPatch.getHunks()); - if (appliedPatch != null) { - myContent = appliedPatch.patchedText; - } else { - myPatchApplyFailed = true; - } + private Data loadContent() { + String localContext = ReadAction.compute(() -> { + Document doc = FileDocumentManager.getInstance().getDocument(myVf); + return doc == null ? null : doc.getText(); + }); + if (localContext == null) { + return new Data(null, true); } - return myContent; + + GenericPatchApplier.AppliedPatch appliedPatch = GenericPatchApplier.apply(localContext, myPatch.getHunks()); + if (appliedPatch != null) { + return new Data(appliedPatch.patchedText, false); + } + else { + return new Data(null, true); + } + } + + @Nullable + public String getContent() { + return myData.getValue().content; } public boolean isPatchApplyFailed() { - return myPatchApplyFailed; + return myData.getValue().patchApplyFailed; } @NotNull @@ -83,4 +89,14 @@ public class LazyPatchContentRevision implements ContentRevision { } }; } + + private static class Data { + @Nullable public final String content; + public final boolean patchApplyFailed; + + public Data(@Nullable String content, boolean patchApplyFailed) { + this.content = content; + this.patchApplyFailed = patchApplyFailed; + } + } }