Skip to content

Commit 47178b2

Browse files
authored
Merge pull request #51 from hellojavaer/1.0.x
1.0.x
2 parents 5b6eff2 + 6697617 commit 47178b2

File tree

5 files changed

+183
-57
lines changed

5 files changed

+183
-57
lines changed

ddal-ddr/src/main/java/org/hellojavaer/ddal/ddr/datasource/manager/rw/DefaultReadWriteDataSourceManager.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ public class DefaultReadWriteDataSourceManager implements ReadWriteDataSourceMan
7676
private boolean initialized = false;
7777

7878
// cache
79-
private Map<String, Set<String>> physicalTables = null;
79+
private volatile Map<String, Set<String>> physicalTables = null;
8080

8181
private DefaultReadWriteDataSourceManager() {
8282
this.metaDataChecker = new DefaultMetaDataChecker("mysql");
@@ -565,7 +565,15 @@ private void check(Connection conn, String scName) {
565565
return;
566566
}
567567
Map<String, Set<String>> physicalTables = getPhysicalTables();
568-
metaDataChecker.check(conn, scName, physicalTables.get(scName));
568+
if (physicalTables != null) {
569+
Set<String> tbNames = physicalTables.get(scName);
570+
if (tbNames != null && !tbNames.isEmpty()) {
571+
metaDataChecker.check(conn, scName, tbNames);
572+
if (stdLogger.isInfoEnabled()) {
573+
stdLogger.info("MetaDataCheck - sc:{}, tb:{} meta data checking is passed", scName, tbNames);
574+
}
575+
}
576+
}
569577
}
570578

571579
private void initWriteOnlyDataSource(List<WriteOnlyDataSourceBinding> bindings) {

ddal-ddr/src/main/java/org/hellojavaer/ddal/ddr/shard/simple/SimpleShardRouter.java

Lines changed: 169 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,10 @@
1515
*/
1616
package org.hellojavaer.ddal.ddr.shard.simple;
1717

18-
import org.hellojavaer.ddal.ddr.expression.range.RangeExpressionParser;
18+
import com.googlecode.concurrentlinkedhashmap.ConcurrentLinkedHashMap;
19+
import com.googlecode.concurrentlinkedhashmap.Weighers;
1920
import org.hellojavaer.ddal.ddr.expression.range.RangeExpressionItemVisitor;
21+
import org.hellojavaer.ddal.ddr.expression.range.RangeExpressionParser;
2022
import org.hellojavaer.ddal.ddr.shard.*;
2123
import org.hellojavaer.ddal.ddr.shard.exception.*;
2224
import org.hellojavaer.ddal.ddr.utils.DDRStringUtils;
@@ -31,11 +33,21 @@
3133
*/
3234
public class SimpleShardRouter implements ShardRouter {
3335

34-
private Logger logger = LoggerFactory.getLogger(getClass());
35-
private List<SimpleShardRouteRuleBinding> routeRuleBindings = null;
36-
private Map<String, InnerSimpleShardRouteRuleBindingWrapper> cache = Collections.EMPTY_MAP;
37-
private Map<String, List<ShardRouteInfo>> routeInfoMap = new HashMap<>();
38-
private Map<String, Set<String>> routedTables = new HashMap<>();
36+
private Logger logger = LoggerFactory.getLogger(getClass());
37+
38+
// schema+table级路由配置
39+
private List<SimpleShardRouteRuleBinding> routeRuleBindings = null;
40+
private Map<String, InnerSimpleShardRouteRuleBindingWrapper> routeInfoCache = Collections.EMPTY_MAP;
41+
private Map<String, List<ShardRouteInfo>> routeInfosCache = new HashMap<>();
42+
private Map<String, Set<String>> routedTables = new HashMap<>();
43+
44+
// schema级路由配置
45+
private Map<String, SimpleShardRouteRuleBinding> schemaBindingMap = new HashMap<>();
46+
private SimpleShardRouteRuleBinding defaultSchemaBinding = null;
47+
private Map<String, List<ShardRouteInfo>> routeInfosCacheForSchemaLevel = new ConcurrentLinkedHashMap.Builder<String, List<ShardRouteInfo>>()//
48+
.maximumWeightedCapacity(10000)//
49+
.weigher(Weighers.singleton())//
50+
.build();
3951

4052
private SimpleShardRouter() {
4153
}
@@ -63,47 +75,62 @@ public void setRouteRuleBindings(List<SimpleShardRouteRuleBinding> bindings) {
6375
if (scName == null) {
6476
throw new IllegalArgumentException("'scName' can't be empty");
6577
}
66-
if (tbName == null) {
67-
throw new IllegalArgumentException("'tbName' can't be empty");
68-
}
69-
final SimpleShardRouteRuleBinding b0 = new SimpleShardRouteRuleBinding();
70-
b0.setScName(scName);
71-
b0.setTbName(tbName);
72-
b0.setSdKey(sdKey);
73-
b0.setRule(binding.getRule());
74-
StringBuilder sb = new StringBuilder();
75-
sb.append(scName).append('.').append(tbName);
76-
putToCache(cache, sb.toString(), b0, true);
77-
putToCache(cache, tbName, b0, false);
78-
79-
final Set<ShardRouteInfo> routeInfos = new LinkedHashSet<>();
80-
if (sdValues != null) {
81-
new RangeExpressionParser(sdValues).visit(new RangeExpressionItemVisitor() {
78+
if (tbName != null) {
79+
final SimpleShardRouteRuleBinding b0 = new SimpleShardRouteRuleBinding();
80+
b0.setScName(scName);
81+
b0.setTbName(tbName);
82+
b0.setSdKey(sdKey);
83+
b0.setRule(binding.getRule());
84+
StringBuilder sb = new StringBuilder();
85+
sb.append(scName).append('.').append(tbName);
86+
putToCache(cache, sb.toString(), b0, true);
87+
putToCache(cache, tbName, b0, false);
8288

83-
@Override
84-
public void visit(Object val) {
85-
ShardRouteInfo routeInfo = getRouteInfo(b0, scName, tbName, val);
86-
routeInfos.add(routeInfo);
89+
// 构建 逻辑sc+逻辑tb下包含的所有物理表信息
90+
final Set<ShardRouteInfo> routeInfos = new LinkedHashSet<>();
91+
if (binding.getRule() == null) {// 如果路由规则为空,则使用原表名
92+
ShardRouteInfo routeInfo = new ShardRouteInfo();
93+
routeInfo.setScName(scName);
94+
routeInfo.setTbName(tbName);
95+
routeInfos.add(routeInfo);
96+
} else {
97+
if (sdValues != null) {
98+
new RangeExpressionParser(sdValues).visit(new RangeExpressionItemVisitor() {
99+
100+
@Override
101+
public void visit(Object val) {
102+
ShardRouteInfo routeInfo = getRouteInfo(b0, scName, tbName, val);
103+
routeInfos.add(routeInfo);
104+
}
105+
});
87106
}
88-
});
89-
}
90-
String key = buildQueryKey(scName, tbName);
91-
if (routeInfoMap.containsKey(key)) {
92-
throw new IllegalArgumentException("Duplicate route config for table '" + key + "'");
93-
} else {
94-
Set<String> tables = routedTables.get(scName);
95-
if (tables == null) {
96-
tables = new LinkedHashSet<>();
97-
routedTables.put(scName, tables);
98107
}
99-
tables.add(tbName);
100-
routeInfoMap.put(key, new ArrayList(routeInfos));
108+
String key = buildQueryKey(scName, tbName);
109+
if (routeInfoMap.containsKey(key)) {
110+
throw new IllegalArgumentException("Duplicate route config for table '" + key + "'");
111+
} else {
112+
Set<String> tables = routedTables.get(scName);
113+
if (tables == null) {
114+
tables = new LinkedHashSet<>();
115+
routedTables.put(scName, tables);
116+
}
117+
tables.add(tbName);
118+
routeInfoMap.put(key, new ArrayList(routeInfos));
119+
}
120+
} else {// 配置schema级别路由规则
121+
if (defaultSchemaBinding == null) {// 使用列表中的第一个作为默认配置
122+
defaultSchemaBinding = binding;
123+
}
124+
if (schemaBindingMap.put(scName, binding) != null) {
125+
throw new DuplicateRouteRuleBindingException("Duplicate route rule binding for scName:"
126+
+ scName);
127+
}
101128
}
102129
}
103130
}
104131
this.routeRuleBindings = bindings;
105-
this.cache = cache;
106-
this.routeInfoMap = routeInfoMap;
132+
this.routeInfoCache = cache;
133+
this.routeInfosCache = routeInfoMap;
107134
this.routedTables = routedTables;
108135
}
109136

@@ -164,7 +191,7 @@ private InnerSimpleShardRouteRuleBindingWrapper getBinding(String scName, String
164191
if (scName != null) {
165192
queryKey = new StringBuilder().append(scName).append('.').append(tbName).toString();
166193
}
167-
InnerSimpleShardRouteRuleBindingWrapper ruleBindingWrapper = cache.get(queryKey);
194+
InnerSimpleShardRouteRuleBindingWrapper ruleBindingWrapper = routeInfoCache.get(queryKey);
168195
if (ruleBindingWrapper == null) {
169196
return null;
170197
} else if (ruleBindingWrapper.getConflictSchemas().size() > 1) {
@@ -179,23 +206,47 @@ private InnerSimpleShardRouteRuleBindingWrapper getBinding(String scName, String
179206
public ShardRouteRule getRouteRule(String scName, String tbName) {
180207
scName = DDRStringUtils.toLowerCase(scName);
181208
tbName = DDRStringUtils.toLowerCase(tbName);
209+
if (tbName == null) {
210+
throw new IllegalArgumentException("tbName can't be null");
211+
}
182212
InnerSimpleShardRouteRuleBindingWrapper bindingWrapper = getBinding(scName, tbName);
183-
if (bindingWrapper == null || bindingWrapper.getRuleBinding() == null) {
184-
return null;
185-
} else {
186-
return bindingWrapper.getRuleBinding().getRule();
213+
if (bindingWrapper != null) {// 1.从schema+table级中获取
214+
if (bindingWrapper.getRuleBinding() != null) {
215+
return bindingWrapper.getRuleBinding().getRule();
216+
} else {
217+
return null;
218+
}
219+
} else {// 2.从schema级别获取
220+
SimpleShardRouteRuleBinding binding = getRouteRuleBindingBySchemaLevel(scName);
221+
if (binding != null) {
222+
return binding.getRule();
223+
} else {
224+
return null;
225+
}
187226
}
188227
}
189228

190229
@Override
191230
public ShardRouteConfig getRouteConfig(String scName, String tbName) {
192231
scName = DDRStringUtils.toLowerCase(scName);
193232
tbName = DDRStringUtils.toLowerCase(tbName);
233+
if (tbName == null) {
234+
throw new IllegalArgumentException("tbName can't be null");
235+
}
194236
InnerSimpleShardRouteRuleBindingWrapper bindingWrapper = getBinding(scName, tbName);
195-
if (bindingWrapper == null) {
196-
return null;
197-
} else {
237+
if (bindingWrapper != null) {// 1.从schema+table级中获取
198238
return bindingWrapper.getRouteConfig();
239+
} else {// 2.从schema级别获取
240+
SimpleShardRouteRuleBinding binding = getRouteRuleBindingBySchemaLevel(scName);
241+
if (binding == null) {
242+
return null;
243+
} else {
244+
ShardRouteConfig config = new ShardRouteConfig();
245+
config.setScName(binding.getScName());
246+
config.setTbName(tbName);// note here
247+
config.setSdKey(binding.getSdKey());
248+
return config;
249+
}
199250
}
200251
}
201252

@@ -205,20 +256,86 @@ public ShardRouteInfo getRouteInfo(String scName, String tbName, Object sdValue)
205256
ShardRouteException {
206257
scName = DDRStringUtils.toLowerCase(scName);
207258
tbName = DDRStringUtils.toLowerCase(tbName);
259+
if (tbName == null) {
260+
throw new IllegalArgumentException("tbName can't be null");
261+
}
262+
SimpleShardRouteRuleBinding binding = null;
208263
InnerSimpleShardRouteRuleBindingWrapper bindingWrapper = getBinding(scName, tbName);
209-
SimpleShardRouteRuleBinding binding = bindingWrapper.getRuleBinding();
264+
if (bindingWrapper != null) {// 1.从schema+table级中获取
265+
binding = bindingWrapper.getRuleBinding();
266+
} else {// 2.从schema级获取
267+
binding = getRouteRuleBindingBySchemaLevel(scName);
268+
}
210269
if (binding == null) {
211270
return null;
212-
} else {// 必须使用 binding 中的 scName,因为sql中的scName可能为空
213-
ShardRouteInfo info = getRouteInfo(binding, binding.getScName(), binding.getTbName(), sdValue);
271+
} else {// 必须使用binding中的scName,因为sql中的scName可能为空,binding.getTbName()可能为null必须使用tbName
272+
ShardRouteInfo info = getRouteInfo(binding, binding.getScName(), tbName, sdValue);
214273
return info;
215274
}
216275
}
217276

277+
/**
278+
*
279+
* @param scName can be null
280+
* @param tbName can't be null
281+
* @return if sdValues is null or scName-tbName don't hit config return null
282+
* @throws ShardValueNotFoundException
283+
* @throws ShardRouteException
284+
*/
218285
@Override
219286
public List<ShardRouteInfo> getRouteInfos(String scName, String tbName) throws ShardValueNotFoundException,
220287
ShardRouteException {
221-
return routeInfoMap.get(buildQueryKey(scName, tbName));
288+
scName = DDRStringUtils.toLowerCase(scName);
289+
tbName = DDRStringUtils.toLowerCase(tbName);
290+
if (tbName == null) {
291+
throw new IllegalArgumentException("tbName can't be null");
292+
}
293+
List<ShardRouteInfo> result = routeInfosCache.get(buildQueryKey(scName, tbName));
294+
if (result != null) {
295+
return result;
296+
} else {// 查询schema配置级别
297+
SimpleShardRouteRuleBinding binding = getRouteRuleBindingBySchemaLevel(scName);
298+
if (binding == null) {
299+
return null;
300+
} else {
301+
String key = buildQueryKey(binding.getScName(), tbName);
302+
String sdValues = binding.getSdValues();
303+
if (sdValues != null) {
304+
List<ShardRouteInfo> list = routeInfosCacheForSchemaLevel.get(key);
305+
if (list == null) {
306+
final List<ShardRouteInfo> routeInfos = new ArrayList<>();
307+
final String scName0 = scName;
308+
final String tbName0 = tbName;
309+
new RangeExpressionParser(sdValues).visit(new RangeExpressionItemVisitor() {
310+
311+
@Override
312+
public void visit(Object val) {
313+
ShardRouteInfo routeInfo = getRouteInfo(scName0, tbName0, val);
314+
routeInfos.add(routeInfo);
315+
}
316+
});
317+
routeInfosCacheForSchemaLevel.put(key, routeInfos);
318+
list = routeInfos;
319+
}
320+
return list;
321+
} else {
322+
return null;
323+
}
324+
}
325+
}
326+
}
327+
328+
/**
329+
*
330+
* @param scName can be null
331+
* @return
332+
*/
333+
private SimpleShardRouteRuleBinding getRouteRuleBindingBySchemaLevel(String scName) {
334+
if (scName != null) {
335+
return schemaBindingMap.get(scName);
336+
} else {
337+
return defaultSchemaBinding;
338+
}
222339
}
223340

224341
@Override

ddal-example/ddal-example-example0/src/main/resources/datasource.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
<list>
3232
<bean class="org.hellojavaer.ddal.ddr.shard.simple.SimpleShardRouteRuleBinding">
3333
<property name="scName" value="base"></property>
34-
<property name="tbName" value="user"></property>
34+
<!--<property name="tbName" value="user"></property>-->
3535
<property name="rule" ref="idRule"></property>
3636
<property name="sdKey" value="id"></property>
3737
<property name="sdValues" value="[0..7]"></property>

ddal-example/ddal-example-example0/src/main/resources/log4j.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616
<logger name="org.hellojavaer.ddr.ds" additivity="false">
1717
<!-- if the value of 'value' is 'trace', target datasource will be printed out -->
18-
<priority value="error"/>
18+
<priority value="info"/>
1919
<appender-ref ref="console"/>
2020
</logger>
2121

ddal-example/ddal-example-example1/src/main/resources/datasource.xml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
<list>
2828
<bean class="org.hellojavaer.ddal.ddr.shard.simple.SimpleShardRouteRuleBinding">
2929
<property name="scName" value="acl"></property>
30-
<property name="tbName" value="role"></property>
30+
<!--<property name="tbName" value="role"></property>-->
3131
</bean>
3232
</list>
3333
</property>
@@ -45,6 +45,7 @@
4545
</bean>
4646
<bean id="dataSourceManager"
4747
class="org.hellojavaer.ddal.ddr.datasource.manager.rw.DefaultReadWriteDataSourceManager">
48+
<property name="shardRouter" ref="shardRouter"/>
4849
<property name="readOnlyDataSourceMonitorServer">
4950
<bean class="org.hellojavaer.ddal.ddr.datasource.manager.rw.monitor.mbean.MBeanReadOnlyDataSourceMonitorServer"></bean>
5051
</property>

0 commit comments

Comments
 (0)