修改优化tablecreator为无锁模型创建,优化添加无缓存路由,并且发布x.4.2.9

This commit is contained in:
xuejiaming 2022-04-15 13:46:49 +08:00
parent e7474d1526
commit b4bf98662b
15 changed files with 234 additions and 99 deletions

View File

@ -1,9 +1,9 @@
:start
::定义版本
set EFCORE2=2.4.2.08
set EFCORE3=3.4.2.08
set EFCORE5=5.4.2.08
set EFCORE6=6.4.2.08
set EFCORE2=2.4.2.09
set EFCORE3=3.4.2.09
set EFCORE5=5.4.2.09
set EFCORE6=6.4.2.09
::删除所有bin与obj下的文件
@echo off

View File

@ -15,12 +15,12 @@ namespace Sample.SqlServer.UnionAllMerge
{
option.UseShardingQuery((conStr, builder) =>
{
builder.UseSqlServer(conStr);
builder.UseSqlServer(conStr).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
builderConfigure?.Invoke(builder);
});
option.UseShardingTransaction((connection, builder) =>
{
builder.UseSqlServer(connection);
builder.UseSqlServer(connection).UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
builderConfigure?.Invoke(builder);
});
}
@ -33,7 +33,7 @@ namespace Sample.SqlServer.UnionAllMerge
((IDbContextOptionsBuilderInfrastructure)optionsBuilder).AddOrUpdateExtension(extension);
return optionsBuilder.ReplaceService<IQuerySqlGeneratorFactory,
UnionAllMergeSqlServerQuerySqlGeneratorFactory<TShardingDbContext>>()
.ReplaceService<IQueryCompiler, UnionAllMergeQueryCompiler>(); ;
.ReplaceService<IQueryCompiler, UnionAllMergeQueryCompiler>();
}
}

View File

@ -38,34 +38,34 @@ namespace Sample.SqlServer3x.Controllers
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
//Console.WriteLine("---------------开始-----------------");
//var s = DateTime.Now.ToString("HHmmss");
//Task.Run(() =>
//{
// try
// {
// var virtualTable = _virtualTableManager.GetVirtualTable(typeof(SysUserMod));
// _virtualTableManager.AddPhysicTable(typeof(SysUserMod), new DefaultPhysicTable(virtualTable, s));
// _shardingTableCreator.CreateTable<SysUserMod>("A", s);
// }
// catch (Exception e)
// {
// Console.WriteLine(e);
// }
//});
//Task.Run(() =>
//{
// try
// {
// var virtualTable = _virtualTableManager.GetVirtualTable(typeof(SysUserModAbc));
// _virtualTableManager.AddPhysicTable(typeof(SysUserModAbc), new DefaultPhysicTable(virtualTable, s));
// _shardingTableCreator.CreateTable<SysUserModAbc>("A", s);
// }
// catch (Exception e)
// {
// Console.WriteLine(e);
// }
//});
Console.WriteLine("---------------开始-----------------");
var s = DateTime.Now.ToString("HHmmss");
Task.Run(() =>
{
try
{
var virtualTable = _virtualTableManager.GetVirtualTable(typeof(SysUserMod));
_virtualTableManager.AddPhysicTable(typeof(SysUserMod), new DefaultPhysicTable(virtualTable, s));
_shardingTableCreator.CreateTable<SysUserMod>("A", s);
}
catch (Exception e)
{
Console.WriteLine(e);
}
});
Task.Run(() =>
{
try
{
var virtualTable = _virtualTableManager.GetVirtualTable(typeof(SysUserModAbc));
_virtualTableManager.AddPhysicTable(typeof(SysUserModAbc), new DefaultPhysicTable(virtualTable, s));
_shardingTableCreator.CreateTable<SysUserModAbc>("A", s);
}
catch (Exception e)
{
Console.WriteLine(e);
}
});
//try
//{
// var virtualTable = _virtualTableManager.GetVirtualTable(typeof(SysUserMod));

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Microsoft.Extensions.Caching.Memory;
namespace ShardingCore.Core
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/4/15 11:40:58
/// Email: 326308290@qq.com
public interface IShardingModelCacheOption
{
#if !EFCORE2
CacheItemPriority GetModelCachePriority();
int GetModelCacheEntrySize();
#endif
int GetModelCacheLockObjectSeconds();
}
}

View File

