diff --git a/MyPerf4J-Base/src/main/java/cn/myperf4j/base/config/ConfigKey.java b/MyPerf4J-Base/src/main/java/cn/myperf4j/base/config/ConfigKey.java index 614e95f4..b414f3a6 100644 --- a/MyPerf4J-Base/src/main/java/cn/myperf4j/base/config/ConfigKey.java +++ b/MyPerf4J-Base/src/main/java/cn/myperf4j/base/config/ConfigKey.java @@ -22,6 +22,11 @@ public String legacyKey() { return legacyKey; } + @Override + public String toString() { + return key; + } + public static ConfigKey of(String key, String legacyKey) { return new ConfigKey(key, legacyKey); } diff --git a/MyPerf4J-Core/src/main/java/cn/myperf4j/core/MethodMetricsHistogram.java b/MyPerf4J-Core/src/main/java/cn/myperf4j/core/MethodMetricsHistogram.java index e94002ee..e098c64e 100644 --- a/MyPerf4J-Core/src/main/java/cn/myperf4j/core/MethodMetricsHistogram.java +++ b/MyPerf4J-Core/src/main/java/cn/myperf4j/core/MethodMetricsHistogram.java @@ -9,12 +9,17 @@ import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import static java.nio.file.StandardCopyOption.REPLACE_EXISTING; + /** * Created by LinShunkang on 2019/07/23 */ @@ -51,8 +56,26 @@ private static void recordMetrics0(int methodTagId, int tp95, int tp99, int tp99 public static void buildSysGenProfilingFile() { final long startMills = System.currentTimeMillis(); final String filePath = ProfilingConfig.basicConfig().sysProfilingParamsFile(); + + try { + final File tempFile = buildTmpProfilingFile(filePath); + final Path destPath = Files.move(tempFile.toPath(), Paths.get(filePath), REPLACE_EXISTING); + final File destFile = destPath.toFile(); + // 此处不能设置只读,否则在windows环境下次move的时候会报错 AccessDeniedException + final boolean rename = destFile.exists()/* && destFile.setReadOnly() */; + Logger.debug("MethodMetricsHistogram.buildSysGenProfilingFile(): rename " + tempFile.getName() + + " to " + destFile.getName() + " " + (rename ? "success" : "fail")); + } catch (Exception e) { + Logger.error("MethodMetricsHistogram.buildSysGenProfilingFile() error", e); + } finally { + Logger.debug("MethodMetricsHistogram.buildSysGenProfilingFile() finished, cost=" + + (System.currentTimeMillis() - startMills) + "ms"); + } + } + + private static File buildTmpProfilingFile(String filePath) throws IOException { final String tempFilePath = filePath + "_tmp"; - final File tempFile = new File(tempFilePath); + final File tempFile = Paths.get(tempFilePath).toFile(); try (BufferedWriter fileWriter = new BufferedWriter(new FileWriter(tempFile, false), 8 * 1024)) { fileWriter.write("#This is a file automatically generated by MyPerf4J, please do not edit!\n"); @@ -73,23 +96,13 @@ public static void buildSysGenProfilingFile() { if (!neverInvokedMethods.isEmpty()) { fileWriter.write("#The following methods have never been invoked!\n"); - for (int i = 0; i < neverInvokedMethods.size(); i++) { - final Integer methodId = neverInvokedMethods.get(i); + for (final Integer methodId : neverInvokedMethods) { writeProfilingInfo(tagMaintainer, fileWriter, methodId, 128); } fileWriter.flush(); } - - final File destFile = new File(filePath); - final boolean rename = tempFile.renameTo(destFile) && destFile.setReadOnly(); - Logger.debug("MethodMetricsHistogram.buildSysGenProfilingFile(): rename " + tempFile.getName() - + " to " + destFile.getName() + " " + (rename ? "success" : "fail")); - } catch (Exception e) { - Logger.error("MethodMetricsHistogram.buildSysGenProfilingFile()", e); - } finally { - Logger.debug("MethodMetricsHistogram.buildSysGenProfilingFile() finished, cost=" - + (System.currentTimeMillis() - startMills) + "ms"); } + return tempFile; } private static void writeProfilingInfo(MethodTagMaintainer tagMaintainer, diff --git a/MyPerf4J-Core/src/test/java/cn/myperf4j/core/FileTest.java b/MyPerf4J-Core/src/test/java/cn/myperf4j/core/FileTest.java new file mode 100644 index 00000000..74060026 --- /dev/null +++ b/MyPerf4J-Core/src/test/java/cn/myperf4j/core/FileTest.java @@ -0,0 +1,137 @@ +package cn.myperf4j.core; + +import cn.myperf4j.base.util.Logger; +import org.junit.AfterClass; +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.Objects; + +/** + * 文件测试 + */ +public class FileTest { + + private static final File baseDir = new File(System.getProperty("user.dir")); + + private static final File testDir = new File(baseDir, "temp"); + + @BeforeClass + public static void prepare() { + getDir(FileTest.class.getSimpleName()); + } + + @AfterClass + public static void cleanup() { + deleteDir(FileTest.class.getSimpleName()); + } + + @Test + public void testFileRename() { + String testFile = getTestDir().getPath() + "/testFileRename"; + final Path testFilePath1 = Paths.get(testFile + 1); + final Path testFilePath2 = Paths.get(testFile + 2); + final Path tmpFilePath = Paths.get(testFile + "_tmp"); + + for (int i = 0; i < 2; i++) { + try (BufferedWriter fileWriter = new BufferedWriter(new FileWriter(tmpFilePath.toFile(), false), 8192)) { + fileWriter.write("#This is a file automatically generated by MyPerf4J, please do not edit!\n"); + fileWriter.flush(); + // 流还没释放导致 + Assert.assertFalse(tmpFilePath.toFile().renameTo(testFilePath1.toFile())); + Assert.assertFalse(testFilePath1.toFile().setReadOnly()); + } catch (Exception e) { + Logger.error("testFileRename error", e); + } + + if (i == 0) { + // 第一次rename能成功 文件存在的情况setReadOnly始终能成功 + Assert.assertTrue(tmpFilePath.toFile().renameTo(testFilePath2.toFile())); + Assert.assertTrue(testFilePath2.toFile().setReadOnly()); + } else { + // 第一次rename能成功,后续就失败 + Assert.assertFalse(tmpFilePath.toFile().renameTo(testFilePath2.toFile())); + Assert.assertTrue(testFilePath2.toFile().setReadOnly()); + } + } + // tmp文件存在 + Assert.assertTrue(tmpFilePath.toFile().exists()); + // BufferedWriter没释放时rename的文件不存在 + Assert.assertFalse(testFilePath1.toFile().exists()); + // BufferedWriter释放后rename的文件存在 + Assert.assertTrue(testFilePath2.toFile().exists()); + } + + @Test + public void testFilesMove() throws IOException { + String testFile = getTestDir().getPath() + "/testFilesMove"; + final Path testFilePath = Paths.get(testFile); + final Path tmpFilePath = Paths.get(testFile + "_tmp"); + if (!tmpFilePath.toFile().exists()) { + Files.createFile(tmpFilePath); + tmpFilePath.toFile().setReadOnly(); + } + Assert.assertFalse(tmpFilePath.toFile().canWrite()); + + final Path moved = Files.move(tmpFilePath, testFilePath, StandardCopyOption.REPLACE_EXISTING); + moved.toFile().setReadOnly(); + Assert.assertFalse(moved.toFile().canWrite()); + + Files.move(moved, tmpFilePath, StandardCopyOption.REPLACE_EXISTING); + Assert.assertFalse(tmpFilePath.toFile().canWrite()); + } + + private File getTestDir() { + return getDir(FileTest.class.getSimpleName()); + } + + private static File getDir(String dir) { + File file = new File(testDir, dir); + if (!file.isDirectory()) { + if (!file.mkdirs()) { + throw new IllegalStateException("Can't create dir: " + file); + } + } + return file; + } + + private static void deleteDir(String dir) { + deleteDir(testDir, dir); + } + + private static void deleteDir(final File parent, String dir) { + final File dirFile = new File(parent, dir); + if (dirFile.isDirectory()) { + for (final File f: Objects.requireNonNull(dirFile.listFiles())) { + if (f.isDirectory()) { + deleteDir(dirFile, f.getName()); + continue; + } + + if (f.isFile()) { + if (!f.delete()) { + throw new IllegalStateException("Can't delete file: " + f); + } + Logger.info("Delete file: " + f); + } + } + + if (!dirFile.delete()) { + throw new IllegalStateException("Can't delete directory: " + dirFile); + } + Logger.info("Delete directory: " + dirFile); + } + + testDir.deleteOnExit(); + Logger.info("Delete testDir: " + testDir); + } +} diff --git a/pom.xml b/pom.xml index f8a3458a..2bb2730f 100644 --- a/pom.xml +++ b/pom.xml @@ -148,7 +148,7 @@ com.puppycrawl.tools checkstyle - 8.29 + 8.40 io.netty