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