@ -16,7 +16,19 @@ namespace ShardingCore.Core.VirtualRoutes
{
public IRouteTail Create(string tail)
{
return new SingleQueryRouteTail(tail);
return Create(tail, true);
}
public IRouteTail Create(string tail, bool cache)
{
if (cache)
{
return new SingleQueryRouteTail(tail);
}
else
{
return new NoCacheSingleQueryRouteTail(tail);
}
}
public IRouteTail Create(TableRouteResult tableRouteResult)

View File

@ -9,7 +9,7 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions
* @Date: Sunday, 22 August 2021 09:44:54
* @Email: 326308290@qq.com
*/
public interface IMultiQueryRouteTail:IRouteTail
public interface IMultiQueryRouteTail: INoCacheRouteTail
{
/// <summary>
/// 获取对象类型的应该后缀

View File

@ -0,0 +1,18 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/4/15 13:22:07
/// Email: 326308290@qq.com
public interface INoCacheRouteTail:IRouteTail
{
}
}

View File

@ -10,7 +10,24 @@ namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions
*/
public interface IRouteTailFactory
{
/// <summary>
/// dbcontext模型会被缓存
/// </summary>
/// <param name="tail"></param>
/// <returns></returns>
IRouteTail Create(string tail);
/// <summary>
/// cache false创建的dbcontext模型不会被缓存
/// </summary>
/// <param name="tail"></param>
/// <param name="cache"></param>
/// <returns></returns>
IRouteTail Create(string tail, bool cache);
/// <summary>
/// dbcontext模型不会被缓存
/// </summary>
/// <param name="tableRouteResult"></param>
/// <returns></returns>
IRouteTail Create(TableRouteResult tableRouteResult);
}
}

View File

@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails.Abstractions;
using ShardingCore.Core.VirtualRoutes.TableRoutes.RoutingRuleEngine;
using ShardingCore.Extensions;
namespace ShardingCore.Core.VirtualRoutes.TableRoutes.RouteTails
{
/// <summary>
///
/// </summary>
/// Author: xjm
/// Created: 2022/4/15 13:23:49
/// Email: 326308290@qq.com
public class NoCacheSingleQueryRouteTail:ISingleQueryRouteTail,INoCacheRouteTail
{
private readonly TableRouteResult _tableRouteResult;
private readonly string _tail;
private readonly string _modelCacheKey;
private readonly bool _isShardingTableQuery;
public NoCacheSingleQueryRouteTail(TableRouteResult tableRouteResult)
{
if (tableRouteResult.ReplaceTables.IsEmpty() || tableRouteResult.ReplaceTables.Count > 1) throw new ArgumentException("route result replace tables must 1");
_tableRouteResult = tableRouteResult;
_tail = _tableRouteResult.ReplaceTables.First().Tail;
_modelCacheKey = _tail.FormatRouteTail2ModelCacheKey();
_isShardingTableQuery = !string.IsNullOrWhiteSpace(_tail);
}
public NoCacheSingleQueryRouteTail(string tail)
{
_tail = tail;
_modelCacheKey = _tail.FormatRouteTail2ModelCacheKey();
_isShardingTableQuery = !string.IsNullOrWhiteSpace(_tail);
}
public virtual string GetRouteTailIdentity()
{
return _modelCacheKey;
}
public virtual bool IsMultiEntityQuery()
{
return false;
}
public bool IsShardingTableQuery()
{
return _isShardingTableQuery;
}
public virtual string GetTail()
{
return _tail;
}
}
}

View File

@ -45,18 +45,24 @@ namespace ShardingCore.EFCores
{
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
if (shardingTableDbContext.RouteTail is INoCacheRouteTail)
{
var multiModel = CreateModel(context, conventionSetBuilder, validator);
return multiModel;
}
}
int waitSeconds = 3;
if (context is IShardingModelCacheOption shardingModelCacheOption)
{
waitSeconds = shardingModelCacheOption.GetModelCacheLockObjectSeconds();
}
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context);
if (!_models.TryGetValue(cacheKey, out var model))
{
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(waitSeconds));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");

View File

