소스 검색

Enhance file data source and flow rule manager

- Some refinement for file data source
- Add resource name checking in FlowRuleManager to avoid NPE

Signed-off-by: Eric Zhao <sczyh16@gmail.com>
master
Eric Zhao 6 년 전
부모
커밋
50a5610010
4개의 변경된 파일55개의 추가작업 그리고 28개의 파일을 삭제
  1. +6
    -0
      sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleManager.java
  2. +5
    -7
      sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/AutoRefreshDataSource.java
  3. +17
    -13
      sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/FileRefreshableDataSource.java
  4. +27
    -8
      sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/FileWritableDataSource.java

+ 6
- 0
sentinel-core/src/main/java/com/alibaba/csp/sentinel/slots/block/flow/FlowRuleManager.java 파일 보기

@@ -110,6 +110,9 @@ public class FlowRuleManager {
}

for (FlowRule rule : list) {
if (!isValid(rule)) {
continue;
}
if (StringUtil.isBlank(rule.getLimitApp())) {
rule.setLimitApp(FlowRule.LIMIT_APP_DEFAULT);
}
@@ -199,4 +202,7 @@ public class FlowRuleManager {

}

private static boolean isValid(FlowRule rule) {
return rule != null && !StringUtil.isBlank(rule.getResource());
}
}

+ 5
- 7
sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/AutoRefreshDataSource.java 파일 보기

@@ -25,10 +25,8 @@ import com.alibaba.csp.sentinel.log.RecordLog;
/**
* A {@link ReadableDataSource} automatically fetches the backend data.
*
* @param <S>
* source data type
* @param <T>
* target data type
* @param <S> source data type
* @param <T> target data type
* @author Carpenter Lee
*/
public abstract class AutoRefreshDataSource<S, T> extends AbstractDataSource<S, T> {
@@ -52,12 +50,12 @@ public abstract class AutoRefreshDataSource<S, T> extends AbstractDataSource<S,

private void startTimerService() {
service = Executors.newScheduledThreadPool(1,
new NamedThreadFactory("sentinel-datasource-auto-refresh-task", true));
new NamedThreadFactory("sentinel-datasource-auto-refresh-task", true));
service.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
if (!refresh()) {
if (!isModified()) {
return;
}
T newValue = loadConfig();
@@ -77,7 +75,7 @@ public abstract class AutoRefreshDataSource<S, T> extends AbstractDataSource<S,
}
}

protected boolean refresh() {
protected boolean isModified() {
return true;
}
}

+ 17
- 13
sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/FileRefreshableDataSource.java 파일 보기

@@ -26,7 +26,7 @@ import com.alibaba.csp.sentinel.log.RecordLog;
/**
* <p>
* A {@link ReadableDataSource} based on file. This class will automatically
* fetches the backend file every refresh period.
* fetches the backend file every isModified period.
* </p>
* <p>
* Limitations: Default read buffer size is 1 MB. If file size is greater than
@@ -46,16 +46,15 @@ public class FileRefreshableDataSource<T> extends AutoRefreshDataSource<String,
private byte[] buf;
private final Charset charset;
private final File file;

private long lastModified = 0L;

/**
* Create a file based {@link ReadableDataSource} whose read buffer size is
* 1MB, charset is UTF8, and read interval is 3 seconds.
*
* @param file
* the file to read
* @param configParser
* the config decoder (parser)
* @param file the file to read
* @param configParser the config decoder (parser)
*/
public FileRefreshableDataSource(File file, Converter<String, T> configParser) throws FileNotFoundException {
this(file, configParser, DEFAULT_REFRESH_MS, DEFAULT_BUF_SIZE, DEFAULT_CHAR_SET);
@@ -66,23 +65,23 @@ public class FileRefreshableDataSource<T> extends AutoRefreshDataSource<String,
}

