Hello,

this patch implements "Flush zones and RRs cache when handling persistent search reconnection" behaviour as requested
in ticket https://fedorahosted.org/bind-dyndb-ldap/ticket/44 .

Petr^2 Spacek
From 06f38006e841a210d60ae93bb5c9027e40073d84 Mon Sep 17 00:00:00 2001
From: Petr Spacek <pspa...@redhat.com>
Date: Fri, 27 Jul 2012 11:18:42 +0200
Subject: [PATCH] Flush zones and RRs cache when handling persistent search
 reconnection

https://fedorahosted.org/bind-dyndb-ldap/ticket/44

Signed-off-by: Petr Spacek <pspa...@redhat.com>
---
 src/cache.c        | 25 ++++++++++++++++++++++++-
 src/cache.h        |  7 +++++++
 src/ldap_helper.c  | 22 +++++++++++++++++-----
 src/ldap_helper.h  |  2 +-
 src/zone_manager.c |  4 ++--
 5 files changed, 51 insertions(+), 9 deletions(-)

diff --git a/src/cache.c b/src/cache.c
index 28f93c937f23707541a015eb071d3934c96cff1f..898d48b291a83da7f77dbcf79e2bd3e7ff8281aa 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -38,7 +38,7 @@
 #include "util.h"
 
 struct ldap_cache {
-	isc_mutex_t	mutex;
+	isc_mutex_t	mutex; /* TODO: RWLOCK? */
 	isc_mem_t	*mctx;
 	dns_rbt_t	*rbt;
 	isc_interval_t	cache_ttl;
@@ -303,3 +303,26 @@ discard_from_cache(ldap_cache_t *cache, dns_name_t *name)
 
 	return result;
 }
+
+isc_result_t
+flush_ldap_cache(ldap_cache_t *cache)
+{
+	isc_result_t result;
+
+	REQUIRE(cache != NULL);
+
+	LOCK(&cache->mutex);
+	if (!ldap_cache_enabled(cache)) {
+		result = ISC_R_SUCCESS;
+	} else {
+		dns_rbt_destroy(&cache->rbt);
+		CHECK(dns_rbt_create(cache->mctx, cache_node_deleter, NULL,
+				&cache->rbt));
+	}
+
+cleanup:
+	if (result != ISC_R_SUCCESS)
+		log_error_r("cache flush failed");
+	UNLOCK(&cache->mutex);
+	return result;
+}
diff --git a/src/cache.h b/src/cache.h
index 6a4e35611f048eb9d10ded68c12017c6cb25de1a..a7aa5b7e889d9e195484a11dcf4f9a10d811f623 100644
--- a/src/cache.h
+++ b/src/cache.h
@@ -77,4 +77,11 @@ ldap_cache_enabled(ldap_cache_t *cache);
 isc_result_t
 discard_from_cache(ldap_cache_t *cache, dns_name_t *name);
 
+/**
+ * Discard all names from the cache and re-initialize internal RB-tree.
+ * @return ISC_R_SUCCESS even if cache is disabled.
+ */
+isc_result_t
+flush_ldap_cache(ldap_cache_t *cache);
+
 #endif /* !_LD_CACHE_H_ */
diff --git a/src/ldap_helper.c b/src/ldap_helper.c
index daffac7c7825a99a07c333217638d3beaddfaad2..717b7b12007f7db5be42e0ca761760a5da22a2bc 100644
--- a/src/ldap_helper.c
+++ b/src/ldap_helper.c
@@ -1175,11 +1175,14 @@ cleanup:
  * added. In that case, only modify the zone's properties, like the update
  * policy.
  *
+ * @param delete_only Do LDAP vs. zone register cross-check and delete zones
+ *                    which aren't in LDAP, but do not load new zones.
+ *
  * Returns ISC_R_SUCCESS if we found and successfully added at least one zone.
  * Returns ISC_R_FAILURE otherwise.
  */
 isc_result_t
-refresh_zones_from_ldap(ldap_instance_t *ldap_inst)
+refresh_zones_from_ldap(ldap_instance_t *ldap_inst, isc_boolean_t delete_only)
 {
 	isc_result_t result = ISC_R_SUCCESS;
 	ldap_connection_t *ldap_conn = NULL;
@@ -1202,8 +1205,8 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst)
 
 	REQUIRE(ldap_inst != NULL);
 
-	if (ldap_inst->psearch) {
-		/* Watcher does the work for us */
+	if (ldap_inst->psearch && !delete_only) {
+		/* Watcher does the work for us, but deletion is allowed. */
 		return ISC_R_SUCCESS;
 	}
 
@@ -1254,7 +1257,8 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst)
 			continue;
 		}
 
-		CHECK(ldap_parse_zoneentry(entry, ldap_inst));
+		if (!delete_only)
+			CHECK(ldap_parse_zoneentry(entry, ldap_inst));
 		zone_count++;
 	}
 
@@ -1280,10 +1284,14 @@ refresh_zones_from_ldap(ldap_instance_t *ldap_inst)
 		node = NULL;
 		
 		result = dns_rbtnodechain_current(&chain, &fname, &forig, &node);
-		if (result != ISC_R_SUCCESS)
+		if (result != ISC_R_SUCCESS) {
+			if (result != ISC_R_NOTFOUND)
+				log_error_r("unable walk through RB-tree during zone_refresh");
 			goto next;
+		}
 
 		if (dns_name_concatenate(&fname, &forig, &aname, aname.buffer) != ISC_R_SUCCESS) {
+			log_error_r("unable to concatenate DNS names during zone_refresh");
 			goto next;	
 		}
 
@@ -3505,6 +3513,10 @@ restart:
 		}
 	}
 
+	/* Unload old zones and flush record cache */
+	CHECK(refresh_zones_from_ldap(inst, ISC_TRUE));
+	CHECK(flush_ldap_cache(inst->cache));
+
 	while (!inst->exiting) {
 		ret = ldap_result(conn->handle, conn->msgid, 0, &tv,
 				  &ldap_qresult->result);
diff --git a/src/ldap_helper.h b/src/ldap_helper.h
index bc784106abefe15787841578687469539c8052c3..f6cbdc593d91485f767ae5ea6017e114f95733d1 100644
--- a/src/ldap_helper.h
+++ b/src/ldap_helper.h
@@ -82,7 +82,7 @@ new_ldap_instance(isc_mem_t *mctx, const char *db_name,
 		  isc_task_t *task, ldap_instance_t **ldap_instp);
 void destroy_ldap_instance(ldap_instance_t **ldap_inst);
 isc_result_t
-refresh_zones_from_ldap(ldap_instance_t *ldap_inst);
+refresh_zones_from_ldap(ldap_instance_t *ldap_inst, isc_boolean_t delete_only);
 
 /* Functions for writing to LDAP. */
 isc_result_t write_to_ldap(dns_name_t *owner, ldap_instance_t *ldap_inst,
diff --git a/src/zone_manager.c b/src/zone_manager.c
index eb761aa922d4f61b2659b2740093cef9bb102624..ca3edd010e5f6ea94adb57e5ae5e915a834e52a0 100644
--- a/src/zone_manager.c
+++ b/src/zone_manager.c
@@ -180,7 +180,7 @@ manager_create_db_instance(isc_mem_t *mctx, const char *name,
 	APPEND(instance_list, db_inst, link);
 	UNLOCK(&instance_list_lock);
 
-	result = refresh_zones_from_ldap(db_inst->ldap_inst);
+	result = refresh_zones_from_ldap(db_inst->ldap_inst, ISC_FALSE);
 	if (result != ISC_R_SUCCESS) {
 		/* In case we don't find any zones, we at least return
 		 * ISC_R_SUCCESS so BIND won't exit because of this. */
@@ -221,7 +221,7 @@ refresh_zones_action(isc_task_t *task, isc_event_t *event)
 
 	UNUSED(task);
 
-	refresh_zones_from_ldap(db_inst->ldap_inst);
+	refresh_zones_from_ldap(db_inst->ldap_inst, ISC_FALSE);
 
 	isc_event_free(&event);
 }
-- 
1.7.11.2

_______________________________________________
Freeipa-devel mailing list
Freeipa-devel@redhat.com
https://www.redhat.com/mailman/listinfo/freeipa-devel

Reply via email to