/* Copyright (c) 2011-2018 Dovecot authors, see the included COPYING file */ #include "lib.h" #include "ioloop.h" #include "hash.h" #include "llist.h" #include "global-memory.h" #include "stats-settings.h" #include "mail-stats.h" #include "mail-domain.h" static HASH_TABLE(char *, struct mail_domain *) mail_domains_hash; /* domains are sorted by their last_update timestamp, oldest first */ static struct mail_domain *mail_domains_head, *mail_domains_tail; struct mail_domain *stable_mail_domains; static size_t mail_domain_memsize(const struct mail_domain *domain) { return sizeof(*domain) + strlen(domain->name) + 1; } struct mail_domain *mail_domain_login_create(const char *name) { struct mail_domain *domain; domain = hash_table_lookup(mail_domains_hash, name); if (domain != NULL) { return domain; } domain = i_malloc(MALLOC_ADD(sizeof(struct mail_domain), stats_alloc_size())); domain->stats = (void *)(domain + 1); domain->name = i_strdup(name); domain->reset_timestamp = ioloop_time; hash_table_insert(mail_domains_hash, domain->name, domain); DLLIST_PREPEND_FULL(&stable_mail_domains, domain, stable_prev, stable_next); global_memory_alloc(mail_domain_memsize(domain)); return domain; } void mail_domain_login(struct mail_domain *domain) { domain->num_logins++; domain->num_connected_sessions++; mail_domain_refresh(domain, NULL); } void mail_domain_disconnected(struct mail_domain *domain) { i_assert(domain->num_connected_sessions > 0); domain->num_connected_sessions--; mail_global_disconnected(); } struct mail_domain *mail_domain_lookup(const char *name) { return hash_table_lookup(mail_domains_hash, name); } void mail_domain_ref(struct mail_domain *domain) { domain->refcount++; } void mail_domain_unref(struct mail_domain **_domain) { struct mail_domain *domain = *_domain; i_assert(domain->refcount > 0); domain->refcount--; *_domain = NULL; } static void mail_domain_free(struct mail_domain *domain) { i_assert(domain->refcount == 0); i_assert(domain->users == NULL); global_memory_free(mail_domain_memsize(domain)); hash_table_remove(mail_domains_hash, domain->name); DLLIST_REMOVE_FULL(&stable_mail_domains, domain, stable_prev, stable_next); DLLIST2_REMOVE_FULL(&mail_domains_head, &mail_domains_tail, domain, sorted_prev, sorted_next); i_free(domain->name); i_free(domain); } void mail_domain_refresh(struct mail_domain *domain, const struct stats *diff_stats) { if (diff_stats != NULL) stats_add(domain->stats, diff_stats); domain->last_update = ioloop_timeval; DLLIST2_REMOVE_FULL(&mail_domains_head, &mail_domains_tail, domain, sorted_prev, sorted_next); DLLIST2_APPEND_FULL(&mail_domains_head, &mail_domains_tail, domain, sorted_prev, sorted_next); mail_global_refresh(diff_stats); } void mail_domains_free_memory(void) { unsigned int diff; while (mail_domains_head != NULL && mail_domains_head->refcount == 0) { mail_domain_free(mail_domains_head); if (global_used_memory < stats_settings->memory_limit || mail_domains_head == NULL) break; diff = ioloop_time - mail_domains_head->last_update.tv_sec; if (diff < stats_settings->domain_min_time) break; } } void mail_domains_init(void) { hash_table_create(&mail_domains_hash, default_pool, 0, str_hash, strcmp); } void mail_domains_deinit(void) { while (mail_domains_head != NULL) mail_domain_free(mail_domains_head); hash_table_destroy(&mail_domains_hash); }