Skip to content

Commit c23d72b

Browse files
committed
修复未读写分离时候的bug(读取了读写分离配置并且使用了),并且添加了路由解析编译缓存可选项,并且发布x.3.1.61
1 parent 0e1e2d8 commit c23d72b

File tree

61 files changed

+292
-117
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+292
-117
lines changed

benchmarks/ShardingCoreBenchmark/EFCoreCrud.cs

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,16 @@ public EFCoreCrud()
118118
public int N;
119119

120120

121-
//[Benchmark]
122-
//public async Task NoShardingFirstOrDefaultAsync()
123-
//{
124-
// for (int i = 0; i < N; i++)
125-
// {
126-
// var next = new Random().Next(1, 3000000).ToString();
127-
// var queryable = _defaultShardingDbContext.Set<Order>().Where(o => o.Id == next);
128-
// _virtualTable.RouteTo(new ShardingTableRouteConfig(queryable: queryable));
129-
// var queryable1 = _defaultShardingDbContext.Set<Order>().Where(o => next== o.Id);
130-
// _virtualTable.RouteTo(new ShardingTableRouteConfig(queryable: queryable1));
131-
// }
132-
//}
121+
[Benchmark]
122+
public async Task NoRouteParseCache()
123+
{
124+
for (int i = 0; i < N; i++)
125+
{
126+
var next = new Random().Next(1, 3000000).ToString();
127+
var queryable = _defaultShardingDbContext.Set<Order>().Where(o => o.Id == next);
128+
_virtualTable.RouteTo(new ShardingTableRouteConfig(queryable: queryable));
129+
}
130+
}
133131

134132
//[Benchmark]
135133
//public async Task ShardingFirstOrDefaultAsync()

nuget-publish.bat

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
:start
22
::定义版本
3-
set EFCORE2=2.3.1.60
4-
set EFCORE3=3.3.1.60
5-
set EFCORE5=5.3.1.60
6-
set EFCORE6=6.3.1.60
3+
set EFCORE2=2.3.1.61
4+
set EFCORE3=3.3.1.61
5+
set EFCORE5=5.3.1.61
6+
set EFCORE6=6.3.1.61
77

88
::删除所有bin与obj下的文件
99
@echo off