public FileRefreshableDataSource(File file, Converter<String, T> configParser, int bufSize)
throws FileNotFoundException {
throws FileNotFoundException {
this(file, configParser, DEFAULT_REFRESH_MS, bufSize, DEFAULT_CHAR_SET);
}

public FileRefreshableDataSource(File file, Converter<String, T> configParser, Charset charset)
throws FileNotFoundException {
throws FileNotFoundException {
this(file, configParser, DEFAULT_REFRESH_MS, DEFAULT_BUF_SIZE, charset);
}

public FileRefreshableDataSource(File file, Converter<String, T> configParser, long recommendRefreshMs, int bufSize,
Charset charset) throws FileNotFoundException {
Charset charset) throws FileNotFoundException {
super(configParser, recommendRefreshMs);
if (bufSize <= 0 || bufSize > MAX_SIZE) {
throw new IllegalArgumentException("bufSize must between (0, " + MAX_SIZE + "], but " + bufSize + " get");
}
if (file == null) {
throw new IllegalArgumentException("file can't be null");
if (file == null || file.isDirectory()) {
throw new IllegalArgumentException("File can't be null or a directory");
}
if (charset == null) {
throw new IllegalArgumentException("charset can't be null");
@@ -90,6 +89,7 @@ public class FileRefreshableDataSource<T> extends AutoRefreshDataSource<String,
this.buf = new byte[bufSize];
this.file = file;
this.charset = charset;
// If the file does not exist, the last modified will be 0.
this.lastModified = file.lastModified();
firstLoad();
}
@@ -105,13 +105,17 @@ public class FileRefreshableDataSource<T> extends AutoRefreshDataSource<String,

@Override
public String readSource() throws Exception {
if (!file.exists()) {
// Will throw FileNotFoundException later.
RecordLog.warn(String.format("[FileRefreshableDataSource] File does not exist: %s", file.getAbsolutePath()));
}
FileInputStream inputStream = null;
try {
inputStream = new FileInputStream(file);
FileChannel channel = inputStream.getChannel();
if (channel.size() > buf.length) {
throw new IllegalStateException(file.getAbsolutePath() + " file size=" + channel.size()
+ ", is bigger than bufSize=" + buf.length + ". Can't read");
+ ", is bigger than bufSize=" + buf.length + ". Can't read");
}
int len = inputStream.read(buf);
return new String(buf, 0, len, charset);
@@ -126,8 +130,8 @@ public class FileRefreshableDataSource<T> extends AutoRefreshDataSource<String,
}

@Override
protected boolean refresh() {
long curLastModified = new File(file.getAbsolutePath()).lastModified();
protected boolean isModified() {
long curLastModified = file.lastModified();
if (curLastModified != this.lastModified) {
this.lastModified = curLastModified;
return true;


+ 27
- 8
sentinel-extension/sentinel-datasource-extension/src/main/java/com/alibaba/csp/sentinel/datasource/FileWritableDataSource.java 파일 보기

@@ -17,46 +17,63 @@ package com.alibaba.csp.sentinel.datasource;

import java.io.File;
import java.io.FileOutputStream;
import java.nio.charset.Charset;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import com.alibaba.csp.sentinel.log.RecordLog;

/**
* A {@link WritableDataSource} based on file.
*
* @param <T>
* data type
* @param <T> data type
* @author Eric Zhao
* @since 0.2.0
*/
public class FileWritableDataSource<T> implements WritableDataSource<T> {

private static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");

private final Converter<T, String> configEncoder;
private File file;
private final File file;
private final Charset charset;

private final Lock lock = new ReentrantLock(true);

public FileWritableDataSource(String filePath, Converter<T, String> configEncoder) {
this(new File(filePath), configEncoder);
}

public FileWritableDataSource(File file, Converter<T, String> configEncoder) {
this(file, configEncoder, DEFAULT_CHARSET);
}

public FileWritableDataSource(File file, Converter<T, String> configEncoder, Charset charset) {
if (file == null || file.isDirectory()) {
throw new IllegalArgumentException("Bad file");
}
if (configEncoder == null) {
throw new IllegalArgumentException("Config encoder cannot be null");
}
if (charset == null) {
throw new IllegalArgumentException("Charset cannot be null");
}
this.configEncoder = configEncoder;
this.file = file;
this.charset = charset;
}

@Override
public void write(T value) throws Exception {
if (configEncoder == null) {
throw new NullPointerException("configEncoder is null Can't write");
}
synchronized (file) {
lock.lock();
try {
String convertResult = configEncoder.convert(value);
FileOutputStream outputStream = null;
try {
outputStream = new FileOutputStream(file);
byte[] bytesArray = convertResult.getBytes();
byte[] bytesArray = convertResult.getBytes(charset);

RecordLog.info(String.format("[FileWritableDataSource] Writing to file %s: %s", file.toString(), convertResult));
outputStream.write(bytesArray);
outputStream.flush();
} finally {
@@ -68,6 +85,8 @@ public class FileWritableDataSource<T> implements WritableDataSource<T> {
}
}
}
} finally {
lock.unlock();
}
}



Loading…
취소
저장