在编写高效的程序时,内存缓存有时是非常有用的,提到缓存,大家可能会很容易想到可以使用哈希表这种最常用的方式来缓存内存对象,但哈希的实现代码一般不具备两项功能:缓存过期时间、缓存数量限制,如果要增加对此二项功能的支持,一般需要增加辅助的链表结构。如果使用ACL里的 ACL_CACHE,则在高效缓存的前提下支持这两项功能。
下面是ACL_CACHE的数据结构及常用的接口调用:
一、数据结构及常用接口说明
1、数据结构定义
/**
* 缓冲池对象结构定义
*/
typedef struct ACL_CACHE {
ACL_HTABLE *table; /**< 哈希表 */
ACL_RING ring; /**< 将被删除的对象的数据链表 */
int max_size; /**< 缓存池容量大小限制值 */
int size; /**< 当前缓存池中的缓存对象个数 */
int timeout; /**< 每个缓存对象的生存时长(秒) */
/**< 释放用户动态对象的释放回调函数 */
void (*free_fn)(const ACL_CACHE_INFO*, void *);
acl_pthread_mutex_t lock; /**< 缓存池锁 */
ACL_SLICE *slice; /**< 内存切片对象 */
/* for acl_iterator */
/* 取迭代器头函数 */
const void *(*iter_head)(ACL_ITER*, struct ACL_CACHE*);
/* 取迭代器下一个函数 */
const void *(*iter_next)(ACL_ITER*, struct ACL_CACHE*);
/* 取迭代器尾函数 */
const void *(*iter_tail)(ACL_ITER*, struct ACL_CACHE*);
/* 取迭代器上一个函数 */
const void *(*iter_prev)(ACL_ITER*, struct ACL_CACHE*);
/* 取迭代器关联的当前容器成员结构对象 */
const ACL_CACHE_INFO *(*iter_info)(ACL_ITER*, struct ACL_CACHE*);
} ACL_CACHE;
/**
* 缓存池中存储的缓存对象
*/
typedef struct ACL_CACHE_INFO {
char *key; /**< 健值 */
void *value; /**< 用户动态对象 */
int nrefer; /**< 引用计数 */
time_t when_timeout; /**< 过期时间截 */
ACL_RING entry; /**< 内部数据链成员 */
} ACL_CACHE_INFO;
2、创建与释放接口
/**
* 创建一个缓存池,并设置每个缓存对象的最大缓存时长及该缓存池的空间容量限制
* @param max_size {int} 该缓存池的容量限制
* @param timeout {int} 每个缓存对象的缓存时长
* @param free_fn {void (*)(void*)} 用户级的释放缓存对象的函数
* @return {ACL_CACHE*} 缓存池对象句柄
*/
ACL_API ACL_CACHE *acl_cache_create(int max_size, int timeout,
void (*free_fn)(const ACL_CACHE_INFO*, void*));
/**
* 释放一个缓存池,并自动调用 acl_cache_create()/3 中的释放函数释放缓存对象
* @param cache {ACL_CACHE*} 缓存池对象句柄
*/
ACL_API void acl_cache_free(ACL_CACHE *cache);
3、增、删、查接口
/**
* 向缓存池中添加被缓存的对象
* @param cache {ACL_CACHE*} 缓存池对象句柄
* @param key {const char*} 缓存对象的健值
* @param value {void*} 动态缓存对象
* @return {ACL_CACHE_INFO*} 缓存对象所依附的结构对象,其中的 value 与用户的对象相同,
* 如果返回 NULL 则表示添加失败,失败原因为:缓存池太大溢出或相同健值的对象存在
* 且引用计数非0; 如果返回非 NULL 则表示添加成功,如果对同一健值的重复添加,会用
* 新的数据替换旧的数据,且旧数据调用释放函数进行释放
*/
ACL_API ACL_CACHE_INFO *acl_cache_enter(ACL_CACHE *cache, const char *key, void *value);
/**
* 从缓存池中查找某个被缓存的对象
* @param cache {ACL_CACHE*} 缓存池对象句柄
* @param key {const char*} 查询健
* @return {void*} 被缓存的用户对象的地址,为NULL时表示未找到
*/
ACL_API void *acl_cache_find(ACL_CACHE *cache, const char *key);
/**
* 从缓存池中查找某个被缓存的对象所依附的缓存信息对象
* @param cache {ACL_CACHE*} 缓存池对象句柄
* @param key {const char*} 查询健
* @return {ACL_CACHE_INFO*} 缓存信息对象地址,为NULL时表示未找到
*/
/**
* 从缓存池中删除某个缓存对象
* @param cache {ACL_CACHE*} 缓存池对象句柄
* @param key {const char*} 健值
* @return {int} 0: 表示删除成功; -1: 表示该对象的引用计数非0或该对象不存在
*/
ACL_API int acl_cache_delete2(ACL_CACHE *cache, const char *key);
4、同步互斥接口
/**
* 加锁缓存池对象,在多线程时用
* @param cache {ACL_CACHE*} 缓存池对象句柄
*/
ACL_API void acl_cache_lock(ACL_CACHE *cache);
/**
* 解锁缓存池对象,在多线程时用
* @param cache {ACL_CACHE*} 缓存池对象句柄
*/
ACL_API void acl_cache_unlock(ACL_CACHE *cache);
5、遍历接口
/**
* 遍历缓存中的所有对象
* @param cache {ACL_CACHE*} 缓存池对象句柄
* @param walk_fn {void (*)(ACL_CACHE_INFO*, void*)} 遍历回调函数
* @param arg {void *} walk_fn()/2 中的第二个参数
*/
ACL_API void acl_cache_walk(ACL_CACHE *cache, void (*walk_fn)(ACL_CACHE_INFO *, void *), void *arg);
当然,因为 ACL_CACHE 符合 ACL_ITER 通用迭代器(C语言中迭代器的设计与使用
)的规则要求,所以也可以采用ACL通用迭代方式遍历ACL_CACHE内部缓存对象,如下:
typedef struct {
char name[32];
char dummy[32];
} MY_DAT;
static free_mydat_fn(const ACL_CACHE_INFO *info, void *arg)
{
MY_DAT *mydat = (MY_DAT*) mydat;
acl_myfree(mydat);
}
void test(void)
{
ACL_CACHE *cache;
ACL_ITER iter;
MY_DAT *mydat;
char key[32];
/* 创建缓存对象句柄 */
cache = acl_cache_create(100, 60, free_mydat_fn);
/* 向缓存中添加缓存数据 */
for (i = 0; i < 10; i++) {
mydat = (MY_DAT*) acl_mymalloc(sizeof(MY_DAT));
snprintf(key, sizeof(key), "key:%d", i);
snprintf(mydat->name, sizeof(mydat->name), "name: %d", i);
(void) acl_cache_enter(cache, key, mydat);
}
/* 遍历所有缓存数据 */
acl_foreach(iter, cache) {
const MY_DAT *mydat = (const MY_DAT*) iter.data;
printf(">>>name: %s\n", mydat->name);
}
/* 释放缓存句柄并清除缓存数据 */
acl_cache_free(cache);
}
除了以上几个常用接口外,ACL_CACHE 模块还提供了其它方便使用的接口调用方式,参见: lib_acl/include/stdlib/acl_cache.h 头文件说明。
二、举例
下面是一个完整使用 ACL_CACHE 的例子:
#include "lib_acl.h"
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
/* 用户自定义数据结构 */
typedef struct {
char *buf;
int len;
} MYOBJ;
/**
* 释放用户数据回调数据
* @param info {const ACL_CACHE_INFO*} 用户缓存数据所依附的ACL_CACHE 的某个数据对象
* @param arg {void*} 用户数据对象以 void * 表示
*/
static void free_fn(const ACL_CACHE_INFO *info, void *arg)
{
MYOBJ *o = (MYOBJ*) arg;
printf("%s: when_timeout: %ld, now: %ld, len: %d, deleted\n",
info->key, (long) info->when_timeout, (long) time(NULL), o->len);
acl_myfree(o->buf);
acl_myfree(o);
}
/**
* 创建一个新的用户数据对象
* @param len {int} MYOBJ.buf 的长度
* @return {MYOBJ*}
static MYOBJ *myobj_new(int len)
{
MYOBJ *o = (MYOBJ*) acl_mymalloc(sizeof(MYOBJ));
o->buf = (char*) acl_mymalloc(len <= 0 ? 100 : len);
o->len = len;
return (o);
}
/**
* 遍历数据数据缓存中每一个数据对象的回调函数
* @param info {ACL_CACHE_INFO*}
* @arg {void*} 用户数据对象
*/
static void walk_fn(ACL_CACHE_INFO *info, void *arg)
{
MYOBJ *o = (MYOBJ*) info->value;
assert(info->value == arg);
printf("%s: size: %d; when_timeout: %ld\n", info->key, o->len, (long) info->when_timeout);
}
static void usage(const char *procname)
{
printf("usage: %s -h [help] -n max_size -t timeout\n", procname);
}
int main(int argc, char *argv[])
{
int i, n = 100, ch, timeout = 1;
ACL_CACHE_INFO *info;
ACL_CACHE *cache;
char key[32];
MYOBJ *o;
while ((ch = getopt(argc, argv, "hn:t:")) > 0) {
switch (ch) {
case 'h':
usage(argv[0]);
exit (0);
case 'n':
n = atoi(optarg);
break;
case 't':
timeout = atoi(optarg);
break;
default:
break;
}
}
/* 创建缓存句柄 */
cache = acl_cache_create(n, timeout, free_fn);
/* 向缓存中添加用户缓存数据 */
for (i = 0; i < n + 5; i++) {
o = myobj_new(i + 1);
snprintf(key, sizeof(key), "key(%d)", i);
assert(acl_cache_enter(cache, key, o));
printf("add one: %s\n", key);
sleep(1);
}
printf("\nfirst walk cache, cache size: %d\n", acl_cache_size(cache));
/* 遍历所有缓存数据 */
acl_cache_walk(cache, walk_fn, NULL);
printf("\nfirst call acl_cache_timeout, size: %d\n", acl_cache_size(cache));
/* 过期的缓存数据被自动删除 */
acl_cache_timeout(cache);
printf(">>>after first acl_cache_timeout, second walk cache, cache's size: %d\n", acl_cache_size(cache));
/* 遍历所有缓存数据 */
acl_cache_walk(cache, walk_fn, NULL);
printf("\n");
i = 0;
/* 休眠以使有些缓存数据过期 */
while (i++ < 5) {
printf("slee one second, i=%d\n", i);
sleep(1);
}
printf("\nsecond call acl_cache_timeout, size: %d\n", acl_cache_size(cache));
/* 过期的缓存数据被自动删除 */
acl_cache_timeout(cache);
printf(">>>after second acl_cache_timeout, third walk_cache, cache's size: %d\n", acl_cache_size(cache));
/* 遍历所有缓存数据 */
acl_cache_walk(cache, walk_fn, NULL);
/* 查询缓存对象 */
o = (MYOBJ*) acl_cache_find(cache, "key(5)");
if (o == NULL)
printf("\n>>>key(5) not exist\n");
else
printf("\n>>>key(5): len: %d\n", o->len);
/* 定位用户缓存数据所依附的缓存对象 */
info = acl_cache_locate(cache, "key(11)");
if (info == NULL)
printf("\n>>>key(11) not exist\n");
else {
o = (MYOBJ*) info->value;
printf("\n>>>key(11): len: %d, when_timeout: %ld\n", o->len, (long) info->when_timeout);
}
printf("\nfree cache, size: %d\n", acl_cache_size(cache));
/* 释放缓存并清除所有用户缓存数据 */
acl_cache_free(cache);
return (0);
}
ACL 库下载位置:http://acl.sourceforge.net/
个人微博:http://weibo.com/zsxxsz
分享到:
相关推荐
- **Caching**:为了提高性能,可以考虑使用缓存(如Redis)存储角色和权限的关系,减少数据库查询。 - **第三方库**:如`Bican/Role`和`Zizaco/Entrust`提供更完整的ACL解决方案,可替代原生实现。 5. **最佳...
除了基本的权限和角色管理,laravel-acl还支持更高级的用例,如继承关系(一个角色可以包含另一个角色的所有权限)、缓存优化、API集成等。你可以根据项目的具体需求对其进行扩展和定制。 总结来说,"laravel-acl...
在实际开发中,开发者需要将这些库文件链接到他们的C++项目中,通过`#include`指令引入相关头文件,然后利用ACL库提供的接口与Redis服务器建立连接,执行命令,读取或写入数据。例如,创建Redis连接、发送`GET`或`...
2. **文档**:可能会有相关的开发和使用指南,帮助用户理解和部署 acl-helper。 3. **示例配置**:提供了示例配置文件,展示如何在Squid配置中集成 acl-helper,以及如何编写自定义的外部程序。 4. **编译脚本和依赖...
此外,Squid的优化还包括访问控制(ACL)、缓存策略、带宽管理等。通过调整这些参数,可以进一步提升服务器性能,满足不同场景的需求。例如,可以设置不同的缓存策略以优先缓存热门或高流量的网站,或者限制某些IP或...
《超市管理系统开发日志》是记录在开发这样一个系统过程中遇到的问题、解决方法及技术细节的文档。这个系统属于互联网应用的范畴,它涉及到的技术和流程对于理解和构建类似的管理信息系统具有重要的参考价值。 在...
Nginx(发音为 "engine-x")是一个高性能的HTTP和反向代理服务器,它以事件驱动和异步非阻塞...6. **缓存机制**:Nginx支持HTTP缓存,可以缓存静态内容以提高响应速度和减轻后端服务器的负载。 7. **配置简单**:Nginx
《Windows NT 文件系统内幕(开发指南)》是一本深度探讨Windows NT内核级文件系统运作机制的专业书籍。这本书主要面向开发者、系统管理员和技术爱好者,它揭示了Windows NT操作系统如何管理和组织磁盘上的文件数据...
Apache Shiro 是一个强大且易用的 Java 安全框架,它提供了认证、授权、加密和会话管理功能,简化了开发人员处理安全问题的过程。本项目是一个基于 Spring Boot 的 Shiro 全流程示例,涵盖了从用户登录认证到权限...
11. **实战案例**:最后,通过实际项目或案例,演示如何在Web开发、缓存、计数器、队列等多种场景下使用Redis 6。 通过这些PPT的学习,你将能掌握Redis 6的核心知识,并具备在实际项目中运用的能力。每个主题都值得...
同时,Nginx还可以通过防火墙规则、访问控制列表(ACL)等方式限制非法访问,增强服务器安全性。 总的来说,《深入理解Nginx模块开发与架构解析》这本书将帮助读者深入了解Nginx的内部运作,包括其高效的设计、模块...
6. **安全性与权限**:通过角色、访问控制列表(ACL)和域策略设置用户权限,确保数据安全。 7. **邮件集成**:Domino内置邮件系统,可以将论坛帖子或回复通过电子邮件通知用户。 8. **Web服务与API**:利用Web...
开发环境-Zookeeper.pdf`可能会讲解Zookeeper的核心概念,包括它的数据模型(节点和ACL)、会话和观察者模式,以及如何在实际应用中使用Zookeeper来解决分布式问题。 3. **Redis**: Redis是一个开源的内存数据...
这句命令用于在全局程序集缓存(GAC)中查找名称包含 "Corillian" 的程序集,如果找到则更新该程序集,否则安装该程序集。 8. sn -t foo.dll 这句命令是干嘛的? 这句命令用于显示程序集 foo.dll 的公钥标记。 9....
本指南旨在为 HDFS 管理员提供实用的操作指南,覆盖了 HDFS 中 ACL 配置、归档存储和集中缓存管理等方面的知识点。通过对这些主题的深入了解,管理员将能够更有效地管理 HDFS 上的数据资源,从而提升整体的数据处理...
Vue.js 是一个流行的前端JavaScript...总的来说,`vue-acl`为Vue.js开发提供了强大的访问控制解决方案,通过它可以轻松实现权限管理,提升应用的安全性和用户体验。合理利用其特性,可以使你的Vue项目更加健壮和安全。
1. 缓存策略:为了提高读取速度,xfile可能会采用缓存机制,将经常访问的文件或数据片段存储在内存中,减少磁盘I/O。 2. 并行处理:对于大型文件,xfile可能采用分块处理的方式,通过多线程并行处理,加快文件操作...
设计权限控制,如角色权限、访问控制列表(ACL),确保不同用户对资源有不同的操作权限。 6. **商品管理**: 创建商品模型,实现商品添加、编辑、删除功能。设计商品分类和属性系统,支持商品的多图上传和详情展示...
5. **安全模型**:讨论了权限、访问控制列表(ACL)和身份验证机制,以及如何确保应用程序的安全性。 6. **组策略**:解释了如何创建、应用和管理组策略对象(GPO),以实现对用户和计算机设置的集中控制。 7. **...
3. **文件权限管理**:Windows NT内核提供了严格的访问控制机制,通过ACL(访问控制列表)定义用户和组对文件和目录的访问权限。权限包括读取、写入、执行等,可以进行细粒度的控制。 4. **文件系统驱动程序(FSD)...