Fix ClosedFileSystemException on hot redeploy (#11549)
#11548 implemented workaround for JDK-8291712 Signed-off-by: Ludovic Orban <lorban@bitronix.be>
This commit is contained in:
parent
258a5e04de
commit
13acb1779e
|
@ -120,8 +120,15 @@ public class FileSystemPool implements Dumpable
|
|||
catch (FileSystemAlreadyExistsException fsaee)
|
||||
{
|
||||
fileSystem = Paths.get(jarURIRoot).getFileSystem();
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Using existing FS {}", jarURIRoot);
|
||||
if (!fileSystem.isOpen())
|
||||
{
|
||||
LOG.warn("FileSystem {} of URI {} already exists but is not open (bug JDK-8291712)", fileSystem, uri);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Using existing FS {}", jarURIRoot);
|
||||
}
|
||||
}
|
||||
catch (ProviderNotFoundException pnfe)
|
||||
{
|
||||
|
@ -164,10 +171,32 @@ public class FileSystemPool implements Dumpable
|
|||
{
|
||||
if (LOG.isDebugEnabled())
|
||||
LOG.debug("Ref counter reached 0, closing pooled FS {}", bucket);
|
||||
IO.close(bucket.fileSystem);
|
||||
pool.remove(fsUri);
|
||||
if (listener != null)
|
||||
listener.onClose(fsUri);
|
||||
try
|
||||
{
|
||||
// If the filesystem's backing file was deleted, re-create it temporarily before closing
|
||||
// the filesystem to try to work around JDK-8291712.
|
||||
Path rootOfCreatedPath = null;
|
||||
if (!Files.exists(bucket.path))
|
||||
rootOfCreatedPath = createEmptyFileWithParents(bucket.path);
|
||||
try
|
||||
{
|
||||
bucket.fileSystem.close();
|
||||
}
|
||||
finally
|
||||
{
|
||||
IO.delete(rootOfCreatedPath);
|
||||
}
|
||||
// Remove the FS from the pool only if the above code did not throw as if it is
|
||||
// createEmptyFileWithParents() that threw, there is a chance we could re-create
|
||||
// that file later on.
|
||||
pool.remove(fsUri);
|
||||
if (listener != null)
|
||||
listener.onClose(fsUri);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
LOG.warn("Unable to close FileSystem {} of URI {} (bug JDK-8291712)", bucket.fileSystem, fsUri, e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -183,6 +212,33 @@ public class FileSystemPool implements Dumpable
|
|||
}
|
||||
}
|
||||
|
||||
private Path createEmptyFileWithParents(Path path) throws IOException
|
||||
{
|
||||
Path createdRootPath = null;
|
||||
if (!Files.exists(path.getParent()))
|
||||
createdRootPath = createDirWithAllParents(path.getParent());
|
||||
Files.createFile(path);
|
||||
if (createdRootPath == null)
|
||||
createdRootPath = path;
|
||||
return createdRootPath;
|
||||
}
|
||||
|
||||
private Path createDirWithAllParents(Path path) throws IOException
|
||||
{
|
||||
Path parentPath = path.getParent();
|
||||
if (!Files.exists(parentPath))
|
||||
{
|
||||
Path createdRootPath = createDirWithAllParents(parentPath);
|
||||
Files.createDirectory(path);
|
||||
return createdRootPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
Files.createDirectory(path);
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
@ManagedAttribute("The mounted FileSystems")
|
||||
public Collection<Mount> mounts()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// ========================================================================
|
||||
// Copyright (c) 1995 Mort Bay Consulting Pty Ltd and others.
|
||||
//
|
||||
// This program and the accompanying materials are made available under the
|
||||
// terms of the Eclipse Public License v. 2.0 which is available at
|
||||
// https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
|
||||
// which is available at https://www.apache.org/licenses/LICENSE-2.0.
|
||||
//
|
||||
// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
|
||||
// ========================================================================
|
||||
//
|
||||
|
||||
package org.eclipse.jetty.util;
|
||||
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
|
||||
import org.eclipse.jetty.toolchain.test.MavenTestingUtils;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDir;
|
||||
import org.eclipse.jetty.toolchain.test.jupiter.WorkDirExtension;
|
||||
import org.eclipse.jetty.util.resource.Resource;
|
||||
import org.eclipse.jetty.util.resource.ResourceFactory;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.ValueSource;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
|
||||
@ExtendWith(WorkDirExtension.class)
|
||||
public class FileSystemPoolTest
|
||||
{
|
||||
public WorkDir workDir;
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"example.jar", "a/b/c/d/example.jar"})
|
||||
public void testCloseResourceFactoryAfterDeletingFileSystemBackingFile(String jarPathString) throws Exception
|
||||
{
|
||||
Path srcPath = MavenTestingUtils.getTestResourcePath("example.jar");
|
||||
Path rootPath = workDir.getEmptyPathDir();
|
||||
Path jarPath = rootPath.resolve(jarPathString);
|
||||
Files.createDirectories(jarPath.getParent());
|
||||
|
||||
Files.copy(srcPath, jarPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
ResourceFactory.Closeable rf1 = ResourceFactory.closeable();
|
||||
Resource resource1 = rf1.newResource(URIUtil.toJarFileUri(jarPath.toUri()));
|
||||
assertThat(resource1.exists(), is(true));
|
||||
// delete the jar file before closing the FS
|
||||
IO.delete(rootPath);
|
||||
rf1.close();
|
||||
assertThat(Files.exists(rootPath), is(false));
|
||||
|
||||
// re-create the jar file at the exact same location
|
||||
Files.createDirectories(jarPath.getParent());
|
||||
Files.copy(srcPath, jarPath, StandardCopyOption.REPLACE_EXISTING);
|
||||
ResourceFactory.Closeable rf2 = ResourceFactory.closeable();
|
||||
// Calling ResourceFactory.newResource() again on the same jar would throw
|
||||
// java.nio.file.ClosedFileSystemException without the workaround for JDK-8291712.
|
||||
Resource resource2 = rf2.newResource(URIUtil.toJarFileUri(jarPath.toUri()));
|
||||
assertThat(resource2.exists(), is(true));
|
||||
rf2.close();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue