📄 cache_handler.c
字号:
#include <net-snmp/net-snmp-config.h>#if HAVE_STRING_H#include <string.h>#else#include <strings.h>#endif#include <net-snmp/net-snmp-includes.h>#include <net-snmp/agent/net-snmp-agent-includes.h>#include <net-snmp/agent/cache_handler.h>#if HAVE_DMALLOC_H#include <dmalloc.h>#endifstatic netsnmp_cache *cache_head = NULL;static int cache_outstanding_valid = 0;static int _cache_load( netsnmp_cache *cache );#define CACHE_RELEASE_FREQUENCY 60 /* Check for expired caches every 60s */void release_cached_resources(unsigned int regNo, void *clientargs);/** @defgroup cache_handler cache_handler: Maintains a cache of data for use by lower level handlers. * @ingroup utilities * This helper checks to see whether the data has been loaded "recently" * (according to the timeout for that particular cache) and calls the * registered "load_cache" routine if necessary. * The lower handlers can then work with this local cached data. * * A timeout value of -1 will cause netsnmp_cache_check_expired() to * always return true, and thus the cache will be reloaded for every * request. * * To minimze resource use by the agent, a periodic callback checks for * expired caches, and will call the free_cache function for any expired * cache. * * The load_cache route should return a negative number if the cache * was not successfully loaded. 0 or any positive number indicates successs. * * * Several flags can be set to affect the operations on the cache. * * If NETSNMP_CACHE_DONT_INVALIDATE_ON_SET is set, the free_cache method * will not be called after a set request has processed. It is assumed that * the lower mib handler using the cache has maintained cache consistency. * * If NETSNMP_CACHE_DONT_FREE_BEFORE_LOAD is set, the free_cache method * will not be called before the load_cache method is called. It is assumed * that the load_cache routine will properly deal with being called with a * valid cache. * * If NETSNMP_CACHE_DONT_FREE_EXPIRED is set, the free_cache method will * not be called with the cache expires. The expired flag will be set, but * the valid flag will not be cleared. It is assumed that the load_cache * routine will properly deal with being called with a valid cache. * * If NETSNMP_CACHE_PRELOAD is set when a the cache handler is created, * the cache load routine will be called immediately. * * If NETSNMP_CACHE_DONT_AUTO_RELEASE is set, the periodic callback that * checks for expired caches will skip the cache. The cache will only be * checked for expiration when a request triggers the cache handler. This * is useful if the cache has it's own periodic callback to keep the cache * fresh. * * If NETSNMP_CACHE_AUTO_RELOAD is set, a timer will be set up to reload * the cache when it expires. This is useful for keeping the cache fresh, * even in the absence of incoming snmp requests. * * * Here are some suggestions for some common situations. * * Cached File: * If your table is based on a file that may periodically change, * you can test the modification date to see if the file has * changed since the last cache load. To get the cache helper to call * the load function for every request, set the timeout to -1, which * will cause the cache to always report that it is expired. This means * that you will want to prevent the agent from flushing the cache when * it has expired, and you will have to flush it manually if you * detect that the file has changed. To accomplish this, set the * following flags: * * NETSNMP_CACHE_DONT_FREE_EXPIRED * NETSNMP_CACHE_DONT_AUTO_RELEASE * * * Constant (periodic) reload: * If you want the cache kept up to date regularly, even if no requests * for the table are received, you can have your cache load routine * called periodically. This is very useful if you need to monitor the * data for changes (eg a <i>LastChanged</i> object). You will need to * prevent the agent from flushing the cache when it expires. Set the * cache timeout to the frequency, in seconds, that you wish to * reload your cache, and set the following flags: * * NETSNMP_CACHE_DONT_FREE_EXPIRED * NETSNMP_CACHE_DONT_AUTO_RELEASE * NETSNMP_CACHE_AUTO_RELOAD * * @{ *//** get cache head * @internal * unadvertised function to get cache head. You really should not * do this, since the internal storage mechanism might change. */netsnmp_cache *netsnmp_cache_get_head(void){ return cache_head;}/** find existing cache */netsnmp_cache *netsnmp_cache_find_by_oid(oid * rootoid, int rootoid_len){ netsnmp_cache *cache; for (cache = cache_head; cache; cache = cache->next) { if (0 == netsnmp_oid_equals(cache->rootoid, cache->rootoid_len, rootoid, rootoid_len)) return cache; } return NULL;}/** returns a cache */netsnmp_cache *netsnmp_cache_create(int timeout, NetsnmpCacheLoad * load_hook, NetsnmpCacheFree * free_hook, oid * rootoid, int rootoid_len){ netsnmp_cache *cache = NULL; cache = SNMP_MALLOC_TYPEDEF(netsnmp_cache); if (NULL == cache) { snmp_log(LOG_ERR,"malloc error in netsnmp_cache_create\n"); return NULL; } cache->timeout = timeout; cache->load_cache = load_hook; cache->free_cache = free_hook; cache->enabled = 1; if(0 == cache->timeout) cache->timeout = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_CACHE_TIMEOUT); /* * Add the registered OID information, and tack * this onto the list for cache SNMP management * * Note that this list is not ordered. * table_iterator rules again! */ if (rootoid) { cache->rootoid = snmp_duplicate_objid(rootoid, rootoid_len); cache->rootoid_len = rootoid_len; cache->next = cache_head; if (cache_head) cache_head->prev = cache; cache_head = cache; } return cache;}/** callback function to call cache load function */static void_timer_reload(unsigned int regNo, void *clientargs){ netsnmp_cache *cache = (netsnmp_cache *)clientargs; DEBUGMSGT(("cache_timer:start", "loading cache %p\n", cache)); cache->expired = 1; _cache_load(cache);}/** starts the recurring cache_load callback */unsigned intnetsnmp_cache_timer_start(netsnmp_cache *cache){ if(NULL == cache) return 0; if(0 != cache->timer_id) { snmp_log(LOG_WARNING, "cache has existing timer id.\n"); return cache->timer_id; } if(! (cache->flags & NETSNMP_CACHE_AUTO_RELOAD)) { snmp_log(LOG_ERR, "cache_timer_start called but auto_reload not set.\n"); return 0; } cache->timer_id = snmp_alarm_register(cache->timeout, SA_REPEAT, _timer_reload, cache); if(0 == cache->timer_id) { snmp_log(LOG_ERR,"could not register alarm\n"); return 0; } DEBUGMSGT(("cache_timer:start", "starting timer %d for cache %p\n", cache->timer_id, cache)); return cache->timer_id;}/** stops the recurring cache_load callback */voidnetsnmp_cache_timer_stop(netsnmp_cache *cache){ if(NULL == cache) return; if(0 == cache->timer_id) { snmp_log(LOG_WARNING, "cache has no timer id.\n"); return; } DEBUGMSGT(("cache_timer:stop", "stopping timer %d for cache %p\n", cache->timer_id, cache)); snmp_alarm_unregister(cache->timer_id);}/** returns a cache handler that can be injected into a given handler chain. */netsnmp_mib_handler *netsnmp_cache_handler_get(netsnmp_cache* cache){ netsnmp_mib_handler *ret = NULL; ret = netsnmp_create_handler("cache_handler", netsnmp_cache_helper_handler); if (ret) { ret->flags |= MIB_HANDLER_AUTO_NEXT; ret->myvoid = (void *) cache; if(NULL != cache) { if ((cache->flags & NETSNMP_CACHE_PRELOAD) && ! cache->valid) { /* * load cache, ignore rc * (failed load doesn't affect registration) */ (void)_cache_load(cache); } if (cache->flags & NETSNMP_CACHE_AUTO_RELOAD) netsnmp_cache_timer_start(cache); } } return ret;}/** returns a cache handler that can be injected into a given handler chain. */netsnmp_mib_handler *netsnmp_get_cache_handler(int timeout, NetsnmpCacheLoad * load_hook, NetsnmpCacheFree * free_hook, oid * rootoid, int rootoid_len){ netsnmp_mib_handler *ret = NULL; netsnmp_cache *cache = NULL; ret = netsnmp_cache_handler_get(NULL); if (ret) { cache = netsnmp_cache_create(timeout, load_hook, free_hook, rootoid, rootoid_len); ret->myvoid = (void *) cache; } return ret;}/** functionally the same as calling netsnmp_register_handler() but also * injects a cache handler at the same time for you. */intnetsnmp_cache_handler_register(netsnmp_handler_registration * reginfo, netsnmp_cache* cache){ netsnmp_mib_handler *handler = NULL; handler = netsnmp_cache_handler_get(cache); netsnmp_inject_handler(reginfo, handler); return netsnmp_register_handler(reginfo);}/** functionally the same as calling netsnmp_register_handler() but also * injects a cache handler at the same time for you. */intnetsnmp_register_cache_handler(netsnmp_handler_registration * reginfo,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -