惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
Cyberwarzone
Cyberwarzone
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
小众软件
小众软件
Recent Announcements
Recent Announcements
博客园 - 三生石上(FineUI控件)
Security Archives - TechRepublic
Security Archives - TechRepublic
W
WeLiveSecurity
Cloudbric
Cloudbric
博客园 - 司徒正美
美团技术团队
N
News and Events Feed by Topic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
PCI Perspectives
PCI Perspectives
宝玉的分享
宝玉的分享
H
Help Net Security
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
Help Net Security
Help Net Security
Last Week in AI
Last Week in AI
S
Schneier on Security
N
News | PayPal Newsroom
B
Blog RSS Feed
L
LINUX DO - 最新话题
T
Troy Hunt's Blog
S
Secure Thoughts
雷峰网
雷峰网
aimingoo的专栏
aimingoo的专栏
L
Lohrmann on Cybersecurity
G
Google Developers Blog
Microsoft Azure Blog
Microsoft Azure Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
T
Tenable Blog
S
Securelist
L
LangChain Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
I
InfoQ
H
Heimdal Security Blog
Cisco Talos Blog
Cisco Talos Blog
F
Full Disclosure
Y
Y Combinator Blog
酷 壳 – CoolShell
酷 壳 – CoolShell
K
Kaspersky official blog
T
Tailwind CSS Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
阮一峰的网络日志
阮一峰的网络日志
C
Cisco Blogs

博客园 - 涤生

了解ASP.NET底层架构(网络上的翻译) EditPlus中的正则表达式使用--如何使用查找到的原字符 Spring.Net学习笔记一——入门、第一个例子 CodeSmith4.0.2连接SqlServer2005――不允许远程连接 many2many的写法与注意点 Nhibernate继承类的写法 One2One主键关联的实现 NHibernate基础学习时遇到的问题 NHibernate学习之一:Many2One遇到的问题 自动提取网页的信息 ,并分析之 权限学习--BlueDavy之技术Blog漫谈权限系统之结尾篇(开源产品、个人观点、知识体系) 权限学习--BlueDavy之技术Blog漫谈权限系统之基于ACL的实现 权限设计学习篇--BlueDavy之技术Blog - 漫谈权限系统之技术策略以及基于RBAC ... 权限设计-之学习篇--来源于BlueDavy之技术Blog Oracle数据库发生Ora-12162错误 Linux下Oracle文件的自动备份与ftp自动上传 BugFree安装手记 CodeSmith3.0x中Oracle的访问 Asp.Net StartKits之Asp.Net Issue Tracker Starter Kit-数据库
Enterprise Library Caching Application Block(CAB)源代码研究之缓存条目清理后台线程篇
涤生 · 2008-11-07 · via 博客园 - 涤生

Tag:

在Caching Application Block(文中将简称为CAB)中关于如何处理缓存条目的文章有不少,但对于如何实现的说的不多。也许很多大牛们不屑吧。

从设计思想上来说
移除条目大的方向有两个,一个是主动的调用Move方法;另外一个是通过后台进程的方法。

对于主动调用,就不赘述了。下面引出本文所要描述的重点,即后台进程移除缓存条目。

设计到的类总共有如下几个:

BackgroundScheduler,实现ICacheScavenger接口:后台线程主类,负责管理所有后台线程,后台线程集合存放在线程安全的ProducerConsumerQueue队列中。

ProducerConsumerQueue:线程安全的Queue,Queue中放入实现IQueueMessage接口的对象

IQueueMessage:后台线程类的操作接口,BackgroundScheduler调用这个接口完成实际的工作

StartScavengingMsg,实现IQueueMessage接口,内部拥有BackgroundScheduler的引用

ExpirationTimeoutExpiredMsg,实现IQueueMessage接口,内部拥有BackgroundScheduler的引用

ScavengerTask:清理器,用来执行缓存清理工作,主要是当缓存条目到最大条目时候执行清理

ExpirationTask:过期条目清理器,用来实际执行过期条目的删除

//下面是一些其他参与类

ExpirationPollTimer:内部拥有一个计时器,用来定期执行过期缓存条目删除

Cache:调用ICacheScavenger,执行ScavengerTask工作

CacheManagerAssembler:初始化所有后台线程类

从缓存条目移除的角度来看,这几个类之间的实际关系如下:

ScavengerTask与ExpirationTask是两个实际执行缓存条目移除的类。这两个类可以认为是缓存移除的Core类部分,既可以直接调用也可以被包装成后台调用。下面我们来分析CAB如何从后台线程调用这两个类完成缓存条目的清理工作的。

