1515 */
1616package 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 ;
1920import org .hellojavaer .ddal .ddr .expression .range .RangeExpressionItemVisitor ;
21+ import org .hellojavaer .ddal .ddr .expression .range .RangeExpressionParser ;
2022import org .hellojavaer .ddal .ddr .shard .*;
2123import org .hellojavaer .ddal .ddr .shard .exception .*;
2224import org .hellojavaer .ddal .ddr .utils .DDRStringUtils ;
3133 */
3234public 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
0 commit comments