📄 acache.c
字号:
INSIST(next != NULL && next != cleaner->current_entry); dns_acache_detachentry(&cleaner->current_entry); dns_acache_attachentry(next, &cleaner->current_entry); UNLOCK(&acache->lock); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1), "acache cleaner: checked %d entries, " "mem inuse %lu, sleeping", cleaner->increment, (unsigned long)isc_mem_inuse(cleaner->acache->mctx)); isc_task_send(task, &event); INSIST(CLEANER_BUSY(cleaner)); return;}/* * This is called when the acache either surpasses its upper limit * or shrinks beyond its lower limit. */static voidacache_overmem_cleaning_action(isc_task_t *task, isc_event_t *event) { acache_cleaner_t *cleaner = event->ev_arg; isc_boolean_t want_cleaning = ISC_FALSE; UNUSED(task); INSIST(event->ev_type == DNS_EVENT_ACACHEOVERMEM); INSIST(cleaner->overmem_event == NULL); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1), "overmem_cleaning_action called, " "overmem = %d, state = %d", cleaner->overmem, cleaner->state); LOCK(&cleaner->lock); if (cleaner->overmem) { if (cleaner->state == cleaner_s_idle) want_cleaning = ISC_TRUE; } else { if (cleaner->state == cleaner_s_busy) /* * end_cleaning() can't be called here because * then both cleaner->overmem_event and * cleaner->resched_event will point to this * event. Set the state to done, and then * when the acache_incremental_cleaning_action() event * is posted, it will handle the end_cleaning. */ cleaner->state = cleaner_s_done; } cleaner->overmem_event = event; UNLOCK(&cleaner->lock); if (want_cleaning) begin_cleaning(cleaner);}static voidwater(void *arg, int mark) { dns_acache_t *acache = arg; isc_boolean_t overmem = ISC_TF(mark == ISC_MEM_HIWATER); REQUIRE(DNS_ACACHE_VALID(acache)); isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE, DNS_LOGMODULE_ACACHE, ISC_LOG_DEBUG(1), "acache memory reaches %s watermark, mem inuse %lu", overmem ? "high" : "low", (unsigned long)isc_mem_inuse(acache->mctx)); LOCK(&acache->cleaner.lock); acache->cleaner.overmem = overmem; if (acache->cleaner.overmem_event != NULL) isc_task_send(acache->task, &acache->cleaner.overmem_event); UNLOCK(&acache->cleaner.lock);}/* * The cleaner task is shutting down; do the necessary cleanup. */static voidacache_cleaner_shutdown_action(isc_task_t *task, isc_event_t *event) { dns_acache_t *acache = event->ev_arg; isc_boolean_t should_free = ISC_FALSE; INSIST(task == acache->task); INSIST(event->ev_type == ISC_TASKEVENT_SHUTDOWN); INSIST(DNS_ACACHE_VALID(acache)); ATRACE("acache cleaner shutdown"); if (CLEANER_BUSY(&acache->cleaner)) end_cleaning(&acache->cleaner, event); else isc_event_free(&event); LOCK(&acache->lock); acache->live_cleaners--; INSIST(acache->live_cleaners == 0); if (isc_refcount_current(&acache->refs) == 0) { INSIST(check_noentry(acache) == ISC_TRUE); should_free = ISC_TRUE; } /* * By detaching the timer in the context of its task, * we are guaranteed that there will be no further timer * events. */ if (acache->cleaner.cleaning_timer != NULL) isc_timer_detach(&acache->cleaner.cleaning_timer); /* Make sure we don't reschedule anymore. */ (void)isc_task_purge(task, NULL, DNS_EVENT_ACACHECLEAN, NULL); UNLOCK(&acache->lock); if (should_free) destroy(acache);}/* * Public functions. */isc_result_tdns_acache_create(dns_acache_t **acachep, isc_mem_t *mctx, isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr){ int i; isc_result_t result; dns_acache_t *acache; REQUIRE(acachep != NULL && *acachep == NULL); REQUIRE(mctx != NULL); REQUIRE(taskmgr != NULL); acache = isc_mem_get(mctx, sizeof(*acache)); if (acache == NULL) return (ISC_R_NOMEMORY); ATRACE("create"); result = isc_refcount_init(&acache->refs, 1); if (result != ISC_R_SUCCESS) { isc_mem_put(mctx, acache, sizeof(*acache)); return (result); } result = isc_mutex_init(&acache->lock); if (result != ISC_R_SUCCESS) { isc_refcount_decrement(&acache->refs, NULL); isc_refcount_destroy(&acache->refs); isc_mem_put(mctx, acache, sizeof(*acache)); return (result); } acache->mctx = NULL; isc_mem_attach(mctx, &acache->mctx); ISC_LIST_INIT(acache->entries); acache->shutting_down = ISC_FALSE; acache->task = NULL; acache->entrylocks = NULL; result = isc_task_create(taskmgr, 1, &acache->task); if (result != ISC_R_SUCCESS) { UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_task_create() failed(): %s", dns_result_totext(result)); result = ISC_R_UNEXPECTED; goto cleanup; } isc_task_setname(acache->task, "acachetask", acache); ISC_EVENT_INIT(&acache->cevent, sizeof(acache->cevent), 0, NULL, DNS_EVENT_ACACHECONTROL, shutdown_task, NULL, NULL, NULL, NULL); acache->cevent_sent = ISC_FALSE; acache->dbentries = 0; for (i = 0; i < DBBUCKETS; i++) ISC_LIST_INIT(acache->dbbucket[i]); acache->entrylocks = isc_mem_get(mctx, sizeof(*acache->entrylocks) * DEFAULT_ACACHE_ENTRY_LOCK_COUNT); if (acache->entrylocks == NULL) { result = ISC_R_NOMEMORY; goto cleanup; } for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++) { result = ACACHE_INITLOCK(&acache->entrylocks[i]); if (result != ISC_R_SUCCESS) { while (i-- > 0) ACACHE_DESTROYLOCK(&acache->entrylocks[i]); isc_mem_put(mctx, acache->entrylocks, sizeof(*acache->entrylocks) * DEFAULT_ACACHE_ENTRY_LOCK_COUNT); acache->entrylocks = NULL; goto cleanup; } } acache->live_cleaners = 0; result = acache_cleaner_init(acache, timermgr, &acache->cleaner); if (result != ISC_R_SUCCESS) goto cleanup; acache->stats.cleaner_runs = 0; reset_stats(acache); acache->magic = ACACHE_MAGIC; *acachep = acache; return (ISC_R_SUCCESS); cleanup: if (acache->task != NULL) isc_task_detach(&acache->task); DESTROYLOCK(&acache->lock); isc_refcount_decrement(&acache->refs, NULL); isc_refcount_destroy(&acache->refs); if (acache->entrylocks != NULL) { for (i = 0; i < DEFAULT_ACACHE_ENTRY_LOCK_COUNT; i++) ACACHE_DESTROYLOCK(&acache->entrylocks[i]); isc_mem_put(mctx, acache->entrylocks, sizeof(*acache->entrylocks) * DEFAULT_ACACHE_ENTRY_LOCK_COUNT); } isc_mem_put(mctx, acache, sizeof(*acache)); isc_mem_detach(&mctx); return (result);}voiddns_acache_attach(dns_acache_t *source, dns_acache_t **targetp) { REQUIRE(DNS_ACACHE_VALID(source)); REQUIRE(targetp != NULL && *targetp == NULL); AATRACE(source, "attach"); isc_refcount_increment(&source->refs, NULL); *targetp = source;}voiddns_acache_countquerymiss(dns_acache_t *acache) { acache->stats.misses++; /* XXXSK danger: unlocked! */ acache->stats.queries++; /* XXXSK danger: unlocked! */}voiddns_acache_detach(dns_acache_t **acachep) { dns_acache_t *acache; unsigned int refs; isc_boolean_t should_free = ISC_FALSE; REQUIRE(acachep != NULL && DNS_ACACHE_VALID(*acachep)); acache = *acachep; ATRACE("detach"); isc_refcount_decrement(&acache->refs, &refs); if (refs == 0) { INSIST(check_noentry(acache) == ISC_TRUE); should_free = ISC_TRUE; } *acachep = NULL; /* * If we're exiting and the cleaner task exists, let it free the cache. */ if (should_free && acache->live_cleaners > 0) { isc_task_shutdown(acache->task); should_free = ISC_FALSE; } if (should_free) destroy(acache);}voiddns_acache_shutdown(dns_acache_t *acache) { REQUIRE(DNS_ACACHE_VALID(acache)); LOCK(&acache->lock); ATRACE("shutdown"); if (!acache->shutting_down) { isc_event_t *event; dns_acache_t *acache_evarg = NULL; INSIST(!acache->cevent_sent); acache->shutting_down = ISC_TRUE; isc_mem_setwater(acache->mctx, NULL, NULL, 0, 0); /* * Self attach the object in order to prevent it from being * destroyed while waiting for the event. */ dns_acache_attach(acache, &acache_evarg); event = &acache->cevent; event->ev_arg = acache_evarg; isc_task_send(acache->task, &event); acache->cevent_sent = ISC_TRUE; } UNLOCK(&acache->lock);}isc_result_tdns_acache_setdb(dns_acache_t *acache, dns_db_t *db) { int bucket; dbentry_t *dbentry; isc_result_t result = ISC_R_SUCCESS; REQUIRE(DNS_ACACHE_VALID(acache)); REQUIRE(db != NULL); ATRACE("setdb"); LOCK(&acache->lock); dbentry = NULL; result = finddbent(acache, db, &dbentry); if (result == ISC_R_SUCCESS) { result = ISC_R_EXISTS; goto end; } result = ISC_R_SUCCESS; dbentry = isc_mem_get(acache->mctx, sizeof(*dbentry)); if (dbentry == NULL) { result = ISC_R_NOMEMORY; goto end; } ISC_LINK_INIT(dbentry, link); ISC_LIST_INIT(dbentry->originlist); ISC_LIST_INIT(dbentry->referlist); dbentry->db = NULL; dns_db_attach(db, &dbentry->db); bucket = isc_hash_calc((const unsigned char *)&db, sizeof(db), ISC_TRUE) % DBBUCKETS; ISC_LIST_APPEND(acache->dbbucket[bucket], dbentry, link); acache->dbentries++; end: UNLOCK(&acache->lock); return (result);}isc_result_tdns_acache_putdb(dns_acache_t *acache, dns_db_t *db) { int bucket; isc_result_t result; dbentry_t *dbentry; dns_acacheentry_t *entry; REQUIRE(DNS_ACACHE_VALID(acache)); REQUIRE(db != NULL); ATRACE("putdb"); LOCK(&acache->lock); dbentry = NULL; result = finddbent(acache, db, &dbentry); if (result != ISC_R_SUCCESS) { /* * The entry may have not been created due to memory shortage. */ UNLOCK(&acache->lock); return (ISC_R_NOTFOUND); } /* * Release corresponding cache entries: for each entry, release all * links the entry has, and then callback to the entry holder (if any). * If no other external references exist (this can happen if the * original holder has canceled callback,) destroy it here. */ while ((entry = ISC_LIST_HEAD(dbentry->originlist)) != NULL) { ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); /* * Releasing olink first would avoid finddbent() in * unlink_dbentries(). */ ISC_LIST_UNLINK(dbentry->originlist, entry, olink); if (acache->cleaner.current_entry != entry) ISC_LIST_UNLINK(acache->entries, entry, link); unlink_dbentries(acache, entry); if (entry->callback != NULL) (entry->callback)(entry, &entry->cbarg); entry->callback = NULL; ACACHE_UNLOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); if (acache->cleaner.current_entry != entry) dns_acache_detachentry(&entry); } while ((entry = ISC_LIST_HEAD(dbentry->referlist)) != NULL) { ACACHE_LOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); ISC_LIST_UNLINK(dbentry->referlist, entry, rlink); if (acache->cleaner.current_entry != entry) ISC_LIST_UNLINK(acache->entries, entry, link); unlink_dbentries(acache, entry); if (entry->callback != NULL) (entry->callback)(entry, &entry->cbarg); entry->callback = NULL; ACACHE_UNLOCK(&acache->entrylocks[entry->locknum], isc_rwlocktype_write); if (acache->cleaner.current_entry != entry) dns_acache_detachentry(&entry); }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -