Skip to content

Commit

Permalink
bugfix: configuration cache get value cast exception. (apache#3293)
Browse files Browse the repository at this point in the history
  • Loading branch information
jsbxyyx committed Dec 16, 2020
1 parent aeeda42 commit 6075716
Show file tree
Hide file tree
Showing 5 changed files with 176 additions and 15 deletions.
16 changes: 16 additions & 0 deletions common/src/test/java/io/seata/common/BranchDO.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed 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 io.seata.common;

import java.util.Date;
Expand Down
16 changes: 16 additions & 0 deletions common/src/test/java/io/seata/common/rpc/RpcStatusTest.java
Original file line number Diff line number Diff line change
@@ -1,3 +1,19 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed 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 io.seata.common.rpc;

import org.junit.jupiter.api.Assertions;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.seata.config;

import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import io.seata.common.util.DurationUtil;
import io.seata.common.util.StringUtils;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
Expand All @@ -32,7 +36,7 @@ public class ConfigurationCache implements ConfigurationChangeListener {

private static final String METHOD_LATEST_CONFIG = METHOD_PREFIX + "LatestConfig";

private static final ConcurrentHashMap<String, Object> CONFIG_CACHE = new ConcurrentHashMap<>();
private static final ConcurrentHashMap<String, ObjectWrapper> CONFIG_CACHE = new ConcurrentHashMap<>();

private Map<String, HashSet<ConfigurationChangeListener>> configListenersMap = new HashMap<>();

Expand Down Expand Up @@ -64,33 +68,42 @@ public static ConfigurationCache getInstance() {

@Override
public void onChangeEvent(ConfigurationChangeEvent event) {
Object oldValue = CONFIG_CACHE.get(event.getDataId());
if (null == oldValue || !oldValue.equals(event.getNewValue())) {
if (StringUtils.isNotBlank(event.getNewValue())) {
CONFIG_CACHE.put(event.getDataId(), event.getNewValue());
ObjectWrapper wrapper = CONFIG_CACHE.get(event.getDataId());
// The wrapper.data only exists in the cache when it is not null.
if (StringUtils.isNotBlank(event.getNewValue())) {
if (wrapper == null) {
CONFIG_CACHE.put(event.getDataId(), new ObjectWrapper(event.getNewValue(), null));
} else {
CONFIG_CACHE.remove(event.getDataId());
Object newValue = new ObjectWrapper(event.getNewValue(), null).convertData(wrapper.getType());
if (!Objects.equals(wrapper.getData(), newValue)) {
CONFIG_CACHE.put(event.getDataId(), new ObjectWrapper(newValue, wrapper.getType()));
}
}
} else {
CONFIG_CACHE.remove(event.getDataId());
}
}

public Configuration proxy(Configuration originalConfiguration) {
return (Configuration)Enhancer.create(Configuration.class,
(MethodInterceptor)(proxy, method, args, methodProxy) -> {
if (method.getName().startsWith(METHOD_PREFIX)
&& !method.getName().equalsIgnoreCase(METHOD_LATEST_CONFIG)) {
&& !method.getName().equalsIgnoreCase(METHOD_LATEST_CONFIG)) {
String rawDataId = (String)args[0];
Object result = CONFIG_CACHE.get(rawDataId);
if (null == result) {
result = method.invoke(originalConfiguration, args);
ObjectWrapper wrapper = CONFIG_CACHE.get(rawDataId);
String type = method.getName().substring(METHOD_PREFIX.length());
if (!ObjectWrapper.supportType(type)) {
type = null;
}
if (null == wrapper) {
Object result = method.invoke(originalConfiguration, args);
// The wrapper.data only exists in the cache when it is not null.
if (result != null) {
CONFIG_CACHE.put(rawDataId, result);
wrapper = new ObjectWrapper(result, type);
CONFIG_CACHE.put(rawDataId, wrapper);
}
}
if (null != result && method.getReturnType().equals(String.class)) {
return String.valueOf(result);
}
return result;
return wrapper == null ? null : wrapper.convertData(type);
}
return method.invoke(originalConfiguration, args);
});
Expand All @@ -103,4 +116,59 @@ private static class ConfigurationCacheInstance {
public void clear() {
CONFIG_CACHE.clear();
}

private static class ObjectWrapper {

static final String INT = "Int";
static final String BOOLEAN = "Boolean";
static final String DURATION = "Duration";
static final String LONG = "Long";
static final String SHORT = "Short";

private final Object data;
private final String type;

ObjectWrapper(Object data, String type) {
this.data = data;
this.type = type;
}

public Object getData() {
return data;
}

public String getType() {
return type;
}

public Object convertData(String aType) {
if (data != null && Objects.equals(type, aType)) {
return data;
}
if (data != null) {
if (INT.equals(aType)) {
return Integer.parseInt(data.toString());
} else if (BOOLEAN.equals(aType)) {
return Boolean.parseBoolean(data.toString());
} else if (DURATION.equals(aType)) {
return DurationUtil.parse(data.toString());
} else if (LONG.equals(aType)) {
return Long.parseLong(data.toString());
} else if (SHORT.equals(aType)) {
return Short.parseShort(data.toString());
}
return String.valueOf(data);
}
return null;
}

public static boolean supportType(String type) {
return INT.equalsIgnoreCase(type)
|| BOOLEAN.equalsIgnoreCase(type)
|| DURATION.equalsIgnoreCase(type)
|| LONG.equalsIgnoreCase(type)
|| SHORT.equalsIgnoreCase(type);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* Licensed 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 io.seata.config;

import io.seata.common.util.DurationUtil;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import java.time.Duration;

/**
* @author jsbxyyx
*/
public class ConfigurationCacheTests {

@Test
public void testChangeValue() throws Exception {
Configuration configuration = new FileConfiguration("registry");
configuration = ConfigurationCache.getInstance().proxy(configuration);
configuration.getBoolean("aaa", false);
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("aaa", "true"));
boolean aaa = configuration.getBoolean("aaa", false);
Assertions.assertTrue(aaa);

configuration.getShort("bbb", (short) 0);
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("bbb", "1"));
short bbb = configuration.getShort("bbb", (short) 0);
Assertions.assertEquals((short) 1, bbb);

configuration.getDuration("ccc", Duration.ZERO);
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("ccc", "1s"));
Duration ccc = configuration.getDuration("ccc", Duration.ZERO);
Assertions.assertEquals(ccc, DurationUtil.parse("1s"));

configuration.getInt("ddd", 0);
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("ddd", "1"));
int ddd = configuration.getInt("ddd", 0);
Assertions.assertEquals(1, ddd);

configuration.getLong("eee", 0);
ConfigurationCache.getInstance().onChangeEvent(new ConfigurationChangeEvent("eee", "1"));
long eee = configuration.getLong("eee", 0);
Assertions.assertEquals((long) 1, eee);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.seata.rm.datasource.undo.h2.keyword;

import io.seata.common.loader.LoadLevel;
Expand Down

0 comments on commit 6075716

Please sign in to comment.