Skip to content

Commit c5603d2

Browse files
EcljpseB0Tjukzi
authored andcommitted
[performance] IFile.write(byte[]): reduce store.fetchInfo()
Optimistically assume the parent folder already exists on local File System when it exists in workspace. So do not explicitly check it. If it did not exist file write will fail and can be retried after creating the parent in File System - which can only happen when the workspace is out of sync with local File System. This optimization is only implemented for byte[] content in the not appending case: * InputStream content would need a reset. * In append mode it is not obvious if something was already appended. #1443
1 parent 6543b14 commit c5603d2

File tree

2 files changed

+45
-5
lines changed

2 files changed

+45
-5
lines changed

resources/bundles/org.eclipse.core.resources/src/org/eclipse/core/internal/localstore/FileSystemResourceManager.java

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1212,7 +1212,7 @@ public void write(IFile target, InputStream content, IFileInfo fileInfo, int upd
12121212
try (content) {
12131213
Resource targetResource = (Resource) target;
12141214
IFileStore store = getStore(target);
1215-
prepareWrite(target, fileInfo, updateFlags, append, targetResource, store);
1215+
prepareWrite(target, fileInfo, updateFlags, append, targetResource, store, false);
12161216

12171217
int options = append ? EFS.APPEND : EFS.NONE;
12181218
try {
@@ -1254,7 +1254,7 @@ public void write(IFile target, InputStream content, IFileInfo fileInfo, int upd
12541254
}
12551255

12561256
private void prepareWrite(IFile target, IFileInfo fileInfo, int updateFlags, boolean append,
1257-
Resource targetResource, IFileStore store) throws CoreException {
1257+
Resource targetResource, IFileStore store, boolean assumeParentDirectoryExists) throws CoreException {
12581258
if (fileInfo.getAttribute(EFS.ATTRIBUTE_READ_ONLY)) {
12591259
String message = NLS.bind(Messages.localstore_couldNotWriteReadOnly, target.getFullPath());
12601260
throw new ResourceException(IResourceStatus.FAILED_WRITE_LOCAL, target.getFullPath(), message, null);
@@ -1303,7 +1303,7 @@ private void prepareWrite(IFile target, IFileInfo fileInfo, int updateFlags, boo
13031303
// never move to the history store, because then the file is missing if write
13041304
// fails
13051305
getHistoryStore().addState(target.getFullPath(), store, fileInfo, false);
1306-
if (!fileInfo.exists()) {
1306+
if (!assumeParentDirectoryExists && !fileInfo.exists()) {
13071307
IFileStore parent = store.getParent();
13081308
IFileInfo parentInfo = parent.fetchInfo();
13091309
if (!parentInfo.exists()) {
@@ -1338,7 +1338,7 @@ public void write(IFile target, byte[] content, IFileInfo fileInfo, int updateFl
13381338
SubMonitor subMonitor = SubMonitor.convert(monitor, 4);
13391339
Resource targetResource = (Resource) target;
13401340
IFileStore store = getStore(target);
1341-
prepareWrite(target, fileInfo, updateFlags, append, targetResource, store);
1341+
prepareWrite(target, fileInfo, updateFlags, append, targetResource, store, true);
13421342

13431343
// On Windows an attempt to open an output stream on a hidden file results in
13441344
// FileNotFoundException.
@@ -1353,7 +1353,25 @@ public void write(IFile target, byte[] content, IFileInfo fileInfo, int updateFl
13531353
subMonitor.split(1);
13541354
}
13551355
int options = append ? EFS.APPEND : EFS.NONE;
1356-
store.write(content, options, subMonitor.split(1));
1356+
try {
1357+
store.write(content, options, subMonitor.split(1));
1358+
} catch (CoreException e) {
1359+
if (append) {
1360+
throw e;
1361+
}
1362+
if (e.getStatus().getCode() != EFS.ERROR_WRITE) {
1363+
throw e;
1364+
}
1365+
IFileStore parent = store.getParent();
1366+
IFileInfo parentInfo = parent.fetchInfo();
1367+
if (parentInfo.exists()) {
1368+
throw e;
1369+
}
1370+
// create missing folders:
1371+
parent.mkdir(EFS.NONE, null);
1372+
// try again:
1373+
store.write(content, options, null);
1374+
}
13571375
if (restoreHiddenAttribute) {
13581376
fileInfo.setAttribute(EFS.ATTRIBUTE_HIDDEN, true);
13591377
store.putInfo(fileInfo, EFS.SET_ATTRIBUTES, subMonitor.split(1));

resources/tests/org.eclipse.core.tests.resources/src/org/eclipse/core/tests/resources/IFileTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@
4646
import java.util.ArrayList;
4747
import java.util.List;
4848
import java.util.concurrent.atomic.AtomicInteger;
49+
import org.eclipse.core.internal.resources.ResourceException;
4950
import org.eclipse.core.resources.IContainer;
5051
import org.eclipse.core.resources.IFile;
5152
import org.eclipse.core.resources.IFileState;
@@ -507,6 +508,27 @@ public void testCreateBytes() throws CoreException {
507508
assertFalse(derived.isDerived());
508509
assertFalse(derived.isTeamPrivateMember());
509510
assertEquals("notDerived", derived.readString());
511+
512+
IFolder subFolder = projects[0].getFolder("subFolder");
513+
subFolder.create(true, true, null);
514+
subFolder.getRawLocation().toFile().delete();
515+
516+
IFile orphan = subFolder.getFile("myParentDoesNotExist.txt");
517+
monitor.prepare();
518+
orphan.write("parentDoesNotExistInFileSystemButInWorkspace".getBytes(), true, false, false, monitor);
519+
monitor.assertUsedUp();
520+
assertEquals("parentDoesNotExistInFileSystemButInWorkspace", orphan.readString());
521+
522+
monitor.prepare();
523+
orphan.getParent().delete(true, null);
524+
// if the parent is deleted in workspace Exception is expected:
525+
try {
526+
orphan.write("parentDoesNotExist - not even in workspace".getBytes(), true, false, false, monitor);
527+
assertFalse("should not be reached", true);
528+
} catch (ResourceException expected) {
529+
monitor.assertUsedUp();
530+
assertFalse(orphan.exists());
531+
}
510532
}
511533

512534
@Test

0 commit comments

Comments
 (0)