mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-170230 Message "Unable to save settings: Failed to save settings. Please restart IntelliJ IDEA" when leaving the IDEA window of a big project
Add LargeFileWriteRequestor marker interface to not assert file size.
This commit is contained in:
@@ -28,6 +28,7 @@ import com.intellij.openapi.diagnostic.debug
|
||||
import com.intellij.openapi.fileEditor.impl.LoadTextUtil
|
||||
import com.intellij.openapi.util.JDOMUtil
|
||||
import com.intellij.openapi.util.io.BufferExposingByteArrayOutputStream
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.openapi.vfs.LocalFileSystem
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.util.ArrayUtil
|
||||
@@ -196,7 +197,7 @@ fun writeFile(file: Path?, requestor: Any, virtualFile: VirtualFile?, element: E
|
||||
virtualFile!!
|
||||
}
|
||||
|
||||
if (LOG.isDebugEnabled || ApplicationManager.getApplication().isUnitTestMode) {
|
||||
if ((LOG.isDebugEnabled || ApplicationManager.getApplication ().isUnitTestMode) && result.length < FileUtilRt.LARGE_FOR_CONTENT_LOADING) {
|
||||
val content = element.toBufferExposingByteArray(lineSeparator.separatorString)
|
||||
if (isEqualContent(result, lineSeparator, content, prependXmlProlog)) {
|
||||
throw IllegalStateException("Content equals, but it must be handled not on this level: ${result.name}")
|
||||
|
||||
@@ -18,13 +18,14 @@ package com.intellij.configurationStore
|
||||
import com.intellij.openapi.components.StateStorage
|
||||
import com.intellij.openapi.util.JDOMExternalizable
|
||||
import com.intellij.openapi.util.WriteExternalException
|
||||
import com.intellij.openapi.vfs.LargeFileWriteRequestor
|
||||
import com.intellij.openapi.vfs.SafeWriteRequestor
|
||||
import com.intellij.reference.SoftReference
|
||||
import com.intellij.util.xmlb.SkipDefaultsSerializationFilter
|
||||
import com.intellij.util.xmlb.XmlSerializer
|
||||
import org.jdom.Element
|
||||
|
||||
abstract class SaveSessionBase : StateStorage.SaveSession, StateStorage.ExternalizationSession, SafeWriteRequestor {
|
||||
abstract class SaveSessionBase : StateStorage.SaveSession, StateStorage.ExternalizationSession, SafeWriteRequestor, LargeFileWriteRequestor {
|
||||
override final fun setState(component: Any?, componentName: String, state: Any) {
|
||||
val element: Element?
|
||||
try {
|
||||
|
||||
@@ -22,6 +22,7 @@ import com.intellij.openapi.project.Project
|
||||
import com.intellij.openapi.project.ProjectManager
|
||||
import com.intellij.openapi.project.ex.ProjectEx
|
||||
import com.intellij.openapi.project.impl.ProjectImpl
|
||||
import com.intellij.openapi.util.io.FileUtilRt
|
||||
import com.intellij.project.stateStore
|
||||
import com.intellij.testFramework.*
|
||||
import com.intellij.testFramework.assertions.Assertions.assertThat
|
||||
@@ -81,6 +82,13 @@ internal class ProjectStoreTest {
|
||||
(ProjectManager.getInstance() as StoreAwareProjectManager).flushChangedProjectFileAlarm()
|
||||
|
||||
assertThat(testComponent.state).isEqualTo(TestState("newValue"))
|
||||
|
||||
testComponent.state!!.value = "s".repeat(FileUtilRt.LARGE_FOR_CONTENT_LOADING + 1024)
|
||||
project.saveStore()
|
||||
|
||||
// we should save twice (first call - virtual file size is not yet set)
|
||||
testComponent.state!!.value = "b".repeat(FileUtilRt.LARGE_FOR_CONTENT_LOADING + 1024)
|
||||
project.saveStore()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,7 +159,7 @@ internal class ProjectStoreTest {
|
||||
// test exact string - xml prolog, line separators, indentation and so on must be exactly the same
|
||||
// todo get rid of default component states here
|
||||
assertThat(file.readText()).startsWith(iprFileContent.replace("customValue", "foo").replace("</project>", ""))
|
||||
|
||||
|
||||
return testComponent
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright 2000-2017 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.vfs;
|
||||
|
||||
/**
|
||||
* A marker interface for {@link VirtualFile#getOutputStream(Object)} to not assert file content size.
|
||||
* @see com.intellij.openapi.util.io.FileUtilRt#isTooLarge
|
||||
*/
|
||||
public interface LargeFileWriteRequestor {
|
||||
}
|
||||
+12
-8
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2014 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -22,6 +22,7 @@ package com.intellij.openapi.vfs.newvfs.impl;
|
||||
import com.intellij.openapi.util.Key;
|
||||
import com.intellij.openapi.util.io.FileTooBigException;
|
||||
import com.intellij.openapi.util.io.FileUtilRt;
|
||||
import com.intellij.openapi.vfs.LargeFileWriteRequestor;
|
||||
import com.intellij.openapi.vfs.VfsUtilCore;
|
||||
import com.intellij.openapi.vfs.VirtualFile;
|
||||
import com.intellij.openapi.vfs.newvfs.NewVirtualFile;
|
||||
@@ -34,7 +35,10 @@ import org.jetbrains.annotations.NonNls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.*;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
@@ -121,7 +125,7 @@ public class VirtualFileImpl extends VirtualFileSystemEntry {
|
||||
@NotNull
|
||||
@Override
|
||||
public byte[] contentsToByteArray(boolean cacheContent) throws IOException {
|
||||
checkNotTooLarge();
|
||||
checkNotTooLarge(null);
|
||||
final byte[] preloadedContent = getUserData(ourPreloadedContentKey);
|
||||
if (preloadedContent != null) return preloadedContent;
|
||||
return ourPersistence.contentsToByteArray(this, cacheContent);
|
||||
@@ -130,19 +134,19 @@ public class VirtualFileImpl extends VirtualFileSystemEntry {
|
||||
@Override
|
||||
@NotNull
|
||||
public OutputStream getOutputStream(final Object requestor, final long modStamp, final long timeStamp) throws IOException {
|
||||
checkNotTooLarge();
|
||||
checkNotTooLarge(requestor);
|
||||
return VfsUtilCore.outputStreamAddingBOM(ourPersistence.getOutputStream(this, requestor, modStamp, timeStamp), this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryContent(@NotNull byte[] content, long newModificationStamp, long newTimeStamp, Object requestor) throws IOException {
|
||||
checkNotTooLarge();
|
||||
checkNotTooLarge(requestor);
|
||||
super.setBinaryContent(content, newModificationStamp, newTimeStamp, requestor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBinaryContent(@NotNull byte[] content, long newModificationStamp, long newTimeStamp) throws IOException {
|
||||
checkNotTooLarge();
|
||||
checkNotTooLarge(null);
|
||||
super.setBinaryContent(content, newModificationStamp, newTimeStamp);
|
||||
}
|
||||
|
||||
@@ -178,8 +182,8 @@ public class VirtualFileImpl extends VirtualFileSystemEntry {
|
||||
return mySegment.changeUserMap(myId, oldMap, UserDataInterner.internUserData(newMap));
|
||||
}
|
||||
|
||||
private void checkNotTooLarge() throws FileTooBigException {
|
||||
if (isTooLarge()) throw new FileTooBigException(getPath());
|
||||
private void checkNotTooLarge(@Nullable Object requestor) throws FileTooBigException {
|
||||
if (!(requestor instanceof LargeFileWriteRequestor) && isTooLarge()) throw new FileTooBigException(getPath());
|
||||
}
|
||||
|
||||
private boolean isTooLarge() {
|
||||
|
||||
+11
-10
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2016 JetBrains s.r.o.
|
||||
* Copyright 2000-2017 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.
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
package com.intellij.configurationStore
|
||||
|
||||
import com.intellij.util.io.IOUtil
|
||||
import org.jdom.*
|
||||
import java.io.DataInputStream
|
||||
import java.io.DataOutputStream
|
||||
@@ -32,7 +33,7 @@ fun serializeElementToBinary(element: Element, out: OutputStream) {
|
||||
fun readElement(input: InputStream) = readElement(DataInputStream(input))
|
||||
|
||||
fun readElement(input: DataInputStream): Element {
|
||||
val element = Element(input.readUTF())
|
||||
val element = Element(IOUtil.readUTF(input))
|
||||
readAttributes(element, input)
|
||||
readContent(element, input)
|
||||
return element
|
||||
@@ -42,15 +43,15 @@ private fun readContent(element: Element, input: DataInputStream) {
|
||||
while (true) {
|
||||
when (input.read()) {
|
||||
TypeMarker.ELEMENT.ordinal -> element.addContent(readElement(input))
|
||||
TypeMarker.TEXT.ordinal -> element.addContent(Text(input.readUTF()))
|
||||
TypeMarker.CDATA.ordinal -> element.addContent(CDATA(input.readUTF()))
|
||||
TypeMarker.TEXT.ordinal -> element.addContent(Text(IOUtil.readUTF(input)))
|
||||
TypeMarker.CDATA.ordinal -> element.addContent(CDATA(IOUtil.readUTF(input)))
|
||||
TypeMarker.ELEMENT_END.ordinal -> return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun writeElement(element: Element, out: DataOutputStream) {
|
||||
out.writeUTF(element.name)
|
||||
IOUtil.writeUTF(out, element.name)
|
||||
|
||||
writeAttributes(out, element.attributes)
|
||||
|
||||
@@ -63,12 +64,12 @@ private fun writeElement(element: Element, out: DataOutputStream) {
|
||||
else if (item is Text) {
|
||||
if (!isAllWhitespace(item)) {
|
||||
out.writeByte(TypeMarker.TEXT.ordinal)
|
||||
out.writeUTF(item.text)
|
||||
IOUtil.writeUTF(out, item.text)
|
||||
}
|
||||
}
|
||||
else if (item is CDATA) {
|
||||
out.writeByte(TypeMarker.CDATA.ordinal)
|
||||
out.writeUTF(item.text)
|
||||
IOUtil.writeUTF(out, item.text)
|
||||
}
|
||||
}
|
||||
out.writeByte(TypeMarker.ELEMENT_END.ordinal)
|
||||
@@ -86,8 +87,8 @@ private fun writeAttributes(out: DataOutputStream, attributes: List<Attribute>?)
|
||||
}
|
||||
else {
|
||||
for (attribute in attributes!!) {
|
||||
out.writeUTF(attribute.name)
|
||||
out.writeUTF(attribute.value)
|
||||
IOUtil.writeUTF(out, attribute.name)
|
||||
IOUtil.writeUTF(out, attribute.value)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -95,7 +96,7 @@ private fun writeAttributes(out: DataOutputStream, attributes: List<Attribute>?)
|
||||
private fun readAttributes(element: Element, input: DataInputStream) {
|
||||
val size = input.readUnsignedByte()
|
||||
for (i in 0..size - 1) {
|
||||
element.setAttribute(Attribute(input.readUTF(), input.readUTF()))
|
||||
element.setAttribute(Attribute(IOUtil.readUTF(input), IOUtil.readUTF(input)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user