You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2022/02/08 02:17:45 UTC
[dubbo] branch 3.0 updated: [3.0] FileCacheStore refactor & Add FileCacheStoreFactory (#9655)
This is an automated email from the ASF dual-hosted git repository.
liujun pushed a commit to branch 3.0
in repository https://gitbox.apache.org/repos/asf/dubbo.git
The following commit(s) were added to refs/heads/3.0 by this push:
new adea101 [3.0] FileCacheStore refactor & Add FileCacheStoreFactory (#9655)
adea101 is described below
commit adea101f93555101a5a0eaec6951c055bfe1ede8
Author: Albumen Kevin <jh...@gmail.com>
AuthorDate: Tue Feb 8 10:17:00 2022 +0800
[3.0] FileCacheStore refactor & Add FileCacheStoreFactory (#9655)
---
.../apache/dubbo/common/cache/FileCacheStore.java | 239 +++++++++------------
.../dubbo/common/cache/FileCacheStoreFactory.java | 170 +++++++++++++++
.../org/apache/dubbo/common/utils/NetUtils.java | 2 +-
.../org/apache/dubbo/common/utils/StringUtils.java | 12 +-
.../common/cache/FileCacheStoreFactoryTest.java | 74 +++++++
.../dubbo/common/cache/FileCacheStoreTest.java | 20 +-
.../apache/dubbo/common/utils/StringUtilsTest.java | 6 +-
.../apache/dubbo/qos/command/impl/CountTelnet.java | 4 +-
.../apache/dubbo/qos/command/impl/PortTelnet.java | 2 +-
.../dubbo/qos/command/impl/SelectTelnet.java | 2 +-
.../dubbo/qos/command/impl/ShutdownTelnet.java | 2 +-
.../apache/dubbo/qos/legacy/LogTelnetHandler.java | 2 +-
.../dubbo/qos/legacy/TraceTelnetHandler.java | 4 +-
.../client/metadata/store/MetaCacheManager.java | 14 +-
.../metadata/store/MetaCacheManagerTest.java | 2 +-
.../telnet/support/command/ClearTelnetHandler.java | 2 +-
.../telnet/support/command/LogTelnetHandler.java | 2 +-
17 files changed, 401 insertions(+), 158 deletions(-)
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStore.java b/dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStore.java
index acfda26..a8ecc80 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStore.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStore.java
@@ -27,48 +27,35 @@ import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.IOException;
import java.io.OutputStreamWriter;
-import java.io.RandomAccessFile;
-import java.nio.channels.FileChannel;
+import java.io.Writer;
import java.nio.channels.FileLock;
-import java.nio.channels.OverlappingFileLockException;
import java.nio.charset.StandardCharsets;
+import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.Map;
-import java.util.Set;
/**
* Local file interaction class that can back different caches.
- *
+ * <p>
* All items in local file are of human friendly format.
*/
public class FileCacheStore {
private static final Logger logger = LoggerFactory.getLogger(FileCacheStore.class);
- private static final int DEL = 0x7F;
- private static final char ESCAPE = '%';
- private static final Set<Character> ILLEGALS = new HashSet<Character>();
- private static final String SUFFIX = ".dubbo.cache";
-
- private File basePath;
+ private String cacheFilePath;
private File cacheFile;
- private FileLock directoryLock;
private File lockFile;
+ private FileLock directoryLock;
- public FileCacheStore(String basePath, String fileName) throws IOException, PathNotExclusiveException {
- if (basePath == null) {
- basePath = System.getProperty("user.home") + "/.dubbo/";
- }
- this.basePath = new File(basePath);
-
- this.cacheFile = getFile(fileName, SUFFIX);
- if (cacheFile != null && !cacheFile.exists()) {
- cacheFile.createNewFile();
- }
+ private FileCacheStore(String cacheFilePath, File cacheFile, File lockFile, FileLock directoryLock) {
+ this.cacheFilePath = cacheFilePath;
+ this.cacheFile = cacheFile;
+ this.lockFile = lockFile;
+ this.directoryLock = directoryLock;
}
- public Map<String, String> loadCache(int entrySize) throws IOException {
+ public synchronized Map<String, String> loadCache(int entrySize) throws IOException {
Map<String, String> properties = new HashMap<>();
try (BufferedReader reader = new BufferedReader(new FileReader(cacheFile))) {
int count = 1;
@@ -93,105 +80,6 @@ public class FileCacheStore {
return properties;
}
- public File getFile(String cacheName, String suffix) throws PathNotExclusiveException {
- cacheName = safeName(cacheName);
- if (!cacheName.endsWith(suffix)) {
- cacheName = cacheName + suffix;
- }
- return getFile(cacheName);
- }
-
- /**
- * Get a file object for the given name
- *
- * @param name the file name
- * @return a file object
- */
- public File getFile(String name) throws PathNotExclusiveException {
- synchronized (this) {
- File candidate = basePath;
- // ensure cache store path exists
- if (!candidate.isDirectory() && !candidate.mkdirs()) {
- throw new RuntimeException("Cache store path can't be created: " + candidate);
- }
-
- boolean autoCreated = false;
- int index = 1;
- while (true) {
- try {
- tryFileLock(name);
- break;
- } catch (PathNotExclusiveException e) {
- autoCreated = true;
- index++;
- name += index;
- if (index > 3) {
- logger.warn("Path '" + basePath + "/" + name
- + "' has already used by an existing Dubbo process.\n Please specify another one explicitly.");
- throw e;
- }
- }
- }
- if (autoCreated && index < 3) {
- logger.warn("Auto-generated cache file name is " + basePath + "/" + name);
- }
- }
-
- File file = new File(basePath, name);
- for (File parent = file.getParentFile(); parent != null; parent = parent.getParentFile()) {
- if (basePath.equals(parent)) {
- return file;
- }
- }
-
- throw new IllegalArgumentException("Attempted to access file outside the dubbo cache path");
- }
-
- /**
- * sanitize a name for valid file or directory name
- *
- * @param name
- * @return sanitized version of name
- */
- private static String safeName(String name) {
- int len = name.length();
- StringBuilder sb = new StringBuilder(len);
- for (int i = 0; i < len; i++) {
- char c = name.charAt(i);
- if (c <= ' ' || c >= DEL || (c >= 'A' && c <= 'Z') || ILLEGALS.contains(c) || c == ESCAPE) {
- sb.append(ESCAPE);
- sb.append(String.format("%04x", (int) c));
- } else {
- sb.append(c);
- }
- }
- return sb.toString();
- }
-
- private void tryFileLock(String fileName) throws PathNotExclusiveException {
- lockFile = new File(basePath.getAbsoluteFile(), fileName + ".lock");
- lockFile.deleteOnExit();
-
- FileLock dirLock;
- try {
- lockFile.createNewFile();
- if (!lockFile.exists()) {
- throw new AssertionError("Failed to create lock file " + lockFile);
- }
- FileChannel lockFileChannel = new RandomAccessFile(lockFile, "rw").getChannel();
- dirLock = lockFileChannel.tryLock();
- } catch (OverlappingFileLockException ofle) {
- dirLock = null;
- } catch (IOException ioe) {
- throw new RuntimeException(ioe);
- }
-
- if (dirLock == null) {
- throw new PathNotExclusiveException(basePath.getAbsolutePath() + "/" + fileName + " is not exclusive.");
- }
-
- this.directoryLock = dirLock;
- }
private void unlock() {
if (directoryLock != null && directoryLock.isValid()) {
@@ -205,12 +93,15 @@ public class FileCacheStore {
}
}
- public void refreshCache(Map<String, String> properties, String comment) {
+ public synchronized void refreshCache(Map<String, String> properties, String comment, long maxFileSize) {
if (CollectionUtils.isEmptyMap(properties)) {
return;
}
- try (BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(cacheFile, false), StandardCharsets.UTF_8))) {
+ try (LimitedLengthBufferedWriter bw =
+ new LimitedLengthBufferedWriter(
+ new OutputStreamWriter(
+ new FileOutputStream(cacheFile, false), StandardCharsets.UTF_8), maxFileSize)) {
bw.write("#" + comment);
bw.newLine();
bw.write("#" + new Date());
@@ -222,6 +113,10 @@ public class FileCacheStore {
bw.newLine();
}
bw.flush();
+ long remainSize = bw.getRemainSize();
+ if (remainSize < 0) {
+ logger.info("Cache file was truncated for exceeding the maximum file size " + maxFileSize + " byte. Exceeded by " + (-remainSize) + " byte.");
+ }
} catch (IOException e) {
logger.warn("Update cache error.");
}
@@ -233,17 +128,97 @@ public class FileCacheStore {
}
}
- private static class PathNotExclusiveException extends Exception {
- public PathNotExclusiveException() {
- super();
+ public synchronized void destroy() {
+ unlock();
+ FileCacheStoreFactory.removeCache(cacheFilePath);
+ }
+
+ /**
+ * for unit test only
+ */
+ @Deprecated
+ protected String getCacheFilePath() {
+ return cacheFilePath;
+ }
+
+ public static Builder newBuilder() {
+ return new Builder();
+ }
+
+ public static class Builder {
+ private String cacheFilePath;
+ private File cacheFile;
+ private File lockFile;
+ private FileLock directoryLock;
+
+ private Builder() {
}
- public PathNotExclusiveException(String msg) {
- super(msg);
+ public Builder cacheFilePath(String cacheFilePath) {
+ this.cacheFilePath = cacheFilePath;
+ return this;
+ }
+
+ public Builder cacheFile(File cacheFile) {
+ this.cacheFile = cacheFile;
+ return this;
+ }
+
+ public Builder lockFile(File lockFile) {
+ this.lockFile = lockFile;
+ return this;
+ }
+
+ public Builder directoryLock(FileLock directoryLock) {
+ this.directoryLock = directoryLock;
+ return this;
+ }
+
+ public FileCacheStore build() {
+ return new FileCacheStore(cacheFilePath, cacheFile, lockFile, directoryLock);
}
}
- public void destroy() {
- unlock();
+ protected static class Empty extends FileCacheStore {
+
+ private Empty(String cacheFilePath) {
+ super(cacheFilePath, null, null, null);
+ }
+
+ public static Empty getInstance(String cacheFilePath) {
+ return new Empty(cacheFilePath);
+ }
+
+ @Override
+ public Map<String, String> loadCache(int entrySize) throws IOException {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public void refreshCache(Map<String, String> properties, String comment, long maxFileSize) {
+ }
+ }
+
+ private static class LimitedLengthBufferedWriter extends BufferedWriter {
+
+ private long remainSize;
+
+ public LimitedLengthBufferedWriter(Writer out, long maxSize) {
+ super(out);
+ this.remainSize = maxSize == 0 ? Long.MAX_VALUE : maxSize;
+ }
+
+ @Override
+ public void write(String str) throws IOException {
+ remainSize -= str.getBytes(StandardCharsets.UTF_8).length;
+ if (remainSize < 0) {
+ return;
+ }
+ super.write(str);
+ }
+
+ public long getRemainSize() {
+ return remainSize;
+ }
}
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStoreFactory.java b/dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStoreFactory.java
new file mode 100644
index 0000000..13fe540
--- /dev/null
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/cache/FileCacheStoreFactory.java
@@ -0,0 +1,170 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.common.cache;
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileChannel;
+import java.nio.channels.FileLock;
+import java.nio.channels.OverlappingFileLockException;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * ClassLoader Level static share.
+ * Prevent FileCacheStore being operated in multi-application
+ */
+public class FileCacheStoreFactory {
+ private final static Logger logger = LoggerFactory.getLogger(FileCacheStoreFactory.class);
+ private static final Map<String, FileCacheStore> cacheMap = new ConcurrentHashMap<>();
+
+ private static final String SUFFIX = ".dubbo.cache";
+ private static final char ESCAPE = '%';
+ private static final Set<Character> LEGAL_CHARACTERS = Collections.unmodifiableSet(new HashSet<Character>(){{
+ // - $ . _ 0-9 a-z A-Z
+ add('-');
+ add('$');
+ add('.');
+ add('_');
+ for (char c = '0'; c <= '9'; c++) {
+ add(c);
+ }
+ for (char c = 'a'; c <= 'z'; c++) {
+ add(c);
+ }
+ for (char c = 'A'; c <= 'Z'; c++) {
+ add(c);
+ }
+ }});
+
+ public static FileCacheStore getInstance(String basePath, String cacheName) {
+ if (basePath == null) {
+ basePath = System.getProperty("user.home") + "/.dubbo/";
+ }
+
+ File candidate = new File(basePath);
+ // ensure cache store path exists
+ if (!candidate.isDirectory() && !candidate.mkdirs()) {
+ throw new RuntimeException("Cache store path can't be created: " + candidate);
+ }
+
+ cacheName = safeName(cacheName);
+ if (!cacheName.endsWith(SUFFIX)) {
+ cacheName = cacheName + SUFFIX;
+ }
+
+ String cacheFilePath = basePath + File.separator + cacheName;
+
+ return cacheMap.computeIfAbsent(cacheFilePath, (k) -> getFile(k));
+ }
+
+ /**
+ * sanitize a name for valid file or directory name
+ *
+ * @param name origin file name
+ * @return sanitized version of name
+ */
+ private static String safeName(String name) {
+ int len = name.length();
+ StringBuilder sb = new StringBuilder(len);
+ for (int i = 0; i < len; i++) {
+ char c = name.charAt(i);
+ if (LEGAL_CHARACTERS.contains(c)) {
+ sb.append(c);
+ } else {
+ sb.append(ESCAPE);
+ sb.append(String.format("%04x", (int) c));
+ }
+ }
+ return sb.toString();
+ }
+
+ /**
+ * Get a file object for the given name
+ *
+ * @param name the file name
+ * @return a file object
+ */
+ private static FileCacheStore getFile(String name) {
+ try {
+ FileCacheStore.Builder builder = FileCacheStore.newBuilder();
+ tryFileLock(builder, name);
+ File file = new File(name);
+ if (!file.exists()) {
+ file.createNewFile();
+ }
+
+ builder.cacheFilePath(name)
+ .cacheFile(file);
+ return builder.build();
+ } catch (Throwable t) {
+ logger.info("Failed to create file store cache. Local file cache will be disabled. Cache file name: " + name, t);
+ return FileCacheStore.Empty.getInstance(name);
+ }
+ }
+
+ private static void tryFileLock(FileCacheStore.Builder builder, String fileName) throws PathNotExclusiveException {
+ File lockFile = new File(fileName + ".lock");
+ lockFile.deleteOnExit();
+
+ FileLock dirLock;
+ try {
+ lockFile.createNewFile();
+ if (!lockFile.exists()) {
+ throw new AssertionError("Failed to create lock file " + lockFile);
+ }
+ FileChannel lockFileChannel = new RandomAccessFile(lockFile, "rw").getChannel();
+ dirLock = lockFileChannel.tryLock();
+ } catch (OverlappingFileLockException ofle) {
+ dirLock = null;
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+
+ if (dirLock == null) {
+ throw new PathNotExclusiveException(fileName + " is not exclusive.");
+ }
+
+ builder.directoryLock(dirLock).lockFile(lockFile);
+ }
+
+ protected static void removeCache(String cacheFileName) {
+ cacheMap.remove(cacheFileName);
+ }
+
+ /**
+ * for unit test only
+ */
+ @Deprecated
+ protected static Map<String, FileCacheStore> getCacheMap() {
+ return cacheMap;
+ }
+
+ private static class PathNotExclusiveException extends Exception {
+ public PathNotExclusiveException(String msg) {
+ super(msg);
+ }
+ }
+
+}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
index a0b56a8..c4f24df 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/NetUtils.java
@@ -643,7 +643,7 @@ public class NetUtils {
int i = host.indexOf('.');
if (i > 0) {
String prefix = host.substring(0, i);
- if (StringUtils.isInteger(prefix)) {
+ if (StringUtils.isNumber(prefix)) {
int p = Integer.parseInt(prefix);
return p >= 224 && p <= 239;
}
diff --git a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
index 386921a..3332b40 100644
--- a/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
+++ b/dubbo-common/src/main/java/org/apache/dubbo/common/utils/StringUtils.java
@@ -61,7 +61,7 @@ public final class StringUtils {
private static final Logger logger = LoggerFactory.getLogger(StringUtils.class);
private static final Pattern KVP_PATTERN = Pattern.compile("([_.a-zA-Z0-9][-_.a-zA-Z0-9]*)[=](.*)"); //key value pair pattern.
- private static final Pattern INT_PATTERN = Pattern.compile("^\\d+$");
+ private static final Pattern NUM_PATTERN = Pattern.compile("^\\d+$");
private static final Pattern PARAMETERS_PATTERN = Pattern.compile("^\\[((\\s*\\{\\s*[\\w_\\-\\.]+\\s*:\\s*.+?\\s*\\}\\s*,?\\s*)+)\\s*\\]$");
private static final Pattern PAIR_PARAMETERS_PATTERN = Pattern.compile("^\\{\\s*([\\w-_\\.]+)\\s*:\\s*(.+)\\s*\\}$");
private static final int PAD_LIMIT = 8192;
@@ -535,12 +535,16 @@ public final class StringUtils {
* @param str
* @return is integer
*/
- public static boolean isInteger(String str) {
- return isNotEmpty(str) && INT_PATTERN.matcher(str).matches();
+ public static boolean isNumber(String str) {
+ return isNotEmpty(str) && NUM_PATTERN.matcher(str).matches();
}
public static int parseInteger(String str) {
- return isInteger(str) ? Integer.parseInt(str) : 0;
+ return isNumber(str) ? Integer.parseInt(str) : 0;
+ }
+
+ public static long parseLong(String str) {
+ return isNumber(str) ? Long.parseLong(str) : 0;
}
/**
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreFactoryTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreFactoryTest.java
new file mode 100644
index 0000000..65f5e28
--- /dev/null
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreFactoryTest.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.dubbo.common.cache;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URISyntaxException;
+import java.net.URL;
+import java.nio.file.Paths;
+
+public class FileCacheStoreFactoryTest {
+
+ @Test
+ public void testSafeName() throws URISyntaxException {
+ FileCacheStore store1 = FileCacheStoreFactory.getInstance(getDirectoryOfClassPath(), "../../../dubbo");
+ Assertions.assertEquals(getDirectoryOfClassPath() + File.separator + "..%002f..%002f..%002fdubbo.dubbo.cache", store1.getCacheFilePath());
+ store1.destroy();
+
+ FileCacheStore store2 = FileCacheStoreFactory.getInstance(getDirectoryOfClassPath(), "../../../中文");
+ Assertions.assertEquals(getDirectoryOfClassPath() + File.separator + "..%002f..%002f..%002f%4e2d%6587.dubbo.cache", store2.getCacheFilePath());
+ store2.destroy();
+ }
+
+ @Test
+ public void testPathIsFile() throws URISyntaxException, IOException {
+ String basePath = getDirectoryOfClassPath();
+ String filePath = basePath + File.separator + "isFile";
+ new File(filePath).createNewFile();
+
+ Assertions.assertThrows(RuntimeException.class, () -> FileCacheStoreFactory.getInstance(filePath, "dubbo"));
+ }
+
+ @Test
+ public void testCacheContains() throws URISyntaxException {
+ FileCacheStore store1 = FileCacheStoreFactory.getInstance(getDirectoryOfClassPath(), "testCacheContains");
+ Assertions.assertNotNull(store1.getCacheFilePath());
+
+ FileCacheStoreFactory.getCacheMap().remove(store1.getCacheFilePath());
+ FileCacheStore store2 = FileCacheStoreFactory.getInstance(getDirectoryOfClassPath(), "testCacheContains");
+ Assertions.assertEquals(FileCacheStore.Empty.class, store2.getClass());
+
+ store1.destroy();
+ store2.destroy();
+
+ FileCacheStore store3 = FileCacheStoreFactory.getInstance(getDirectoryOfClassPath(), "testCacheContains");
+ Assertions.assertNotNull(store3.getCacheFilePath());
+ store3.destroy();
+ }
+
+ private String getDirectoryOfClassPath() throws URISyntaxException {
+ URL resource = this.getClass().getResource("/log4j.xml");
+ String path = Paths.get(resource.toURI()).toFile().getAbsolutePath();
+ int index = path.indexOf("log4j.xml");
+ String directoryPath = path.substring(0, index);
+ return directoryPath;
+ }
+}
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreTest.java
index 9b766d0..6d8bf11 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/cache/FileCacheStoreTest.java
@@ -33,7 +33,7 @@ public class FileCacheStoreTest {
public void testCache() throws Exception {
String directoryPath = getDirectoryOfClassPath();
String filePath = "test-cache.dubbo.cache";
- cacheStore = new FileCacheStore(directoryPath, filePath);
+ cacheStore = FileCacheStoreFactory.getInstance(directoryPath, filePath);
Map<String, String> properties = cacheStore.loadCache(10);
assertEquals(2, properties.size());
@@ -42,8 +42,8 @@ public class FileCacheStoreTest {
newProperties.put("newKey2", "newValue2");
newProperties.put("newKey3", "newValue3");
newProperties.put("newKey4", "newValue4");
- cacheStore = new FileCacheStore(directoryPath, "non-exit.dubbo.cache");
- cacheStore.refreshCache(newProperties, "test refresh cache");
+ cacheStore = FileCacheStoreFactory.getInstance(directoryPath, "non-exit.dubbo.cache");
+ cacheStore.refreshCache(newProperties, "test refresh cache", 0);
Map<String, String> propertiesLimitTo2 = cacheStore.loadCache(2);
assertEquals(2, propertiesLimitTo2.size());
@@ -53,6 +53,20 @@ public class FileCacheStoreTest {
cacheStore.destroy();
}
+ @Test
+ public void testFileSizeExceed() throws Exception {
+ String directoryPath = getDirectoryOfClassPath();
+ Map<String, String> newProperties = new HashMap<>();
+ newProperties.put("newKey1", "newValue1");
+ newProperties.put("newKey2", "newValue2");
+ newProperties.put("newKey3", "newValue3");
+ newProperties.put("newKey4", "newValue4");
+ cacheStore = FileCacheStoreFactory.getInstance(directoryPath, "non-exit.dubbo.cache");
+ cacheStore.refreshCache(newProperties, "test refresh cache", 2);
+ Map<String, String> propertiesLimitTo1 = cacheStore.loadCache(2);
+ assertEquals(0, propertiesLimitTo1.size());
+ }
+
private String getDirectoryOfClassPath() throws URISyntaxException {
URL resource = this.getClass().getResource("/log4j.xml");
String path = Paths.get(resource.toURI()).toFile().getAbsolutePath();
diff --git a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java
index cd42972..043ac40 100644
--- a/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java
+++ b/dubbo-common/src/test/java/org/apache/dubbo/common/utils/StringUtilsTest.java
@@ -164,9 +164,9 @@ public class StringUtilsTest {
@Test
public void testIsInteger() throws Exception {
- assertFalse(StringUtils.isInteger(null));
- assertFalse(StringUtils.isInteger(""));
- assertTrue(StringUtils.isInteger("123"));
+ assertFalse(StringUtils.isNumber(null));
+ assertFalse(StringUtils.isNumber(""));
+ assertTrue(StringUtils.isNumber("123"));
}
@Test
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/CountTelnet.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/CountTelnet.java
index 03599f7..1064e9f 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/CountTelnet.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/CountTelnet.java
@@ -71,13 +71,13 @@ public class CountTelnet implements BaseCommand {
} else {
method = args.length > 0 ? args[0] : null;
}
- if (StringUtils.isInteger(method)) {
+ if (StringUtils.isNumber(method)) {
times = method;
method = null;
} else {
times = args.length > 2 ? args[2] : "1";
}
- if (!StringUtils.isInteger(times)) {
+ if (!StringUtils.isNumber(times)) {
return "Illegal times " + times + ", must be integer.";
}
final int t = Integer.parseInt(times);
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/PortTelnet.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/PortTelnet.java
index db7635c..a28e411 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/PortTelnet.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/PortTelnet.java
@@ -48,7 +48,7 @@ public class PortTelnet implements BaseCommand {
if ("-l".equals(part)) {
detail = true;
} else {
- if (!StringUtils.isInteger(part)) {
+ if (!StringUtils.isNumber(part)) {
return "Illegal port " + part + ", must be integer.";
}
port = part;
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SelectTelnet.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SelectTelnet.java
index f49544e..ff15ed1 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SelectTelnet.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/SelectTelnet.java
@@ -54,7 +54,7 @@ public class SelectTelnet implements BaseCommand {
if (CollectionUtils.isEmpty(methodList)) {
return "Please use the invoke command first.";
}
- if (!StringUtils.isInteger(message) || Integer.parseInt(message) < 1 || Integer.parseInt(message) > methodList.size()) {
+ if (!StringUtils.isNumber(message) || Integer.parseInt(message) < 1 || Integer.parseInt(message) > methodList.size()) {
return "Illegal index ,please input select 1~" + methodList.size();
}
Method method = methodList.get(Integer.parseInt(message) - 1);
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/ShutdownTelnet.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/ShutdownTelnet.java
index aef3983..08f268d 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/ShutdownTelnet.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/command/impl/ShutdownTelnet.java
@@ -42,7 +42,7 @@ public class ShutdownTelnet implements BaseCommand {
int sleepMilliseconds = 0;
if (args != null && args.length > 0) {
- if (args.length == 2 && "-t".equals(args[0]) && StringUtils.isInteger(args[1])) {
+ if (args.length == 2 && "-t".equals(args[0]) && StringUtils.isNumber(args[1])) {
sleepMilliseconds = Integer.parseInt(args[1]);
} else {
return "Invalid parameter,please input like shutdown -t 10000";
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java
index 3cbfc83..958c369 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/LogTelnetHandler.java
@@ -49,7 +49,7 @@ public class LogTelnetHandler implements TelnetHandler {
buf.append("EXAMPLE: log error / log 100");
} else {
String[] str = message.split(" ");
- if (!StringUtils.isInteger(str[0])) {
+ if (!StringUtils.isNumber(str[0])) {
LoggerFactory.setLevel(Level.valueOf(message.toUpperCase()));
} else {
int showLogLength = Integer.parseInt(str[0]);
diff --git a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/TraceTelnetHandler.java b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/TraceTelnetHandler.java
index 2488da4..d4d6397 100644
--- a/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/TraceTelnetHandler.java
+++ b/dubbo-plugin/dubbo-qos/src/main/java/org/apache/dubbo/qos/legacy/TraceTelnetHandler.java
@@ -54,11 +54,11 @@ public class TraceTelnetHandler implements TelnetHandler {
method = parts.length > 0 ? parts[0] : null;
times = parts.length > 1 ? parts[1] : "1";
}
- if (StringUtils.isInteger(method)) {
+ if (StringUtils.isNumber(method)) {
times = method;
method = null;
}
- if (!StringUtils.isInteger(times)) {
+ if (!StringUtils.isNumber(times)) {
return "Illegal times " + times + ", must be integer.";
}
Invoker<?> invoker = null;
diff --git a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManager.java b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManager.java
index cf013f2..6ad990c 100644
--- a/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManager.java
+++ b/dubbo-registry/dubbo-registry-api/src/main/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManager.java
@@ -17,6 +17,7 @@
package org.apache.dubbo.registry.client.metadata.store;
import org.apache.dubbo.common.cache.FileCacheStore;
+import org.apache.dubbo.common.cache.FileCacheStoreFactory;
import org.apache.dubbo.common.logger.Logger;
import org.apache.dubbo.common.logger.LoggerFactory;
import org.apache.dubbo.common.resource.Disposable;
@@ -76,7 +77,7 @@ public class MetaCacheManager implements ScopeModelAware, Disposable {
cache = new LRUCache<>(entrySize);
try {
- cacheStore = new FileCacheStore(filePath, fileName);
+ cacheStore = FileCacheStoreFactory.getInstance(filePath, fileName);
Map<String, String> properties = cacheStore.loadCache(entrySize);
logger.info("Successfully loaded meta cache from file " + fileName + ", entries " + properties.size());
for (Map.Entry<String, String> entry : properties.entrySet()) {
@@ -88,7 +89,10 @@ public class MetaCacheManager implements ScopeModelAware, Disposable {
}
// executorService can be empty if FileCacheStore fails
executorService = Executors.newSingleThreadScheduledExecutor(new NamedThreadFactory("Dubbo-cache-refresh", true));
- executorService.scheduleWithFixedDelay(new CacheRefreshTask(cacheStore, cache), 10, INTERVAL, TimeUnit.MINUTES);
+
+ String rawMaxFileSize = System.getProperty("dubbo.meta.cache.maxFileSize");
+ long maxFileSize = StringUtils.parseLong(rawMaxFileSize);
+ executorService.scheduleWithFixedDelay(new CacheRefreshTask(cacheStore, cache, maxFileSize), 10, INTERVAL, TimeUnit.MINUTES);
} catch (Exception e) {
logger.error("Load metadata from local cache file error ", e);
}
@@ -137,10 +141,12 @@ public class MetaCacheManager implements ScopeModelAware, Disposable {
protected static class CacheRefreshTask implements Runnable {
private final FileCacheStore cacheStore;
private final LRUCache<String, MetadataInfo> cache;
+ private final long maxFileSize;
- public CacheRefreshTask(FileCacheStore cacheStore, LRUCache<String, MetadataInfo> cache) {
+ public CacheRefreshTask(FileCacheStore cacheStore, LRUCache<String, MetadataInfo> cache, long maxFileSize) {
this.cacheStore = cacheStore;
this.cache = cache;
+ this.maxFileSize = maxFileSize;
}
@Override
@@ -157,7 +163,7 @@ public class MetaCacheManager implements ScopeModelAware, Disposable {
}
logger.info("Dumping meta caches, latest entries " + properties.size());
- cacheStore.refreshCache(properties, DEFAULT_COMMENT);
+ cacheStore.refreshCache(properties, DEFAULT_COMMENT, maxFileSize);
}
}
}
diff --git a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManagerTest.java b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManagerTest.java
index d039778..95db4c8 100644
--- a/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManagerTest.java
+++ b/dubbo-registry/dubbo-registry-api/src/test/java/org/apache/dubbo/registry/client/metadata/store/MetaCacheManagerTest.java
@@ -93,7 +93,7 @@ public class MetaCacheManagerTest {
cacheManager.put("3", metadataInfo3);
try {
- MetaCacheManager.CacheRefreshTask task = new MetaCacheManager.CacheRefreshTask(cacheManager.cacheStore, cacheManager.cache);
+ MetaCacheManager.CacheRefreshTask task = new MetaCacheManager.CacheRefreshTask(cacheManager.cacheStore, cacheManager.cache, 0);
task.run();
} catch (Exception e) {
fail();
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/ClearTelnetHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/ClearTelnetHandler.java
index 957d5ea..f7de70e 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/ClearTelnetHandler.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/ClearTelnetHandler.java
@@ -34,7 +34,7 @@ public class ClearTelnetHandler implements TelnetHandler {
public String telnet(Channel channel, String message) {
int lines = 100;
if (message.length() > 0) {
- if (!StringUtils.isInteger(message)) {
+ if (!StringUtils.isNumber(message)) {
return "Illegal lines " + message + ", must be integer.";
}
lines = Math.min(MAX_LINES,Integer.parseInt(message));
diff --git a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java
index 6c0167d..144fabb 100644
--- a/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java
+++ b/dubbo-remoting/dubbo-remoting-api/src/main/java/org/apache/dubbo/remoting/telnet/support/command/LogTelnetHandler.java
@@ -49,7 +49,7 @@ public class LogTelnetHandler implements TelnetHandler {
buf.append("EXAMPLE: log error / log 100");
} else {
String[] str = message.split(" ");
- if (!StringUtils.isInteger(str[0])) {
+ if (!StringUtils.isNumber(str[0])) {
LoggerFactory.setLevel(Level.valueOf(message.toUpperCase()));
} else {
int showLogLength = Integer.parseInt(str[0]);