src/ShardingCore/Core/VirtualRoutes/DataSourceRoutes/Abstractions/AbstractShardingFilterVirtualDataSourceRoute.cs

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,22 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
2020
/// <summary>
2121
/// 过滤虚拟路由用于处理强制路由、提示路由、路由断言
2222
/// </summary>
23-
/// <typeparam name="T"></typeparam>
23+
/// <typeparam name="TEntity"></typeparam>
2424
/// <typeparam name="TKey"></typeparam>
25-
public abstract class AbstractShardingFilterVirtualDataSourceRoute<T, TKey> : AbstractVirtualDataSourceRoute<T, TKey> where T : class
25+
public abstract class AbstractShardingFilterVirtualDataSourceRoute<TEntity, TKey> : AbstractVirtualDataSourceRoute<TEntity, TKey> where TEntity : class
2626
{
2727

28-
public ShardingRouteContext CurrentShardingRouteContext =>
28+
public ShardingRouteContext CurrentShardingRouteContext =>
2929
ShardingContainer.GetService<IShardingRouteManager>().Current;
3030
/// <summary>
3131
/// 启用提示路由
3232
/// </summary>
33-
protected virtual bool EnableHintRoute => false;
33+
protected virtual bool EnableHintRoute => false;
3434
/// <summary>
3535
/// 启用断言路由
3636
/// </summary>
3737
protected virtual bool EnableAssertRoute => false;
38-
public override List<string> RouteWithPredicate(IQueryable queryable,bool isQuery)
38+
public override List<string> RouteWithPredicate(IQueryable queryable, bool isQuery)
3939
{
4040
var allDataSourceNames = GetAllDataSourceNames();
4141
if (!isQuery)
@@ -48,44 +48,55 @@ public override List<string> RouteWithPredicate(IQueryable queryable,bool isQuer
4848
{
4949
if (CurrentShardingRouteContext != null)
5050
{
51-
if (CurrentShardingRouteContext.TryGetMustDataSource<T>(out HashSet<string> mustDataSources) && mustDataSources.IsNotEmpty())
51+
if (CurrentShardingRouteContext.TryGetMustDataSource<TEntity>(out HashSet<string> mustDataSources) && mustDataSources.IsNotEmpty())
5252
{
5353
var dataSources = allDataSourceNames.Where(o => mustDataSources.Contains(o)).ToList();
54-
if (dataSources.IsEmpty()||dataSources.Count!=mustDataSources.Count)
54+
if (dataSources.IsEmpty() || dataSources.Count != mustDataSources.Count)
5555
throw new ShardingCoreException(
56-
$" sharding data source route must error:[{EntityMetadata.EntityType.FullName}]-->[{string.Join(",",mustDataSources)}]");
56+
$" sharding data source route must error:[{EntityMetadata.EntityType.FullName}]-->[{string.Join(",", mustDataSources)}]");
5757
return dataSources;
5858
}
5959

60-
if (CurrentShardingRouteContext.TryGetHintDataSource<T>(out HashSet<string> hintDataSources) && hintDataSources.IsNotEmpty())
60+
if (CurrentShardingRouteContext.TryGetHintDataSource<TEntity>(out HashSet<string> hintDataSources) && hintDataSources.IsNotEmpty())
6161
{
6262
var dataSources = allDataSourceNames.Where(o => hintDataSources.Contains(o)).ToList();
63-
if (dataSources.IsEmpty()||dataSources.Count!=hintDataSources.Count)
63+
if (dataSources.IsEmpty() || dataSources.Count != hintDataSources.Count)
6464
throw new ShardingCoreException(
65-
$" sharding data source route hint error:[{EntityMetadata.EntityType.FullName}]-->[{string.Join(",",hintDataSources)}]");
65+
$" sharding data source route hint error:[{EntityMetadata.EntityType.FullName}]-->[{string.Join(",", hintDataSources)}]");
6666

6767
return GetFilterDataSourceNames(allDataSourceNames, dataSources);
6868
}
6969
}
7070
}
7171
var filterDataSources = DoRouteWithPredicate(allDataSourceNames, queryable);
72-
return GetFilterDataSourceNames(allDataSourceNames,filterDataSources);
72+
return GetFilterDataSourceNames(allDataSourceNames, filterDataSources);
7373
}
74-
74+
/// <summary>
75+
/// 判断是调用全局还是内部断言
76+
/// </summary>
77+
/// <param name="allDataSourceNames"></param>
78+
/// <param name="filterDataSources"></param>
79+
/// <returns></returns>
7580
private List<string> GetFilterDataSourceNames(List<string> allDataSourceNames, List<string> filterDataSources)
7681
{
77-
//后拦截器
78-
var resultDataSources = AfterDataSourceFilter(allDataSourceNames, filterDataSources);
79-
//最后处理断言
80-
ProcessAssertRoutes(allDataSourceNames, resultDataSources);
81-
return resultDataSources;
82+
if (UseAssertRoute)
83+
{
84+
//最后处理断言
85+
ProcessAssertRoutes(allDataSourceNames, filterDataSources);
86+
return filterDataSources;
87+
}
88+
else
89+
{
90+
return AfterDataSourceFilter(allDataSourceNames, filterDataSources);
91+
}
8292
}
93+
private bool UseAssertRoute => EnableAssertRoute && CurrentShardingRouteContext != null && CurrentShardingRouteContext.TryGetAssertDataSource<TEntity>(out ICollection<IDataSourceRouteAssert> routeAsserts) && routeAsserts.IsNotEmpty();
8394

