Пример #1
0
        protected DatabaseRepository(ILogger logger, IDatabaseReader databaseReader, ICache cache, IMemoryLockManager memoryLockManager)
        {
            Logger            = logger;
            Cache             = cache;
            MemoryLockManager = memoryLockManager;

            //Dirty trick
            Database = (IDatabase)databaseReader;

            Logger.LogInformation($"{GetType().Name} 初始化完成");
        }
Пример #2
0
        /// <summary>
        /// CacheAsideAsync
        /// </summary>
        /// <param name="cacheItem"></param>
        /// <param name="dbRetrieve"></param>
        /// <param name="cache"></param>
        /// <param name="memoryLockManager"></param>
        /// <param name="database"></param>
        /// <param name="logger"></param>
        /// <returns></returns>
        /// <exception cref="CacheException"></exception>
        /// <exception cref="RepositoryException"></exception>
        public static async Task <TResult?> CacheAsideAsync <TResult>(
            CachedItem <TResult> cacheItem, Func <IDatabaseReader, Task <TResult> > dbRetrieve,
            ICache cache, IMemoryLockManager memoryLockManager, IDatabase database, ILogger logger)
            where TResult : class
        {
            //Cache First
            TResult?result = await cacheItem.GetFromAsync(cache).ConfigureAwait(false);

            if (result != null)
            {
                return(result);
            }

            using var @lock = memoryLockManager.Lock(cacheItem.ResourceType, cacheItem.CacheKey, Consts.OccupiedTime, Consts.PatienceTime);

            if (@lock.IsAcquired)
            {
                //Double Check
                result = await cacheItem.GetFromAsync(cache).ConfigureAwait(false);

                if (result != null)
                {
                    return(result);
                }

                TResult dbRt = await dbRetrieve(database).ConfigureAwait(false);

                UtcNowTicks now = TimeUtil.UtcNowTicks;


                // 如果TResult是集合类型,可能会存入空集合。而在EntityCache中是不会存入空集合的。
                //这样设计是合理的,因为EntityCache是按Entity角度,存入的Entity会复用,就像一个KVStore一样,而CachedItem纯粹是一个查询结果,不思考查询结果的内容。
                if (dbRt != null)
                {
                    UpdateCache(cacheItem.Value(dbRt).Timestamp(now), cache);
                    logger.LogInformation($"缓存 Missed. Entity:{cacheItem.GetType().Name}, CacheKey:{cacheItem.CacheKey}");
                }
                else
                {
                    logger.LogInformation($"查询到空值. Entity:{cacheItem.GetType().Name}, CacheKey:{cacheItem.CacheKey}");
                }

                return(dbRt);
            }
            else
            {
                logger.LogCritical($"锁未能占用. Entity:{cacheItem.GetType().Name}, CacheKey:{cacheItem.CacheKey}, Lock Status:{@lock.Status}");

                return(await dbRetrieve(database).ConfigureAwait(false));
            }
        }
Пример #3
0
        public static async Task <IEnumerable <TEntity> > CacheAsideAsync <TEntity>(string dimensionKeyName, IEnumerable dimensionKeyValues, Func <IDatabaseReader, Task <IEnumerable <TEntity> > > dbRetrieve,
                                                                                    IDatabase database, ICache cache, IMemoryLockManager memoryLockManager, ILogger logger) where TEntity : Entity, new()
        {
            if (!ICache.IsEntityEnabled <TEntity>())
            {
                return(await dbRetrieve(database).ConfigureAwait(false));
            }

            try
            {
                (IEnumerable <TEntity>?cachedEntities, bool allExists) = await cache.GetEntitiesAsync <TEntity>(dimensionKeyName, dimensionKeyValues).ConfigureAwait(false);

                if (allExists)
                {
                    logger.LogDebug("Cache中全部存在,返回. Entity: {EntityType}", typeof(TEntity).Name);
                    return(cachedEntities !);
                }
            }
            catch (Exception ex)
            {
                //有可能实体定义发生改变,导致缓存读取出错
                logger.LogError2(ex, $"读取缓存出错,缓存可能已经被删除,继续读取数据库,dimensionKeyName:{dimensionKeyName}, dimensionKeyValues:{SerializeUtil.ToJson(dimensionKeyValues)}");
            }

            //常规做法是先获取锁(参看历史)。
            //但如果仅从当前dimension来锁的话,有可能被别人从其他dimension操作同一个entity,
            //所以这里改变常规做法,先做database retrieve

            //以上是针对无version版本cache的。现在不用担心从其他dimension操作同一个entity了,cache会自带version来判断。
            //而且如果刚开始很多请求直接打到数据库上,数据库撑不住,还是得加锁。
            //但可以考虑加单机本版的锁就可,这个锁主要为了降低数据库压力,不再是为了数据一致性(带version的cache自己解决)。
            //所以可以使用单机版本的锁即可。一个主机同时放一个db请求,还是没问题的。

            List <string> resources = new List <string>();

            foreach (object dimensionKeyValue in dimensionKeyValues)
            {
                resources.Add(dimensionKeyName + dimensionKeyValue.ToString());
            }

            using var @lock = memoryLockManager.Lock(typeof(TEntity).Name, resources, Consts.OccupiedTime, Consts.PatienceTime);

            if (@lock.IsAcquired)
            {
                try
                {
                    //Double check
                    (IEnumerable <TEntity>?cachedEntities, bool allExists) = await cache.GetEntitiesAsync <TEntity>(dimensionKeyName, dimensionKeyValues).ConfigureAwait(false);

                    if (allExists)
                    {
                        logger.LogDebug("Cache中全部存在,返回. Entity: {EntityType}", typeof(TEntity).Name);
                        return(cachedEntities !);
                    }
                }
                catch (Exception ex)
                {
                    //有可能实体定义发生改变,导致缓存读取出错
                    logger.LogError2(ex, $"!!!这里是读取缓存的DoubleCheck,这里不应该出现,缓存可能已经被删除,继续读取数据库,dimensionKeyName:{dimensionKeyName}, dimensionKeyValues:{SerializeUtil.ToJson(dimensionKeyValues)}");
                }

                IEnumerable <TEntity> entities = await dbRetrieve(database).ConfigureAwait(false);

                if (entities.IsNotNullOrEmpty())
                {
                    UpdateCache(entities, cache);

                    logger.LogInformation($"缓存 Missed. Entity:{typeof(TEntity).Name}, DimensionKeyName:{dimensionKeyName}, DimensionKeyValues:{dimensionKeyValues.ToJoinedString(",")}");
                }
                else
                {
                    logger.LogInformation($"查询到空值. Entity:{typeof(TEntity).Name}, DimensionKeyName:{dimensionKeyName}, DimensionKeyValues:{dimensionKeyValues.ToJoinedString(",")}");
                }

                return(entities);
            }
            else
            {
                logger.LogError($"锁未能占用. Entity:{typeof(TEntity).Name}, dimensionKeyName:{dimensionKeyName},dimensionKeyValues:{dimensionKeyValues.ToJoinedString(",")}, Lock Status:{@lock.Status}");

                return(await dbRetrieve(database).ConfigureAwait(false));
            }
        }