首先看CacheManagerAssembler类,这个类是在CAB被加载的时候执行的,有关的代码如下:(此部分代码在CacheManagerFactoryHelper中,CacheManagerAssembler调用CacheManagerFactoryHelper完成加载过程)

Code

这段代码描述了上面涉及到的部分类之间的关系。此处看也许不一定能看懂这些代码,可以在看完本文后重新来阅读这段代码。我们先主要看这段代码的其中一句

timer.StartPolling(new TimerCallback(scheduler.ExpirationTimeoutExpired), expirationPollFrequencyInSeconds * 1000);

这句话的主要意思是在固定的时间间隔中调用schedulerExpirationTimeoutExpired方法。而schedulerBackgroundScheduler 的一个实例。也就是说系统将间隔固定时间执行过期条目的清理。同时这个清理的过程交给后台线程管理类BackgroundScheduler 来执行。这样所有条目的清理任务都交给了BackgroundScheduler 来管理。而ExpirationPollTimer 类负责定期通知BackgroundScheduler 来执行这个过程。

下面我们就隆重的退出CAB后台线程管理类BackgroundScheduler

首先看它的加载与启动:

Code

在CacheManagerAssembler类中,有如下代码

Code


这两段代码完成了线程管理类在CAB模块加载的时候运行于后台的目的。

下面我们来看BackgroundScheduler 类是如何设计的

BackgroundScheduler 类拥有一个队列ProducerConsumerQueue,这个队列中存放的是所有的要在后台执行任务的对象。所有在后台执行任务的对象都需要实现IQueueMessage接口。

IQueueMessage接口内容如下:

Code

BackgroundScheduler的加载部分我们可以得知,该线程的回调函数是QueueReader

我们来看这个函数的主要内容:

Code

从这个代码我们可以看出后台类在不断的轮休去执行队列中的所有任务。从而实现后台线程管理类的大的框架。

上文讲到,ExpirationPollTimer 类负责通知BackgroundScheduler 定期执行过期条目处理任务。它的回调函数是ExpirationTimeoutExpired

Code


可以看出,回调函数的主要功能是在队列inputQueue中增加要执行过期条目处理任务的对象,而这个对象将在QueueReader函数中执行实际的操作。

此处要注意,ExpirationPollTimer 类并没有直接回调实际执行任务的对象,而是委托给BackgroundScheduler 来调用。统一了后台线程的管理,这样的设计方法值得学习。

BackgroundScheduler整体框架分析完,我们来分析每一个任务的具体实现方法。

两个消息类的实现方法相同,以其中的StartScavengingMsg来分析,实现代码如下:

Code

可以看到这个消息类拥有BackgroundScheduler 的引用,又重新把实际执行的任务委托给类BackgroundScheduler 来执行。

Code

此处我们终于看到实际执行任务的scavenger对象了。最终BackgroundScheduler 委托ScavengerTask来执行缓存条目清理任务。通过这样一个系列的包装,ScavengerTaskExpirationTask这两个实际执行缓存条目移除的类就开始在后台默默的工作了。

呵呵,前面讲了ExpirationTask是通过ExpirationPollTimer来定时调用触发的机制。那么另外一个清理类ScavengerTask是如何来触发的了?

我们回到CacheManagerAssembler的加载过程,

Code


可知,在初始化时,我们将BackgroundScheduler 实例放入cache中,观察cache的代码可知,它在Add条目的时候调用这个BackgroundScheduler 的实例,Add代码有关部分如下:

Code

可以得知,Cache在加入条目的时候提出清理的请求。而清理请求将执行一个判断,如果超过最大条目则将清理任务放入后台队列中,进行清理。而后台队列的调用过程见上面一小节。

如上,我们分析了CAB模块的清理缓存条目的全部过程。其中我们可以学习它的后台线程类的设计思路,这个思路可以应用在自己系统的后台线程类的实现中。这也是我记录这个学习过程的主要目的。

至于如何判断缓存条目是否过期,如何清理等,不是本文主要的目的。

简单的说,它通过一个策略模式来实现。每一个CacheItem中都包含一个过期处理策略的数组ICacheItemExpiration[],数组中放入该CacheItem过期处理策略,每个策略都实现ICacheItemExpiration接口,CacheItem通过这个接口来判断该CacheItem是否过期。CAB中实现AbsoluteTime(绝对时间过期策略)、SlidingTime(相对时间过期策略)、NeverExpired(永不过期策略)、FileDependency与ExtendedFormatTime等。