@ -49,28 +49,33 @@ namespace ShardingCore.EFCores
IConventionSetBuilder conventionSetBuilder)
{
var priority = CacheItemPriority.High;
var size = 200;
var waitSeconds = 3;
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail)
if (shardingTableDbContext.RouteTail is INoCacheRouteTail)
{
if (singleQueryRouteTail.IsShardingTableQuery())
{
priority = CacheItemPriority.Normal;
}
var noCacheModel = CreateModel(context, conventionSetBuilder);
return noCacheModel;
}
else if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
else if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail && singleQueryRouteTail.IsShardingTableQuery())
{
var multiModel = CreateModel(context, conventionSetBuilder);
return multiModel;
priority = CacheItemPriority.Normal;
}
}
if (context is IShardingModelCacheOption shardingModelCacheOption)
{
priority = shardingModelCacheOption.GetModelCachePriority();
size = shardingModelCacheOption.GetModelCacheEntrySize();
waitSeconds = shardingModelCacheOption.GetModelCacheLockObjectSeconds();
}
var cache = Dependencies.MemoryCache;
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context);
if (!cache.TryGetValue(cacheKey, out IModel model))
{
// Make sure OnModelCreating really only gets called once, since it may not be thread safe.
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(waitSeconds));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
@ -80,7 +85,7 @@ namespace ShardingCore.EFCores
if (!cache.TryGetValue(cacheKey, out model))
{
model = CreateModel(context, conventionSetBuilder);
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = 200, Priority = priority });
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = size, Priority = priority });
}
}
finally

View File

@ -65,27 +65,32 @@ namespace ShardingCore.EFCores
{
var priority = CacheItemPriority.High;
var size = 200;
var waitSeconds = 3;
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail)
if (shardingTableDbContext.RouteTail is INoCacheRouteTail)
{
if (singleQueryRouteTail.IsShardingTableQuery())
{
priority = CacheItemPriority.Normal;
}
var noCacheModel = CreateModel(context, conventionSetBuilder, modelDependencies);
return noCacheModel;
}
else if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
else if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail&& singleQueryRouteTail.IsShardingTableQuery())
{
var multiModel = CreateModel(context, conventionSetBuilder, modelDependencies);
return multiModel;
priority = CacheItemPriority.Normal;
}
}
if (context is IShardingModelCacheOption shardingModelCacheOption)
{
priority = shardingModelCacheOption.GetModelCachePriority();
size = shardingModelCacheOption.GetModelCacheEntrySize();
waitSeconds = shardingModelCacheOption.GetModelCacheLockObjectSeconds();
}
var cache = Dependencies.MemoryCache;
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context);
if (!cache.TryGetValue(cacheKey, out IModel model))
{
// Make sure OnModelCreating really only gets called once, since it may not be thread safe.
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(waitSeconds));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
@ -95,7 +100,7 @@ namespace ShardingCore.EFCores
if (!cache.TryGetValue(cacheKey, out model))
{
model = CreateModel(context, conventionSetBuilder, modelDependencies);
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = 200, Priority = priority });
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = size, Priority = priority });
}
}
finally

View File

@ -79,28 +79,35 @@ namespace ShardingCore.EFCores
bool designTime)
{
var priority = CacheItemPriority.High;
var size = 200;
var waitSeconds = 3;
if (context is IShardingTableDbContext shardingTableDbContext)
{
if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail)
if (shardingTableDbContext.RouteTail is INoCacheRouteTail)
{
if (singleQueryRouteTail.IsShardingTableQuery())
{
priority = CacheItemPriority.Normal;
}
var noCacheModel = this.CreateModel(context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
noCacheModel = modelCreationDependencies.ModelRuntimeInitializer.Initialize(noCacheModel, designTime, modelCreationDependencies.ValidationLogger);
return noCacheModel;
}
else if (shardingTableDbContext.RouteTail is IMultiQueryRouteTail)
else
if (shardingTableDbContext.RouteTail is ISingleQueryRouteTail singleQueryRouteTail && singleQueryRouteTail.IsShardingTableQuery())
{
var multiModel = this.CreateModel(context, modelCreationDependencies.ConventionSetBuilder, modelCreationDependencies.ModelDependencies);
multiModel = modelCreationDependencies.ModelRuntimeInitializer.Initialize(multiModel, designTime, modelCreationDependencies.ValidationLogger);
return multiModel;
priority = CacheItemPriority.Normal;
}
}
if (context is IShardingModelCacheOption shardingModelCacheOption)
{
priority = shardingModelCacheOption.GetModelCachePriority();
size = shardingModelCacheOption.GetModelCacheEntrySize();
waitSeconds = shardingModelCacheOption.GetModelCacheLockObjectSeconds();
}
var cache = Dependencies.MemoryCache;
var cacheKey = Dependencies.ModelCacheKeyFactory.Create(context, designTime);
if (!cache.TryGetValue(cacheKey, out IModel model))
{
// Make sure OnModelCreating really only gets called once, since it may not be thread safe.
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(3));
var acquire = Monitor.TryEnter(_syncObject, TimeSpan.FromSeconds(waitSeconds));
if (!acquire)
{
throw new ShardingCoreInvalidOperationException("cache model timeout");
@ -115,7 +122,7 @@ namespace ShardingCore.EFCores
model = modelCreationDependencies.ModelRuntimeInitializer.Initialize(
model, designTime, modelCreationDependencies.ValidationLogger);
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = 200, Priority = priority });
model = cache.Set(cacheKey, model, new MemoryCacheEntryOptions { Size = size, Priority = priority });
}
}
finally