Пример #4
0
 public UserActivityRepo(ILogger <UserActivityRepo> logger, IDatabaseReader databaseReader, ICache cache, IMemoryLockManager memoryLockManager) : base(logger, databaseReader, cache, memoryLockManager)
 {
 }
Пример #5
0
        public UserRepo(ILogger <UserRepo> logger, IDatabaseReader databaseReader, ICache cache, IMemoryLockManager memoryLockManager)
            : base(logger, databaseReader, cache, memoryLockManager)
        {
            _databaseReader = databaseReader;

            EntityUpdating += (sender, args) =>
            {
                sender.SecurityStamp = SecurityUtil.CreateUniqueToken();
                return(Task.CompletedTask);
            };
        }
Пример #6
0
 public RoleRepo(ILogger <RoleRepo> logger, IDatabaseReader databaseReader, ICache cache, IMemoryLockManager memoryLockManager) : base(logger, databaseReader, cache, memoryLockManager)
 {
 }
Пример #7
0
 public SignInTokenBiz(ILogger <SignInTokenBiz> logger, IDatabaseReader databaseReader, ICache cache, IMemoryLockManager memoryLockManager) : base(logger, databaseReader, cache, memoryLockManager)
 {
     _databaseReader = databaseReader;
 }
Пример #8
0
 public MemoryLockTests(ServiceFixture_MySql serviceFixture)
 {
     _lockManager = serviceFixture.ServiceProvider.GetRequiredService <IMemoryLockManager>();
     _logger      = GlobalSettings.Logger;
 }
Пример #9
0
        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="databaseReader"></param>
        /// <param name="cache"></param>
        /// <param name="memoryLockManager"></param>
        /// <exception cref="CacheException"></exception>
        public RoleOfUserRepo(ILogger <RoleOfUserRepo> logger, IDatabaseReader databaseReader, ICache cache, IMemoryLockManager memoryLockManager) : base(logger, databaseReader, cache, memoryLockManager)
        {
            _databaseReader = databaseReader;

            EntityAdded += (roleOfUser, args) =>
            {
                InvalidateCache(CachedRolesByUserId.Key(roleOfUser.UserId).Timestamp(args.UtcNowTicks));
                return(Task.CompletedTask);
            };

            EntityUpdated += (roleOfUser, args) =>
            {
                InvalidateCache(CachedRolesByUserId.Key(roleOfUser.UserId).Timestamp(args.UtcNowTicks));
                return(Task.CompletedTask);
            };

            EntityDeleted += (roleOfUser, args) =>
            {
                InvalidateCache(CachedRolesByUserId.Key(roleOfUser.UserId).Timestamp(args.UtcNowTicks));
                return(Task.CompletedTask);
            };
        }
Пример #10
0
        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="logger"></param>
        /// <param name="databaseReader"></param>
        /// <param name="cache"></param>
        /// <param name="memoryLockManager"></param>
        /// <exception cref="CacheException"></exception>
        public UserClaimRepo(ILogger <UserClaimRepo> logger, IDatabaseReader databaseReader, ICache cache, IMemoryLockManager memoryLockManager) : base(logger, databaseReader, cache, memoryLockManager)
        {
            EntityAdded += (entity, args) =>
            {
                InvalidateCache(CachedUserClaimsByUserId.Key(entity.UserId).Timestamp(args.UtcNowTicks));
                return(Task.CompletedTask);
            };

            EntityUpdated += (entity, args) =>
            {
                InvalidateCache(CachedUserClaimsByUserId.Key(entity.UserId).Timestamp(args.UtcNowTicks));
                return(Task.CompletedTask);
            };

            EntityDeleted += (entity, args) =>
            {
                InvalidateCache(CachedUserClaimsByUserId.Key(entity.UserId).Timestamp(args.UtcNowTicks));
                return(Task.CompletedTask);
            };
        }