📄 acache.c
字号:
INSIST(ISC_LIST_EMPTY(dbentry->originlist) && ISC_LIST_EMPTY(dbentry->referlist)); bucket = isc_hash_calc((const unsigned char *)&db, sizeof(db), ISC_TRUE) % DBBUCKETS; ISC_LIST_UNLINK(acache->dbbucket[bucket], dbentry, link); dns_db_detach(&dbentry->db); isc_mem_put(acache->mctx, dbentry, sizeof(*dbentry)); acache->dbentries--; acache->stats.deleted++; UNLOCK(&acache->lock); return (ISC_R_SUCCESS);}isc_result_tdns_acache_createentry(dns_acache_t *acache, dns_db_t *origdb, void (*callback)(dns_acacheentry_t *, void **), void *cbarg, dns_acacheentry_t **entryp){ dns_acacheentry_t *newentry; isc_result_t result; isc_uint32_t r; REQUIRE(DNS_ACACHE_VALID(acache)); REQUIRE(entryp != NULL && *entryp == NULL); REQUIRE(origdb != NULL); /* * Should we exceed our memory limit for some reason (for * example, if the cleaner does not run aggressively enough), * then we will not create additional entries. * * XXXSK: It might be better to lock the acache->cleaner->lock, * but locking may be an expensive bottleneck. If we misread * the value, we will occasionally refuse to create a few * cache entries, or create a few that we should not. I do not * expect this to happen often, and it will not have very bad * effects when it does. So no lock for now. */ if (acache->cleaner.overmem) { acache->stats.overmem_nocreates++; /* XXXSK danger: unlocked! */ return (ISC_R_NORESOURCES); } newentry = isc_mem_get(acache->mctx, sizeof(*newentry)); if (newentry == NULL) { acache->stats.nomem++; /* XXXMLG danger: unlocked! */ return (ISC_R_NOMEMORY); } isc_random_get(&r); newentry->locknum = r % DEFAULT_ACACHE_ENTRY_LOCK_COUNT; result = isc_refcount_init(&newentry->references, 1); if (result != ISC_R_SUCCESS) { isc_mem_put(acache->mctx, newentry, sizeof(*newentry)); return (result); }; ISC_LINK_INIT(newentry, link); ISC_LINK_INIT(newentry, olink); ISC_LINK_INIT(newentry, rlink); newentry->acache = NULL; dns_acache_attach(acache, &newentry->acache); newentry->zone = NULL; newentry->db = NULL; newentry->version = NULL; newentry->node = NULL; newentry->foundname = NULL; newentry->callback = callback; newentry->cbarg = cbarg; newentry->origdb = NULL; dns_db_attach(origdb, &newentry->origdb); isc_stdtime_get(&newentry->lastused); newentry->magic = ACACHEENTRY_MAGIC; *entryp = newentry; return (ISC_R_SUCCESS);}isc_result_tdns_acache_getentry(dns_acacheentry_t *entry, dns_zone_t **zonep, dns_db_t **dbp, dns_dbversion_t **versionp, dns_dbnode_t **nodep, dns_name_t *fname, dns_message_t *msg, isc_stdtime_t now){ isc_result_t result = ISC_R_SUCCESS; dns_rdataset_t *erdataset; isc_stdtime32_t now32; dns_acache_t *acache; int locknum; REQUIRE(DNS_ACACHEENTRY_VALID(entry)); REQUIRE(zonep == NULL || *zonep == NULL); REQUIRE(dbp != NULL && *dbp == NULL); REQUIRE(versionp != NULL && *versionp == NULL); REQUIRE(nodep != NULL && *nodep == NULL); REQUIRE(fname != NULL); REQUIRE(msg != NULL); acache = entry->acache; REQUIRE(DNS_ACACHE_VALID(acache)); locknum = entry->locknum; ACACHE_LOCK(&acache->entrylocks[locknum], isc_rwlocktype_read); isc_stdtime_convert32(now, &now32); acache_storetime(entry, now32); if (entry->zone != NULL && zonep != NULL) dns_zone_attach(entry->zone, zonep); if (entry->db == NULL) { *dbp = NULL; *versionp = NULL; } else { dns_db_attach(entry->db, dbp); dns_db_attachversion(entry->db, entry->version, versionp); } if (entry->node == NULL) *nodep = NULL; else { dns_db_attachnode(entry->db, entry->node, nodep); INSIST(entry->foundname != NULL); dns_name_copy(entry->foundname, fname, NULL); for (erdataset = ISC_LIST_HEAD(entry->foundname->list); erdataset != NULL; erdataset = ISC_LIST_NEXT(erdataset, link)) { dns_rdataset_t *ardataset; ardataset = NULL; result = dns_message_gettemprdataset(msg, &ardataset); if (result != ISC_R_SUCCESS) { ACACHE_UNLOCK(&acache->entrylocks[locknum], isc_rwlocktype_read); goto fail; } /* * XXXJT: if we simply clone the rdataset, we'll get * lost wrt cyclic ordering. We'll need an additional * trick to get the latest counter from the original * header. */ dns_rdataset_init(ardataset); dns_rdataset_clone(erdataset, ardataset); ISC_LIST_APPEND(fname->list, ardataset, link); } } entry->acache->stats.hits++; /* XXXMLG danger: unlocked! */ entry->acache->stats.queries++; ACACHE_UNLOCK(&acache->entrylocks[locknum], isc_rwlocktype_read); return (result); fail: while ((erdataset = ISC_LIST_HEAD(fname->list)) != NULL) { ISC_LIST_UNLINK(fname->list, erdataset, link); dns_rdataset_disassociate(erdataset); dns_message_puttemprdataset(msg, &erdataset); } if (*nodep != NULL) dns_db_detachnode(*dbp, nodep); if (*versionp != NULL) dns_db_closeversion(*dbp, versionp, ISC_FALSE); if (*dbp != NULL) dns_db_detach(dbp); if (zonep != NULL && *zonep != NULL) dns_zone_detach(zonep); return (result);}isc_result_tdns_acache_setentry(dns_acache_t *acache, dns_acacheentry_t *entry, dns_zone_t *zone, dns_db_t *db, dns_dbversion_t *version, dns_dbnode_t *node, dns_name_t *fname){ isc_result_t result; dbentry_t *odbent; dbentry_t *rdbent = NULL; isc_boolean_t close_version = ISC_FALSE; dns_acacheentry_t *dummy_entry = NULL; REQUIRE(DNS_ACACHE_VALID(acache)); REQUIRE(DNS_ACACHEENTRY_VALID(entry)); LOCK(&acache->lock); /* XXX: need to lock it here for ordering */ ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); /* Set zone */ if (zone != NULL) dns_zone_attach(zone, &entry->zone); /* Set DB */ if (db != NULL) dns_db_attach(db, &entry->db); /* * Set DB version. If the version is not given by the caller, * which is the case for glue or cache DBs, use the current version. */ if (version == NULL) { if (db != NULL) { dns_db_currentversion(db, &version); close_version = ISC_TRUE; } } if (version != NULL) { INSIST(db != NULL); dns_db_attachversion(db, version, &entry->version); } if (close_version) dns_db_closeversion(db, &version, ISC_FALSE); /* Set DB node. */ if (node != NULL) { INSIST(db != NULL); dns_db_attachnode(db, node, &entry->node); } /* * Set list of the corresponding rdatasets, if given. * To minimize the overhead and memory consumption, we'll do this for * positive cache only, in which case the DB node is non NULL. * We do not want to cache incomplete information, so give up the * entire entry when a memory shortage happen during the process. */ if (node != NULL) { dns_rdataset_t *ardataset, *crdataset; entry->foundname = isc_mem_get(acache->mctx, sizeof(*entry->foundname)); if (entry->foundname == NULL) { result = ISC_R_NOMEMORY; goto fail; } dns_name_init(entry->foundname, NULL); result = dns_name_dup(fname, acache->mctx, entry->foundname); if (result != ISC_R_SUCCESS) goto fail; for (ardataset = ISC_LIST_HEAD(fname->list); ardataset != NULL; ardataset = ISC_LIST_NEXT(ardataset, link)) { crdataset = isc_mem_get(acache->mctx, sizeof(*crdataset)); if (crdataset == NULL) { result = ISC_R_NOMEMORY; goto fail; } dns_rdataset_init(crdataset); dns_rdataset_clone(ardataset, crdataset); ISC_LIST_APPEND(entry->foundname->list, crdataset, link); } } odbent = NULL; result = finddbent(acache, entry->origdb, &odbent); if (result != ISC_R_SUCCESS) goto fail; if (db != NULL) { rdbent = NULL; result = finddbent(acache, db, &rdbent); if (result != ISC_R_SUCCESS) goto fail; } ISC_LIST_APPEND(acache->entries, entry, link); ISC_LIST_APPEND(odbent->originlist, entry, olink); if (rdbent != NULL) ISC_LIST_APPEND(rdbent->referlist, entry, rlink); /* * The additional cache needs an implicit reference to entries in its * link. */ dns_acache_attachentry(entry, &dummy_entry); ACACHE_UNLOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); acache->stats.adds++; UNLOCK(&acache->lock); return (ISC_R_SUCCESS); fail: clear_entry(acache, entry); ACACHE_UNLOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); UNLOCK(&acache->lock); return (result);}voiddns_acache_cancelentry(dns_acacheentry_t *entry) { dns_acache_t *acache = entry->acache; REQUIRE(DNS_ACACHEENTRY_VALID(entry)); INSIST(DNS_ACACHE_VALID(acache)); LOCK(&acache->lock); ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); /* * Release dependencies stored in this entry as much as possible. * The main link cannot be released, since the acache object has * a reference to this entry; the empty entry will be released in * the next cleaning action. */ unlink_dbentries(acache, entry); clear_entry(entry->acache, entry); entry->callback = NULL; entry->cbarg = NULL; ACACHE_UNLOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); UNLOCK(&acache->lock);}voiddns_acache_attachentry(dns_acacheentry_t *source, dns_acacheentry_t **targetp){ REQUIRE(DNS_ACACHEENTRY_VALID(source)); REQUIRE(targetp != NULL && *targetp == NULL); isc_refcount_increment(&source->references, NULL); *targetp = source;}voiddns_acache_detachentry(dns_acacheentry_t **entryp) { dns_acacheentry_t *entry; unsigned int refs; REQUIRE(entryp != NULL && DNS_ACACHEENTRY_VALID(*entryp)); entry = *entryp; isc_refcount_decrement(&entry->references, &refs); /* * If there are no references to the entry, the entry must have been * unlinked and can be destroyed safely. */ if (refs == 0) { INSIST(!ISC_LINK_LINKED(entry, link)); (*entryp)->acache->stats.deleted++; destroy_entry(entry); } *entryp = NULL;}voiddns_acache_setcleaninginterval(dns_acache_t *acache, unsigned int t) { isc_interval_t interval; isc_result_t result; REQUIRE(DNS_ACACHE_VALID(acache)); ATRACE("dns_acache_setcleaninginterval"); LOCK(&acache->lock); /* * It may be the case that the acache has already shut down. * If so, it has no timer. (Not sure if this can really happen.) */ if (acache->cleaner.cleaning_timer == NULL) goto unlock; acache->cleaner.cleaning_interval = t; if (t == 0) { result = isc_timer_reset(acache->cleaner.cleaning_timer, isc_timertype_inactive, NULL, NULL, ISC_TRUE); } else { isc_interval_set(&interval, acache->cleaner.cleaning_interval, 0); result = isc_timer_reset(acache->cleaner.cleaning_timer, isc_timertype_ticker, NULL, &interval, ISC_FALSE); } if (result != ISC_R_SUCCESS) isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE, ISC_LOG_WARNING, "could not set acache cleaning interval: %s", isc_result_totext(result)); else isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE, ISC_LOG_NOTICE, "acache %p cleaning interval set to %d.", acache, t); unlock: UNLOCK(&acache->lock);}/* * This function was derived from cache.c:dns_cache_setcachesize(). See the * function for more details about the logic. */voiddns_acache_setcachesize(dns_acache_t *acache, isc_uint32_t size) { isc_uint32_t lowater; isc_uint32_t hiwater; REQUIRE(DNS_ACACHE_VALID(acache)); if (size != 0 && size < DNS_ACACHE_MINSIZE) size = DNS_ACACHE_MINSIZE; hiwater = size - (size >> 3); lowater = size - (size >> 2); if (size == 0 || hiwater == 0 || lowater == 0) isc_mem_setwater(acache->mctx, water, acache, 0, 0); else isc_mem_setwater(acache->mctx, water, acache, hiwater, lowater);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -