From 1a242086588f455af626db859769d9ba5b1ea9e4 Mon Sep 17 00:00:00 2001 From: Wouter Wijngaards Date: Fri, 24 Jan 2014 11:21:15 +0000 Subject: [PATCH] - speed up unbound (reports say it could be up to 10%), by reducing lock contention on localzones.lock. It is changed to an rwlock. git-svn-id: file:///svn/unbound/trunk@3048 be551aaa-1e26-0410-a405-d3ace91eadb9 --- daemon/remote.c | 20 +++++++-------- doc/Changelog | 2 ++ libunbound/libunbound.c | 12 ++++----- services/localzone.c | 56 +++++++++++++++++++++-------------------- services/localzone.h | 2 +- 5 files changed, 48 insertions(+), 44 deletions(-) diff --git a/daemon/remote.c b/daemon/remote.c index 9f93e6043..0db1f48b8 100644 --- a/daemon/remote.c +++ b/daemon/remote.c @@ -981,7 +981,7 @@ do_zone_add(SSL* ssl, struct worker* worker, char* arg) free(nm); return; } - lock_quick_lock(&worker->daemon->local_zones->lock); + lock_rw_wrlock(&worker->daemon->local_zones->lock); if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN))) { /* already present in tree */ @@ -989,17 +989,17 @@ do_zone_add(SSL* ssl, struct worker* worker, char* arg) z->type = t; /* update type anyway */ lock_rw_unlock(&z->lock); free(nm); - lock_quick_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&worker->daemon->local_zones->lock); send_ok(ssl); return; } if(!local_zones_add_zone(worker->daemon->local_zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN, t)) { - lock_quick_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&worker->daemon->local_zones->lock); ssl_printf(ssl, "error out of memory\n"); return; } - lock_quick_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&worker->daemon->local_zones->lock); send_ok(ssl); } @@ -1013,13 +1013,13 @@ do_zone_remove(SSL* ssl, struct worker* worker, char* arg) struct local_zone* z; if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) return; - lock_quick_lock(&worker->daemon->local_zones->lock); + lock_rw_wrlock(&worker->daemon->local_zones->lock); if((z=local_zones_find(worker->daemon->local_zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN))) { /* present in tree */ local_zones_del_zone(worker->daemon->local_zones, z); } - lock_quick_unlock(&worker->daemon->local_zones->lock); + lock_rw_unlock(&worker->daemon->local_zones->lock); free(nm); send_ok(ssl); } @@ -1974,7 +1974,7 @@ do_list_local_zones(SSL* ssl, struct worker* worker) struct local_zones* zones = worker->daemon->local_zones; struct local_zone* z; char buf[257]; - lock_quick_lock(&zones->lock); + lock_rw_rdlock(&zones->lock); RBTREE_FOR(z, struct local_zone*, &zones->ztree) { lock_rw_rdlock(&z->lock); dname_str(z->name, buf); @@ -1982,7 +1982,7 @@ do_list_local_zones(SSL* ssl, struct worker* worker) local_zone_type2str(z->type)); lock_rw_unlock(&z->lock); } - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); } /** do the list_local_data command */ @@ -1995,7 +1995,7 @@ do_list_local_data(SSL* ssl, struct worker* worker) struct local_rrset* p; char* s = (char*)sldns_buffer_begin(worker->env.scratch_buffer); size_t slen = sldns_buffer_capacity(worker->env.scratch_buffer); - lock_quick_lock(&zones->lock); + lock_rw_rdlock(&zones->lock); RBTREE_FOR(z, struct local_zone*, &zones->ztree) { lock_rw_rdlock(&z->lock); RBTREE_FOR(d, struct local_data*, &z->data) { @@ -2016,7 +2016,7 @@ do_list_local_data(SSL* ssl, struct worker* worker) } lock_rw_unlock(&z->lock); } - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); } /** tell other processes to execute the command */ diff --git a/doc/Changelog b/doc/Changelog index 1347b8f44..2cf92384f 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -2,6 +2,8 @@ - Change unbound-event.h to use void* buffer, length idiom. - iana portlist updated. - unbound-event.h is installed if you configure --enable-event-api. + - speed up unbound (reports say it could be up to 10%), by reducing + lock contention on localzones.lock. It is changed to an rwlock. 21 January 2014: Wouter - Fix #547: no trustanchor written if filesystem full, fclose checked. diff --git a/libunbound/libunbound.c b/libunbound/libunbound.c index dfcce0f8f..d3a6fc256 100644 --- a/libunbound/libunbound.c +++ b/libunbound/libunbound.c @@ -1125,23 +1125,23 @@ int ub_ctx_zone_add(struct ub_ctx* ctx, const char *zone_name, return UB_SYNTAX; } - lock_quick_lock(&ctx->local_zones->lock); + lock_rw_wrlock(&ctx->local_zones->lock); if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN))) { /* already present in tree */ lock_rw_wrlock(&z->lock); z->type = t; /* update type anyway */ lock_rw_unlock(&z->lock); - lock_quick_unlock(&ctx->local_zones->lock); + lock_rw_unlock(&ctx->local_zones->lock); free(nm); return UB_NOERROR; } if(!local_zones_add_zone(ctx->local_zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN, t)) { - lock_quick_unlock(&ctx->local_zones->lock); + lock_rw_unlock(&ctx->local_zones->lock); return UB_NOMEM; } - lock_quick_unlock(&ctx->local_zones->lock); + lock_rw_unlock(&ctx->local_zones->lock); return UB_NOERROR; } @@ -1160,13 +1160,13 @@ int ub_ctx_zone_remove(struct ub_ctx* ctx, const char *zone_name) return UB_SYNTAX; } - lock_quick_lock(&ctx->local_zones->lock); + lock_rw_wrlock(&ctx->local_zones->lock); if((z=local_zones_find(ctx->local_zones, nm, nmlen, nmlabs, LDNS_RR_CLASS_IN))) { /* present in tree */ local_zones_del_zone(ctx->local_zones, z); } - lock_quick_unlock(&ctx->local_zones->lock); + lock_rw_unlock(&ctx->local_zones->lock); free(nm); return UB_NOERROR; } diff --git a/services/localzone.c b/services/localzone.c index 29df15fae..f1a9aaa95 100644 --- a/services/localzone.c +++ b/services/localzone.c @@ -59,7 +59,7 @@ local_zones_create(void) if(!zones) return NULL; rbtree_init(&zones->ztree, &local_zone_cmp); - lock_quick_init(&zones->lock); + lock_rw_init(&zones->lock); lock_protect(&zones->lock, &zones->ztree, sizeof(zones->ztree)); /* also lock protects the rbnode's in struct local_zone */ return zones; @@ -78,7 +78,7 @@ local_zones_delete(struct local_zones* zones) { if(!zones) return; - lock_quick_destroy(&zones->lock); + lock_rw_destroy(&zones->lock); /* walk through zones and delete them all */ traverse_postorder(&zones->ztree, lzdel, NULL); free(zones); @@ -174,16 +174,16 @@ lz_enter_zone_dname(struct local_zones* zones, uint8_t* nm, size_t len, } /* add to rbtree */ - lock_quick_lock(&zones->lock); + lock_rw_wrlock(&zones->lock); lock_rw_wrlock(&z->lock); if(!rbtree_insert(&zones->ztree, &z->node)) { log_warn("duplicate local-zone"); lock_rw_unlock(&z->lock); local_zone_delete(z); - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); return NULL; } - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); return z; } @@ -490,14 +490,14 @@ lz_enter_rr_str(struct local_zones* zones, const char* rr) return 0; } labs = dname_count_size_labels(rr_name, &len); - lock_quick_lock(&zones->lock); + lock_rw_rdlock(&zones->lock); z = local_zones_lookup(zones, rr_name, len, labs, rr_class); if(!z) { - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); fatal_exit("internal error: no zone for rr %s", rr); } lock_rw_wrlock(&z->lock); - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); free(rr_name); r = lz_enter_rr_into_zone(z, rr); lock_rw_unlock(&z->lock); @@ -530,13 +530,13 @@ lz_exists(struct local_zones* zones, const char* name) log_err("bad name %s", name); return 0; } - lock_quick_lock(&zones->lock); + lock_rw_rdlock(&zones->lock); if(rbtree_search(&zones->ztree, &z.node)) { - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); free(z.name); return 1; } - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); free(z.name); return 0; } @@ -693,7 +693,7 @@ init_parents(struct local_zones* zones) { struct local_zone* node, *prev = NULL, *p; int m; - lock_quick_lock(&zones->lock); + lock_rw_wrlock(&zones->lock); RBTREE_FOR(node, struct local_zone*, &zones->ztree) { lock_rw_wrlock(&node->lock); node->parent = NULL; @@ -718,7 +718,7 @@ init_parents(struct local_zones* zones) prev = node; lock_rw_unlock(&node->lock); } - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); } /** enter implicit transparent zone for local-data: without local-zone: */ @@ -748,7 +748,7 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg) return 0; } labs = dname_count_size_labels(rr_name, &len); - lock_quick_lock(&zones->lock); + lock_rw_rdlock(&zones->lock); if(!local_zones_lookup(zones, rr_name, len, labs, rr_class)) { if(!have_name) { dclass = rr_class; @@ -763,7 +763,7 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg) /* process other classes later */ free(rr_name); have_other_classes = 1; - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); continue; } /* find smallest shared topdomain */ @@ -774,7 +774,7 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg) match = m; } } else free(rr_name); - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); } if(have_name) { uint8_t* n2; @@ -919,7 +919,7 @@ local_zone_out(struct local_zone* z) void local_zones_print(struct local_zones* zones) { struct local_zone* z; - lock_quick_lock(&zones->lock); + lock_rw_rdlock(&zones->lock); log_info("number of auth zones %u", (unsigned)zones->ztree.count); RBTREE_FOR(z, struct local_zone*, &zones->ztree) { lock_rw_rdlock(&z->lock); @@ -956,7 +956,7 @@ void local_zones_print(struct local_zones* zones) local_zone_out(z); lock_rw_unlock(&z->lock); } - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); } /** encode answer consisting of 1 rrset */ @@ -1106,15 +1106,15 @@ local_zones_answer(struct local_zones* zones, struct query_info* qinfo, struct local_data* ld; struct local_zone* z; int r; - lock_quick_lock(&zones->lock); + lock_rw_rdlock(&zones->lock); z = local_zones_lookup(zones, qinfo->qname, qinfo->qname_len, labs, qinfo->qclass); if(!z) { - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); return 0; } lock_rw_rdlock(&z->lock); - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); if(local_data_answer(z, qinfo, edns, buf, temp, labs, &ld)) { lock_rw_unlock(&z->lock); @@ -1238,20 +1238,22 @@ local_zones_add_RR(struct local_zones* zones, const char* rr) return 0; } labs = dname_count_size_labels(rr_name, &len); - lock_quick_lock(&zones->lock); + /* could first try readlock then get writelock if zone does not exist, + * but we do not add enough RRs (from multiple threads) to optimize */ + lock_rw_wrlock(&zones->lock); z = local_zones_lookup(zones, rr_name, len, labs, rr_class); if(!z) { z = local_zones_add_zone(zones, rr_name, len, labs, rr_class, local_zone_transparent); if(!z) { - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); return 0; } } else { free(rr_name); } lock_rw_wrlock(&z->lock); - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); r = lz_enter_rr_into_zone(z, rr); lock_rw_unlock(&z->lock); return r; @@ -1297,15 +1299,15 @@ void local_zones_del_data(struct local_zones* zones, /* find zone */ struct local_zone* z; struct local_data* d; - lock_quick_lock(&zones->lock); + lock_rw_rdlock(&zones->lock); z = local_zones_lookup(zones, name, len, labs, dclass); if(!z) { /* no such zone, we're done */ - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); return; } lock_rw_wrlock(&z->lock); - lock_quick_unlock(&zones->lock); + lock_rw_unlock(&zones->lock); /* find the domain */ d = lz_find_node(z, name, len, labs); diff --git a/services/localzone.h b/services/localzone.h index 68100ea7f..2db586750 100644 --- a/services/localzone.h +++ b/services/localzone.h @@ -78,7 +78,7 @@ enum localzone_type { */ struct local_zones { /** lock on the localzone tree */ - lock_quick_t lock; + lock_rw_t lock; /** rbtree of struct local_zone */ rbtree_t ztree; }; -- 2.47.2