View File

@ -19,18 +19,16 @@ namespace ShardingCore.TableCreator
/// </summary>
/// <param name="dataSourceName"></param>
/// <param name="tail"></param>
/// <param name="timeOut"></param>
/// <typeparam name="T"></typeparam>
void CreateTable<T>(string dataSourceName, string tail,int timeOut=6000) where T : class;
void CreateTable<T>(string dataSourceName, string tail) where T : class;
/// <summary>
/// 创建表
/// </summary>
/// <param name="dataSourceName"></param>
/// <param name="shardingEntityType"></param>
/// <param name="tail"></param>
/// <param name="timeOut"></param>
/// <exception cref="ShardingCreateException"></exception>
void CreateTable(string dataSourceName, Type shardingEntityType, string tail, int timeOut = 6000);
void CreateTable(string dataSourceName, Type shardingEntityType, string tail);
}
public interface IShardingTableCreator<TShardingDbContext>: IShardingTableCreator where TShardingDbContext : DbContext, IShardingDbContext
{

View File

@ -25,7 +25,6 @@ namespace ShardingCore.TableCreator
private readonly IServiceProvider _serviceProvider;
private readonly IShardingEntityConfigOptions<TShardingDbContext> _entityConfigOptions;
private readonly IRouteTailFactory _routeTailFactory;
private readonly object _lock = new object();
public ShardingTableCreator(ILogger<ShardingTableCreator<TShardingDbContext>> logger, IServiceProvider serviceProvider, IShardingEntityConfigOptions<TShardingDbContext> entityConfigOptions, IRouteTailFactory routeTailFactory)
{
@ -35,9 +34,9 @@ namespace ShardingCore.TableCreator
_routeTailFactory = routeTailFactory;
}
public void CreateTable<T>(string dataSourceName, string tail, int timeOut = 6000) where T : class
public void CreateTable<T>(string dataSourceName, string tail) where T : class
{
CreateTable(dataSourceName, typeof(T), tail, timeOut);
CreateTable(dataSourceName, typeof(T), tail);
}
/// <summary>
@ -46,22 +45,15 @@ namespace ShardingCore.TableCreator
/// <param name="dataSourceName"></param>
/// <param name="shardingEntityType"></param>
/// <param name="tail"></param>
public void CreateTable(string dataSourceName, Type shardingEntityType, string tail, int timeOut = 6000)
public void CreateTable(string dataSourceName, Type shardingEntityType, string tail)
{
var acquire = Monitor.TryEnter(_lock, TimeSpan.FromMilliseconds(timeOut));
if (!acquire)
using (var serviceScope = _serviceProvider.CreateScope())
{
throw new ShardingCoreException("CreateTable cant get _lock");
}
try
{
using (var serviceScope = _serviceProvider.CreateScope())
var dbContext = serviceScope.ServiceProvider.GetService<TShardingDbContext>();
var shardingDbContext = (IShardingDbContext)dbContext;
using (var context = shardingDbContext.GetDbContext(dataSourceName, false,
_routeTailFactory.Create(tail, false)))
{
var dbContext = serviceScope.ServiceProvider.GetService<TShardingDbContext>();
var shardingDbContext = (IShardingDbContext)dbContext;
var context = shardingDbContext.GetDbContext(dataSourceName, false, _routeTailFactory.Create(tail));
context.RemoveDbContextRelationModelSaveOnlyThatIsNamedType(shardingEntityType);
var databaseCreator = context.Database.GetService<IDatabaseCreator>() as RelationalDatabaseCreator;
try
@ -77,17 +69,8 @@ namespace ShardingCore.TableCreator
throw new ShardingCoreException($" create table error :{ex.Message}", ex);
}
}
finally
{
context.RemoveModelCache();
}
}
}
finally
{
Monitor.Exit(_lock);
}
}
}
}