84-
private void ProcessAssertRoutes(List<string> allDataSources,List<string> filterDataSources)
95+
private void ProcessAssertRoutes(List<string> allDataSources, List<string> filterDataSources)
8596
{
8697
if (EnableAssertRoute)
8798
{
88-
if (CurrentShardingRouteContext != null && CurrentShardingRouteContext.TryGetAssertDataSource<T>(out ICollection<IDataSourceRouteAssert> routeAsserts) && routeAsserts.IsNotEmpty())
99+
if (CurrentShardingRouteContext != null && CurrentShardingRouteContext.TryGetAssertDataSource<TEntity>(out ICollection<IDataSourceRouteAssert> routeAsserts) && routeAsserts.IsNotEmpty())
89100
{
90101
foreach (var routeAssert in routeAsserts)
91102
{

src/ShardingCore/Core/VirtualRoutes/DataSourceRoutes/Abstractions/AbstractShardingOperatorVirtualDataSourceRoute.cs

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,17 @@ namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
2020
/// <summary>
2121
/// 抽象类型抽象出对应的条件表达式
2222
/// </summary>
23-
/// <typeparam name="T"></typeparam>
23+
/// <typeparam name="TEntity"></typeparam>
2424
/// <typeparam name="TKey"></typeparam>
25-
public abstract class AbstractShardingOperatorVirtualDataSourceRoute<T, TKey> : AbstractShardingFilterVirtualDataSourceRoute<T, TKey> where T : class
25+
public abstract class AbstractShardingOperatorVirtualDataSourceRoute<TEntity, TKey> : AbstractShardingRouteParseCompileCacheVirtualDataSourceRoute<TEntity, TKey> where TEntity : class
2626
{
2727
protected override List<string> DoRouteWithPredicate(List<string> allDataSourceNames, IQueryable queryable)
2828
{
29-
//获取所有需要路由的表后缀
30-
var filter = ShardingUtil.GetRouteShardingTableFilter<TKey>(queryable, EntityMetadata, GetRouteToFilter,false);
29+
//获取路由后缀表达式
30+
var routeParseExpression = ShardingUtil.GetRouteParseExpression<TKey>(queryable, EntityMetadata, GetRouteToFilter, false);
31+
//表达式缓存编译
32+
var filter = CachingCompile(routeParseExpression);
33+
//通过编译结果进行过滤
3134
var dataSources = allDataSourceNames.Where(o => filter(o)).ToList();
3235
return dataSources;
3336
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
using System;
2+
using System.Collections.Concurrent;
3+
using System.Collections.Generic;
4+
using System.Linq;
5+
using System.Linq.Expressions;
6+
using System.Text;
7+
using System.Threading.Tasks;
8+
using ShardingCore.Extensions;
9+
using ShardingCore.Sharding.Visitors;
10+
11+
namespace ShardingCore.Core.VirtualRoutes.DataSourceRoutes.Abstractions
12+
{
13+
/// <summary>
14+
/// 分库路由表达式解析缓存
15+
/// </summary>
16+
/// <typeparam name="TEntity"></typeparam>
17+
/// <typeparam name="TKey"></typeparam>
18+
public abstract class AbstractShardingRouteParseCompileCacheVirtualDataSourceRoute<TEntity, TKey> : AbstractShardingFilterVirtualDataSourceRoute<TEntity, TKey> where TEntity : class
19+
{
20+
private static readonly ConcurrentDictionary<Expression<Func<string, bool>>, Func<string, bool>> _routeCompileCaches = new(new ExtensionExpressionComparer.ExpressionEqualityComparer());
21+
22+
static AbstractShardingRouteParseCompileCacheVirtualDataSourceRoute()
23+
{
24+
Expression<Func<string, bool>> defaultWhere1 = x => true;
25+
_routeCompileCaches.TryAdd(defaultWhere1, defaultWhere1.Compile());
26+
Expression<Func<string, bool>> defaultWhere2 = x => true;
27+
var expression = defaultWhere2.And(defaultWhere1);
28+
_routeCompileCaches.TryAdd(expression, expression.Compile());
29+
}
30+
/// <summary>
31+
/// 是否启用路由解析编译缓存
32+
/// </summary>
33+
public virtual bool EnableRouteParseCompileCache => false;
34+
/// <summary>
35+
/// 对表达式进行缓存编译默认永久缓存单个参数表达式,且不包含orElse只包含单个AndAlso或者没有AndAlso的,
36+
/// 比如:<![CDATA[o.id==x]]>或者<![CDATA[o.id>x]]>,不会缓存<![CDATA[o=>id>x && o.id<y ]]>等一共大于、等于、小于、大于等于、小于等于(不等于编译成<![CDATA[t=>true]]>)缓存会存在的数量个数上限为
37+
/// 表后缀x*5+2,当前表如果有300个后缀那么就是1502个缓存结果额外两个为<![CDATA[o=>true]]>和<![CDATA[o=>true and true]]>
38+
/// </summary>
39+
/// <param name="parseWhere"></param>
40+
/// <returns></returns>
41+
public virtual Func<string, bool> CachingCompile(Expression<Func<string, bool>> parseWhere)
42+
{
43+
if (EnableRouteParseCompileCache)
44+
{
45+
var doCachingCompile = DoCachingCompile(parseWhere);
46+
if (doCachingCompile != null)
47+
return doCachingCompile;
48+
doCachingCompile = CustomerCachingCompile(parseWhere);
49+
if (doCachingCompile != null)
50+
return doCachingCompile;
51+
}
52+
return parseWhere.Compile();
53+
}
54+
/// <summary>
55+
/// 系统默认永久单表达式缓存
56+
/// </summary>
57+
/// <param name="parseWhere"></param>
58+
/// <returns>返回null会走<see cref="CustomerCachingCompile"/>这个方法如果还是null就会调用<see cref="Compile"/>方法</returns>
59+
protected virtual Func<string, bool> DoCachingCompile(Expression<Func<string, bool>> parseWhere)
60+
{
61+
var shouldCache = ShouldCache(parseWhere);
62+
if (shouldCache)
63+
return _routeCompileCaches.GetOrAdd(parseWhere, key => parseWhere.Compile());
64+
return null;
65+
}
66+
/// <summary>
67+
/// 表达式是否应该被缓存默认没有or并且and只有一个或者没有
68+
/// </summary>
69+
/// <param name="whereExpression"></param>
70+
/// <returns></returns>
71+
protected bool ShouldCache(Expression whereExpression)
72+
{
73+
var routeParseCacheExpressionVisitor = new RouteParseCacheExpressionVisitor();
74+
routeParseCacheExpressionVisitor.Visit(whereExpression);
75+
if (routeParseCacheExpressionVisitor.HasOrElse())
76+
return false;
77+
if (routeParseCacheExpressionVisitor.AndAlsoCount() > 1)
78+
return false;
79+
return true;
80+
}
81+
82+
protected virtual Func<string, bool> CustomerCachingCompile(Expression<Func<string, bool>> parseWhere)
83+
{
84+
return null;
85+
}
86+
}
87+
}

src/ShardingCore/Core/VirtualRoutes/TableRoutes/Abstractions/AbstractShardingFilterVirtualTableRoute.cs

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -63,22 +63,24 @@ public override List<IPhysicTable> RouteWithPredicate(List<IPhysicTable> allPhys
6363
if (physicTables.IsEmpty()||physicTables.Count!=hintTails.Count)
6464
throw new ShardingCoreException(
6565
$" sharding route hint error:[{EntityMetadata.EntityType.FullName}]-->[{string.Join(",",hintTails)}]");
66-
if (UseAssertRoute)
67-
{
68-
ProcessAssertRoutes(allPhysicTables, physicTables);
69-
return physicTables;
70-
}
71-
else
72-
{
73-
//后拦截器
74-
return AfterPhysicTableFilter(allPhysicTables, physicTables);
75-
}
66+
return GetFilterTableNames(allPhysicTables, physicTables);
7667
}
7768
}
7869
}
7970

8071

8172
var filterPhysicTables = DoRouteWithPredicate(allPhysicTables,queryable);
73+
return GetFilterTableNames(allPhysicTables, filterPhysicTables);
74+
}
75+
76+
/// <summary>
77+
/// 判断是调用全局过滤器还是调用内部断言
78+
/// </summary>
79+
/// <param name="allPhysicTables"></param>
80+
/// <param name="filterPhysicTables"></param>
81+
/// <returns></returns>
82+
private List<IPhysicTable> GetFilterTableNames(List<IPhysicTable> allPhysicTables, List<IPhysicTable> filterPhysicTables)
83+
{
8284
if (UseAssertRoute)
8385
{
8486
//最后处理断言

src/ShardingCore/Core/VirtualRoutes/TableRoutes/Abstractions/AbstractShardingOperatorVirtualTableRoute.cs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,15 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.Abstractions
1616
* @Date: Saturday, 19 December 2020 19:55:24
1717
1818
*/
19-
public abstract class AbstractShardingOperatorVirtualTableRoute<TEntity, TKey> : AbstractShardingFilterVirtualTableRoute<TEntity, TKey> where TEntity : class
19+
public abstract class AbstractShardingOperatorVirtualTableRoute<TEntity, TKey> : AbstractShardingRouteParseCompileCacheVirtualTableRoute<TEntity, TKey> where TEntity : class
2020
{
2121
protected override List<IPhysicTable> DoRouteWithPredicate(List<IPhysicTable> allPhysicTables, IQueryable queryable)
2222
{
23-
//获取所有需要路由的表后缀
24-
var filter = ShardingUtil.GetRouteShardingTableFilter<TKey>(queryable, EntityMetadata, GetRouteToFilter,true);
23+
//获取路由后缀表达式
24+
var routeParseExpression = ShardingUtil.GetRouteParseExpression<TKey>(queryable, EntityMetadata, GetRouteToFilter,true);
25+
//表达式缓存编译
26+
var filter=CachingCompile(routeParseExpression);
27+
//通过编译结果进行过滤
2528
var physicTables = allPhysicTables.Where(o => filter(o.Tail)).ToList();
2629
return physicTables;
2730
}

0 commit comments

Comments
 (0)