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,54 @@ 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+ final Set <ShardRouteInfo > routeInfos = new LinkedHashSet <>();
90+ if (sdValues != null ) {
91+ new RangeExpressionParser (sdValues ).visit (new RangeExpressionItemVisitor () {
92+
93+ @ Override
94+ public void visit (Object val ) {
95+ ShardRouteInfo routeInfo = getRouteInfo (b0 , scName , tbName , val );
96+ routeInfos .add (routeInfo );
97+ }
98+ });
99+ }
100+ String key = buildQueryKey (scName , tbName );
101+ if (routeInfoMap .containsKey (key )) {
102+ throw new IllegalArgumentException ("Duplicate route config for table '" + key + "'" );
103+ } else {
104+ Set <String > tables = routedTables .get (scName );
105+ if (tables == null ) {
106+ tables = new LinkedHashSet <>();
107+ routedTables .put (scName , tables );
87108 }
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 );
109+ tables . add ( tbName );
110+ routeInfoMap . put ( key , new ArrayList ( routeInfos ));
111+ }
112+ } else { // 配置schema级别路由规则
113+ if ( defaultSchemaBinding == null ) { // 使用列表中的第一个作为默认配置
114+ defaultSchemaBinding = binding ;
115+ }
116+ if (schemaBindingMap . put ( scName , binding ) ! = null ) {
117+ throw new DuplicateRouteRuleBindingException ( "Duplicate route rule binding for scName:"
118+ + scName );
98119 }
99- tables .add (tbName );
100- routeInfoMap .put (key , new ArrayList (routeInfos ));
101120 }
102121 }
103122 }
104123 this .routeRuleBindings = bindings ;
105- this .cache = cache ;
106- this .routeInfoMap = routeInfoMap ;
124+ this .routeInfoCache = cache ;
125+ this .routeInfosCache = routeInfoMap ;
107126 this .routedTables = routedTables ;
108127 }
109128
@@ -164,7 +183,7 @@ private InnerSimpleShardRouteRuleBindingWrapper getBinding(String scName, String
164183 if (scName != null ) {
165184 queryKey = new StringBuilder ().append (scName ).append ('.' ).append (tbName ).toString ();
166185 }
167- InnerSimpleShardRouteRuleBindingWrapper ruleBindingWrapper = cache .get (queryKey );
186+ InnerSimpleShardRouteRuleBindingWrapper ruleBindingWrapper = routeInfoCache .get (queryKey );
168187 if (ruleBindingWrapper == null ) {
169188 return null ;
170189 } else if (ruleBindingWrapper .getConflictSchemas ().size () > 1 ) {
@@ -179,23 +198,47 @@ private InnerSimpleShardRouteRuleBindingWrapper getBinding(String scName, String
179198 public ShardRouteRule getRouteRule (String scName , String tbName ) {
180199 scName = DDRStringUtils .toLowerCase (scName );
181200 tbName = DDRStringUtils .toLowerCase (tbName );
201+ if (tbName == null ) {
202+ throw new IllegalArgumentException ("tbName can't be null" );
203+ }
182204 InnerSimpleShardRouteRuleBindingWrapper bindingWrapper = getBinding (scName , tbName );
183- if (bindingWrapper == null || bindingWrapper .getRuleBinding () == null ) {
184- return null ;
185- } else {
186- return bindingWrapper .getRuleBinding ().getRule ();
205+ if (bindingWrapper != null ) {// 1.从schema+table级中获取
206+ if (bindingWrapper .getRuleBinding () != null ) {
207+ return bindingWrapper .getRuleBinding ().getRule ();
208+ } else {
209+ return null ;
210+ }
211+ } else {// 2.从schema级别获取
212+ SimpleShardRouteRuleBinding binding = getRouteRuleBindingBySchemaLevel (scName );
213+ if (binding != null ) {
214+ return binding .getRule ();
215+ } else {
216+ return null ;
217+ }
187218 }
188219 }
189220
190221 @ Override
191222 public ShardRouteConfig getRouteConfig (String scName , String tbName ) {
192223 scName = DDRStringUtils .toLowerCase (scName );
193224 tbName = DDRStringUtils .toLowerCase (tbName );
225+ if (tbName == null ) {
226+ throw new IllegalArgumentException ("tbName can't be null" );
227+ }
194228 InnerSimpleShardRouteRuleBindingWrapper bindingWrapper = getBinding (scName , tbName );
195- if (bindingWrapper == null ) {
196- return null ;
197- } else {
229+ if (bindingWrapper != null ) {// 1.从schema+table级中获取
198230 return bindingWrapper .getRouteConfig ();
231+ } else {// 2.从schema级别获取
232+ SimpleShardRouteRuleBinding binding = getRouteRuleBindingBySchemaLevel (scName );
233+ if (binding == null ) {
234+ return null ;
235+ } else {
236+ ShardRouteConfig config = new ShardRouteConfig ();
237+ config .setScName (binding .getScName ());
238+ config .setTbName (tbName );// note here
239+ config .setSdKey (binding .getSdKey ());
240+ return config ;
241+ }
199242 }
200243 }
201244
@@ -205,20 +248,86 @@ public ShardRouteInfo getRouteInfo(String scName, String tbName, Object sdValue)
205248 ShardRouteException {
206249 scName = DDRStringUtils .toLowerCase (scName );
207250 tbName = DDRStringUtils .toLowerCase (tbName );
251+ if (tbName == null ) {
252+ throw new IllegalArgumentException ("tbName can't be null" );
253+ }
254+ SimpleShardRouteRuleBinding binding = null ;
208255 InnerSimpleShardRouteRuleBindingWrapper bindingWrapper = getBinding (scName , tbName );
209- SimpleShardRouteRuleBinding binding = bindingWrapper .getRuleBinding ();
256+ if (bindingWrapper != null ) {// 1.从schema+table级中获取
257+ binding = bindingWrapper .getRuleBinding ();
258+ } else {// 2.从schema级获取
259+ binding = getRouteRuleBindingBySchemaLevel (scName );
260+ }
210261 if (binding == null ) {
211262 return null ;
212- } else {// 必须使用 binding 中的 scName ,因为sql中的scName可能为空
213- ShardRouteInfo info = getRouteInfo (binding , binding .getScName (), binding . getTbName () , sdValue );
263+ } else {// 必须使用binding中的scName ,因为sql中的scName可能为空,binding.getTbName()可能为null必须使用tbName
264+ ShardRouteInfo info = getRouteInfo (binding , binding .getScName (), tbName , sdValue );
214265 return info ;
215266 }
216267 }
217268
269+ /**
270+ *
271+ * @param scName can be null
272+ * @param tbName can't be null
273+ * @return if sdValues is null or scName-tbName don't hit config return null
274+ * @throws ShardValueNotFoundException
275+ * @throws ShardRouteException
276+ */
218277 @ Override
219278 public List <ShardRouteInfo > getRouteInfos (String scName , String tbName ) throws ShardValueNotFoundException ,
220279 ShardRouteException {
221- return routeInfoMap .get (buildQueryKey (scName , tbName ));
280+ scName = DDRStringUtils .toLowerCase (scName );
281+ tbName = DDRStringUtils .toLowerCase (tbName );
282+ if (tbName == null ) {
283+ throw new IllegalArgumentException ("tbName can't be null" );
284+ }
285+ List <ShardRouteInfo > result = routeInfosCache .get (buildQueryKey (scName , tbName ));
286+ if (result != null ) {
287+ return result ;
288+ } else {// 查询schema配置级别
289+ SimpleShardRouteRuleBinding binding = getRouteRuleBindingBySchemaLevel (scName );
290+ if (binding == null ) {
291+ return null ;
292+ } else {
293+ String key = buildQueryKey (binding .getScName (), tbName );
294+ String sdValues = binding .getSdValues ();
295+ if (sdValues != null ) {
296+ List <ShardRouteInfo > list = routeInfosCacheForSchemaLevel .get (key );
297+ if (list == null ) {
298+ final List <ShardRouteInfo > routeInfos = new ArrayList <>();
299+ final String scName0 = scName ;
300+ final String tbName0 = tbName ;
301+ new RangeExpressionParser (sdValues ).visit (new RangeExpressionItemVisitor () {
302+
303+ @ Override
304+ public void visit (Object val ) {
305+ ShardRouteInfo routeInfo = getRouteInfo (scName0 , tbName0 , val );
306+ routeInfos .add (routeInfo );
307+ }
308+ });
309+ routeInfosCacheForSchemaLevel .put (key , routeInfos );
310+ list = routeInfos ;
311+ }
312+ return list ;
313+ } else {
314+ return null ;
315+ }
316+ }
317+ }
318+ }
319+
320+ /**
321+ *
322+ * @param scName can be null
323+ * @return
324+ */
325+ private SimpleShardRouteRuleBinding getRouteRuleBindingBySchemaLevel (String scName ) {
326+ if (scName != null ) {
327+ return schemaBindingMap .get (scName );
328+ } else {
329+ return defaultSchemaBinding ;
330+ }
222331 }
223332
224333 @ Override
0 commit comments