PERFORCE change 124745 for review

Fredrik Lindberg fli at FreeBSD.org
Sun Aug 5 11:46:09 PDT 2007


http://perforce.freebsd.org/chv.cgi?CH=124745

Change 124745 by fli at fli_nexus on 2007/08/05 18:45:59

	- Refactor the record database (again..).  Introduce "virtual"
	         records and resources that are built upon configuration data,
	  real records are resources are created from these templates.
	  This allows (even) more dynamically created records than before,
	  which is needed to properly support database mainpulation from
	  client applications (via the unix domain socket).
	- Also adds proper locking which was long over due.

Affected files ...

.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.c#3 edit
.. //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.h#2 edit

Differences ...

==== //depot/projects/soc2007/fli-mdns_sd/mdnsd/dbrec.c#3 (text+ko) ====

@@ -1,5 +1,5 @@
 /*-
- * Copyright (c) 2007 Fredrik Lindberg
+ * Copyright (c) 2007 Fredbik Lindberg
  * All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -36,20 +36,28 @@
 #include "var.h"
 
 static void record_type_del_cb(struct record_type *, void *);
-static void rec_update(struct dbr_rec *, struct vt_data *, size_t);
+static void rec_update(struct dbr_ident *, struct vt_data *, size_t);
 static void rec_var_update(void *);
-static inline void rec_pastop(struct dbr_rec *);
+static inline void rec_pastop(struct dbr_ident *);
+static struct dbr_rec * rec_add(struct dbr_ident *, wchar_t *);
 static void rec_del(struct dbr_rec *);
-static void res_update(struct dbr_res *, wchar_t **, size_t);
+static void res_update(struct dbr_ident_res *, wchar_t **, size_t);
 static void res_var_update(void *);
+static struct dbr_res * res_add(struct dbr_rec *, struct dbr_ident_res *,
+    struct dbr_res *, wchar_t *);
 static void res_del(struct dbr_res *);
 
+static void ident_del(struct dbr *, struct dbr_ident *);
+static int ident_setname(struct dbr_ident *, int);
+static int ident_res_del(struct dbr *, struct dbr_ident_res *);
+
 static int dbr_pac_add(struct dbr_pac *, struct dbr_rec *, int);
 static int dbr_pac_del(struct dbr_rec *, int);
 static void dbr_pac_start(struct dbr_pac *, int, int, void *);
 static int probe_step(const struct event_tmr *, const ev_arg);
 static int an_step(const struct event_tmr *, const ev_arg);
 
+
 /*
  * Initialize a database record system
  */
@@ -61,6 +69,7 @@
 	dbr->dbr_ctx = context;
 	MDNS_INIT_SET(dbr, dbr_magic);
 	hashtbl_init(&dbr->dbr_ident, 8, 512, 3);
+	TAILQ_INIT(&dbr->dbr_ilist);
 
 	var_init(&dbr->dbr_vars, mif->mif_glob->g_evl, dbr);
 	/* We only do the IN class */
@@ -68,16 +77,6 @@
 	dprintf(DEBUG_DBR, "Database records initialized");
 }
 
-static void
-record_del_cb(struct record *r, __unused void *arg)
-{
-	struct dbr_rec *dr;
-
-	dr = record_getparent(r);
-	MDNS_INIT_ASSERT(dr, dr_magic);
-	dbr_del(dr);
-}
-
 /*
  * Destroy a database record system
  */
@@ -85,76 +84,29 @@
 dbr_destroy(struct dbr *dbr)
 {
 	struct md_if *mif;
+	struct dbr_ident *dbi, *dbi2;
 
 	MDNS_INIT_ASSERT(dbr, dbr_magic);
+	RW_WLOCK(dbr, dbr_lock);
 	mif = dbr->dbr_ctx;
 
-	records_foreach(&dbr->dbr_recs, record_del_cb, NULL);
+	TAILQ_FOREACH_SAFE(dbi, &dbr->dbr_ilist, dbi_next, dbi2) {
+		ident_del(dbr, dbi);
+	}
+
 	records_destroy(&dbr->dbr_recs);
 	var_destroy(&dbr->dbr_vars, mif->mif_glob->g_evl);
 	hashtbl_destroy(&dbr->dbr_ident);
+
+	RW_UNLOCK(dbr, dbr_lock);
+	RW_DESTROY(dbr, dbr_lock);
 	MDNS_INIT_UNSET(dbr, dbr_magic);
-
 	dprintf(DEBUG_DBR, "Database records destroyed");
 }
 
 /*
- * Clone a record
- */
-static struct dbr_rec *
-clone_rec(struct dbr_rec *orig)
-{
-	struct dbr_rec *dr;
-
-	dr = malloc(sizeof(struct dbr_rec));
-	if (dr == NULL)
-		return (NULL);
-	memcpy(dr, orig, sizeof(struct dbr_rec));
-	dr->dr_flags |= DR_CLONE;	
-	TAILQ_INSERT_TAIL(&orig->dr_clone.head, dr, dr_clone.next);
-	dprintf(DEBUG_DBR, "Database record cloned dr=%x, source=%x", dr, orig);
-	return (dr);
-}
-
-/*
- * Clone all resources from `orig' onto `dr'
- */
-static void
-clone_rec_res(struct dbr_rec *orig, struct dbr_rec *dr)
-{
-	struct record *r;
-	struct record_type *rt;
-	struct record_res *rr;
-	struct dbr_res *ds;
-	struct dbr_rec *dr2;
-	void *res;
-	int ptr;
-
-	MDNS_INIT_ASSERT(dr, dr_magic);
-	MDNS_INIT_ASSERT(orig, dr_magic);
-	r = &orig->dr_rec;
-	MDNS_INIT_ASSERT(r, r_magic);
-
-	record_foreach(rt, r) {
-		record_type_foreach(rr, rt) {
-			ds = record_res_getparent(rr);
-			ptr = ds->ds_flags & DS_POINTER;
-			if (ptr) {
-				dr2 = ds->ds_vdata.rec;
-				res = dr2->dr_ident;
-			}
-			else
-				res = ds->ds_vdata.wp;
-
-			dbr_res_add(dr, rt->rt_type, ds->ds_ttl, res, ptr);
-		}
-	}
-	dprintf(DEBUG_DBR, "Cloned resources from %x to %x", orig, dr);
-}
-
-/*
  * Update a database record
- *   dr  - Database record
+ *   dbi  - Database record set identifier
  *   vtd - Arrays of expanded names
  *   vtd_len - Array length
  *
@@ -163,81 +115,59 @@
  * then those clones are removed.
  */
 static void
-rec_update(struct dbr_rec *dr, struct vt_data *vtd, size_t vtd_len)
+rec_update(struct dbr_ident *dbi, struct vt_data *vtd, size_t vtd_len)
 {
-	struct dbr_rec *dr_clone, *dr_tmp;
-	struct dbr_res *ds, *ds2;
+	struct dbr_rec *dr, *dr2;
 	struct dbr *dbr;
+	struct dbr_ident_res *dir, *dir2;
 	struct record *r;
 	uint32_t i;
 	int32_t diff;
 	wchar_t **names;
 	char *nam;
 
-	MDNS_INIT_ASSERT(dr, dr_magic);
-	dbr = dr->dr_dbr;
+	MDNS_INIT_ASSERT(dbi, dbi_magic);
+	dbr = dbi->dbi_dbr;
 	MDNS_INIT_ASSERT(dbr, dbr_magic);
 
-	assert(dr == dr->dr_chead);
-
 	/* Stop pending probes/announces */
-	rec_pastop(dr);
+	rec_pastop(dbi);
 
 	/*
 	 * If the provided array length is 0 there are no available
 	 * names, invalidate record and remove all clones.
 	 */
 	if (vtd_len == 0) {
-		if (dr->dr_name != NULL)
-			free(dr->dr_name);
-		dr->dr_name = NULL;
-		dr->dr_flags |= DR_INVALID;
-		dr->dr_flags &= ~DR_OK;
-
-		TAILQ_FOREACH_SAFE(dr_clone, &dr->dr_clone.head,
-		    dr_clone.next, dr_tmp) {
-			rec_del(dr_clone);
+		TAILQ_FOREACH_SAFE(dr, &dbi->dbi_rech, dr_next, dr2) {
+			rec_del(dr);
 		}
 
-		/*
-		 * Invalidate all database resources that are using this
-		 * record name as their data source.
-		 */
-		TAILQ_FOREACH(ds, &dr->dr_res_ptr, ds_ptr_next) {
-			ds->ds_flags |= DS_INVALID;
-			free(ds->ds_data);
-			ds->ds_data = NULL;
+		/* Clear resources that points to this record */
+		TAILQ_FOREACH(dir, &dbi->dbi_res_ptr, dir_ptr_next) {
+			MTX_LOCK(dir, dir_mtx);
+			res_update(dir, NULL, 0);
+			MTX_UNLOCK(dir, dir_mtx);
 		}
 		return;
 	}
 
-	i = 1;
-	nam = mdns_name_encode(vtd[0].vtd_str, vtd[0].vtd_len, MDNS_ENC_AUTO);
-	r = &dr->dr_rec;
-	if (dr->dr_name != NULL)
-		free(dr->dr_name);
-	record_setname(r, nam);
-
-	free(nam);
-	dr->dr_name = vtd[0].vtd_str;
-	dr->dr_flags &= ~(DR_OK | DR_INVALID);
-
 	/*
 	 * Replace names as long as there are enough clones
 	 * and results available.
 	 */
-	TAILQ_FOREACH(dr_clone, &dr->dr_clone.head, dr_clone.next) {
-		if ((i - 1) == dr->dr_clones || i == vtd_len)
+	i = 0;
+	TAILQ_FOREACH(dr, &dbi->dbi_rech, dr_next) {
+		if (i == dbi->dbi_records || i == vtd_len)
 			break;
-		r = &dr_clone->dr_rec;
+		r = &dr->dr_rec;
+		if (dr->dr_name != NULL)
+			free(dr->dr_name);
 		nam = mdns_name_encode(vtd[i].vtd_str, vtd[i].vtd_len,
 		    MDNS_ENC_AUTO);
 		record_setname(r, nam);
 		free(nam);
-		if (dr_clone->dr_name != NULL)
-			free(dr_clone->dr_name);
-		dr_clone->dr_name = vtd[i].vtd_str;
-		dr_clone->dr_flags &= ~DR_OK;
+		dr->dr_name = _wcsdup(vtd[i].vtd_str);
+		dr->dr_flags &= ~DR_OK;
 		i++;
 	}
 
@@ -245,41 +175,34 @@
 	if (vtd_len > i) {
 		diff = vtd_len - i;
 		while (diff-- > 0) {
-			dr_clone = clone_rec(dr);
-			dr_clone->dr_clones = 0;
-			dr->dr_clones++;
-			r = &dr_clone->dr_rec;
-			nam = mdns_name_encode(vtd[i].vtd_str, vtd[i].vtd_len,
-				MDNS_ENC_AUTO);
-			record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, nam);
-			record_setparent(r, dr_clone);
-			clone_rec_res(dr, dr_clone);
-			free(nam);
-			dr_clone->dr_name = vtd[i].vtd_str;
+			rec_add(dbi, vtd[i].vtd_str);
 			i++;
 		}
 	}
 	/* More clones than results, shrink */
-	else if (dr->dr_clones >= i) {
-		diff = dr->dr_clones - i;
+	else if (dbi->dbi_records > i) {
+		diff = dbi->dbi_records - 1;
 		while (diff-- >= 0) {
-			dr_tmp = TAILQ_LAST(&dr->dr_clone.head, recclone_head);
-			rec_del(dr_tmp);
+			dr = TAILQ_LAST(&dbi->dbi_rech, rechead);
+			rec_del(dr);
 		}
 	}
 
 	/* Update resources that points to this record */
 	names = malloc(sizeof(wchar_t *) * vtd_len);
-	TAILQ_FOREACH_SAFE(ds, &dr->dr_res_ptr, ds_ptr_next, ds2) {
-		for (i = 0; i < vtd_len; i++)
-			names[i] = _wcsdup(vtd[i].vtd_str);
-		res_update(ds, names, vtd_len);
+	for (i = 0; i < vtd_len; i++)
+		names[i] = vtd[i].vtd_str;
+
+	TAILQ_FOREACH_SAFE(dir, &dbi->dbi_res_ptr, dir_ptr_next, dir2) {
+		res_update(dir, names, vtd_len);
 	}
 	free(names);
 
+#if 0
 	dprintf(DEBUG_DBR,
 	    "Database record r=%x, (%ls) updated, flags=%x, clones=%d",
 	    dr, dr->dr_names[dr->dr_cur], dr->dr_flags, dr->dr_clones);
+#endif
 }
 
 /*
@@ -290,362 +213,901 @@
 rec_var_update(void *ptr)
 {
 	struct dbr *dbr;
-	struct dbr_rec *dr, *dr2;
+	struct dbr_ident *dbi, *dbi2;
+	struct dbr_ident_res *dir;
+	struct dbr_rec *dr;
 	struct dbr_pac *pac;
-	struct dbr_res *ds;
-	struct record *r;
 	struct vt_data *vtd;
 	size_t vtd_len;
 	wchar_t *wp;
 
-	dr = ptr;
-	MDNS_INIT_ASSERT(dr, dr_magic);
-	dbr = dr->dr_dbr;
+	dbi = ptr;
+	MDNS_INIT_ASSERT(dbi, dbi_magic);
+	dbr = dbi->dbi_dbr;
 	MDNS_INIT_ASSERT(dbr, dbr_magic);
-	r = &dr->dr_rec;
 
-	assert(dr == dr->dr_chead);
+	RW_WLOCK(dbr, dbr_lock);
+	MTX_LOCK(dbi, dbi_mtx);
 
-	wp = dr->dr_names[dr->dr_cur];
+	wp = dbi->dbi_names[dbi->dbi_curnam];
 	vtd = var_expand(&dbr->dbr_vars, wp, &vtd_len);
-	rec_update(dr, vtd, vtd_len);
+	rec_update(dbi, vtd, vtd_len);
 	free(vtd);
 
 	/*
 	 * Create a probe context and and affected records to it
 	 */
 	pac = dbr_pac_new(dbr, PAC_PROBE);
-	dbr_probe_add(pac, dr);
-	TAILQ_FOREACH(dr2, &dr->dr_clone.head, dr_clone.next) {
-		dbr_probe_add(pac, dr2);
+	TAILQ_FOREACH(dr, &dbi->dbi_rech, dr_next) {
+		dbr_probe_add(pac, dr);
 	}
+
 	/* Resources pointing to this record */
-	TAILQ_FOREACH(ds, &dr->dr_res_ptr, ds_ptr_next) {
-		MDNS_INIT_ASSERT(ds, ds_magic);
-		dr2 = ds->ds_type->dt_rec;
-		MDNS_INIT_ASSERT(dr2, dr_magic);
-		dbr_probe_add(pac, dr2);
+	TAILQ_FOREACH(dir, &dbi->dbi_res_ptr, dir_ptr_next) {
+		MDNS_INIT_ASSERT(dir, dir_magic);
+		dbi2 = dir->dir_dbi;
+		MDNS_INIT_ASSERT(dbi2, dbi_magic);
+
+		TAILQ_FOREACH(dr, &dbi2->dbi_rech, dr_next) {
+			dbr_probe_add(pac, dr);
+		}
 	}
+
+	MTX_UNLOCK(dbi, dbi_mtx);
+	RW_UNLOCK(dbr, dbr_lock);
+
 	dbr_probe_start(pac);
 }
 
 /*
- * Add a new database record
- *   dbr   - Record database
- *   ident - Unique record set identifier
- *   names - Array of un-expanded alternativ names (NULL-terminated)
- *   shared  - Shared record?
- *
+ * Select a name from the alternatives to use
  */
-struct dbr_rec *
-dbr_add(struct dbr *dbr, char *ident, wchar_t **names, int shared)
+static int
+ident_setname(struct dbr_ident *dbi, int namsel)
 {
-	wchar_t *wp;
+	struct dbr *dbr;
 	struct vt_data *vtd;
 	size_t vtd_len;
-	struct dbr_rec *dr;
-	struct record *r;
-	int error;
-	uint32_t i;
+	wchar_t *wp;
+
+	dbr = dbi->dbi_dbr;
+	MDNS_INIT_ASSERT(dbr, dbr_magic);
+
+	if (namsel >= dbi->dbi_numnam)
+		return (-1);
+
+	wp = dbi->dbi_names[namsel];
+	vtd = var_expand(&dbr->dbr_vars, wp, &vtd_len);
+	if (vtd_len > 0) {
+		var_dereg(&dbr->dbr_vars,
+		   dbi->dbi_names[dbi->dbi_curnam], dbi);
+		var_reg(&dbr->dbr_vars, wp, rec_var_update, dbi);
+		dbi->dbi_curnam = namsel;
+		rec_update(dbi, vtd, vtd_len);
+	}
+	else {
+		var_vtdfree(vtd, vtd_len);
+		return (-1);
+	}
+	var_vtdfree(vtd, vtd_len);
+	return (0);
+}
+
+/*
+ * Create a record set identifier
+ *  dbr   - Database record handle
+ *  ident - Record set identifier to create
+ */
+int
+dbr_ident_add(struct dbr *dbr, char *ident)
+{
+	struct dbr_ident *dbi;
+	size_t ilen;
+
+	ilen = strlen(ident);
+
+	RW_WLOCK(dbr, dbr_lock);
+	dbi = hashtbl_find(&dbr->dbr_ident, ident, ilen);
+	if (dbi != NULL) {
+		dprintf(DEBUG_DBR, "Record set %s does already exists dbi=%x",
+		    ident, dbi);
+		goto out;
+	}
+
+	dbi = malloc(sizeof(struct dbr_ident));
+	if (dbi == NULL)
+		goto out;
+	bzero(dbi, sizeof(struct dbr_ident));
+	MTX_INIT(dbi, dbi_mtx, NULL);	
+	dbi->dbi_dbr = dbr;
+	dbi->dbi_ident = strdup(ident);
+	TAILQ_INIT(&dbi->dbi_rech);
+	TAILQ_INIT(&dbi->dbi_res);
+	TAILQ_INIT(&dbi->dbi_res_ptr);
+	MDNS_INIT_SET(dbi, dbi_magic);
+
+	TAILQ_INSERT_TAIL(&dbr->dbr_ilist, dbi, dbi_next);
+	hashtbl_add(&dbr->dbr_ident, dbi->dbi_ident, ilen, dbi, 0);
+
+	RW_UNLOCK(dbr, dbr_lock);
+	return (0);
+out:
+	RW_UNLOCK(dbr, dbr_lock);
+	return (-1);
+}
+
+static void
+ident_del(struct dbr *dbr, struct dbr_ident *dbi)
+{
+	struct dbr_ident_res *dir, *dir2;
+	size_t ilen;
+	int i;
+
+	TAILQ_REMOVE(&dbr->dbr_ilist, dbi, dbi_next);
+	ilen = strlen(dbi->dbi_ident);
+	hashtbl_del(&dbr->dbr_ident, dbi->dbi_ident, ilen);
+
+	if (dbi->dbi_numnam > 0)
+		var_dereg(&dbr->dbr_vars, dbi->dbi_names[dbi->dbi_curnam], dbi);
+
+	/* Remove resources pointing to this record */
+	TAILQ_FOREACH_SAFE(dir, &dbi->dbi_res_ptr, dir_ptr_next, dir2) {
+		ident_res_del(dbr, dir);
+	}
+
+	/* Remove resources on this record */
+	TAILQ_FOREACH_SAFE(dir, &dbi->dbi_res, dir_next, dir2) {
+		ident_res_del(dbr, dir);
+	}
+
+	rec_update(dbi, NULL, 0);
+
+	for (i = 0; i < dbi->dbi_numnam; i++)
+		free(dbi->dbi_names[i]);
+
+	if (dbi->dbi_numnam > 0)
+		free(dbi->dbi_names);
+
+	free(dbi->dbi_ident);
+	MTX_DESTROY(dbi, dbi_mtx);
+	MDNS_INIT_UNSET(dbi, dbi_magic);
+	free(dbi);
+
+	dprintf(DEBUG_DBR, "Removed identifier %d", dbi);
+}
+
+/*
+ * Remove a record set identifier
+ *  dbr   - Database record handle
+ *  ident - Identifier to remove
+ *
+ * Removes an identifier and all records and resources associated with it.
+ */
+int
+dbr_ident_del(struct dbr *dbr, char *ident)
+{
+	struct dbr_ident *dbi;
+	size_t ilen;
 
-	dr = hashtbl_find(&dbr->dbr_ident, ident, strlen(ident));
-	if (dr != NULL) {
-		dprintf(DEBUG_DBR, "Record set %s does already exists dr=%x",
-		    ident, dr);
-		return (dr);
+	ilen = strlen(ident);
+	RW_WLOCK(dbr, dbr_lock);
+	dbi = hashtbl_find(&dbr->dbr_ident, ident, ilen);
+	if (dbi == NULL) {
+		dprintf(DEBUG_DBR, "Record set %s does not exists", ident);
+		goto out;
 	}
-	else if (names[0] == NULL)
-		return (NULL);
+
+	ident_del(dbr, dbi);
+	RW_UNLOCK(dbr, dbr_lock);
+	return (0);
+out:
+	RW_UNLOCK(dbr, dbr_lock);
+	return (-1);
+}
+
+/*
+ * Return a list of identifiers
+ *   dbr - Record database handle
+ */
+char **
+dbr_ident_list(struct dbr *dbr)
+{
+	struct dbr_ident *dbi;
+	char **ident;
+	int i;
+
+	MDNS_INIT_ASSERT(dbr, dbr_magic);
 
+	ident = NULL;
 	i = 0;
-	error = -1;
-	dr = malloc(sizeof(struct dbr_rec));
-	TAILQ_INIT(&dr->dr_clone.head);
-	dr->dr_clones = 0;
-	dr->dr_dbr = dbr;
-	dr->dr_name = NULL;
-	dr->dr_ident = strdup(ident);
-	dr->dr_names = names;
-	dr->dr_cur = 0;
-	dr->dr_cols = 0;
-	dr->dr_col_ts = 0;
-	dr->dr_chead = dr;
-	dr->dr_flags = DR_INVALID;
-	r = &dr->dr_rec;
-	record_get(&dbr->dbr_recs, &r, RECORD_NOALLOC, ident);
-	record_setparent(r, dr);
+	RW_RLOCK(dbr, dbr_lock);
+	TAILQ_FOREACH(dbi, &dbr->dbr_ilist, dbi_next) {
+		MDNS_INIT_ASSERT(dbi, dbi_magic);
+		ident = realloc(ident, sizeof(char *) * ++i);
+		ident[i - 1] = strdup(dbi->dbi_ident);
+	}
+	RW_UNLOCK(dbr, dbr_lock);
+
+	ident = realloc(ident, sizeof(char *) * ++i);
+	ident[i - 1] = NULL;
+
+	return (ident);
+}
+
+/*
+ * Free an identifier array previously allocated with dbr_ident_()
+ */
+void
+dbr_ident_list_free(char **ident)
+{
+	int i = 0;
+
+	if (ident == NULL)
+		return;
+	while (ident[i] != NULL)
+		free(ident[i++]);
+	free(ident);
+}
+
+/*
+ * Add a record name to a record set identifier
+ *  dbr   - Database record handle
+ *  ident - Record set identifier
+ *  name  - Wide character encoded (NULL-terminated) name to add
+ */
+int
+dbr_name_add(struct dbr *dbr, char *ident, wchar_t *name)
+{
+	struct dbr_ident *dbi;
+	size_t ilen;
+	int i;
+
+	ilen = strlen(ident);
+	RW_WLOCK(dbr, dbr_lock);
+	dbi = hashtbl_find(&dbr->dbr_ident, ident, ilen);
+	if (dbi == NULL)
+		goto out;
+
+	MTX_LOCK(dbi, dbi_mtx);
+	i = dbi->dbi_numnam;
+	dbi->dbi_numnam++;
+	dbi->dbi_names = realloc(dbi->dbi_names,
+	    dbi->dbi_numnam * sizeof(wchar_t *));
+	dbi->dbi_names[i] = _wcsdup(name);
+
+	if (dbi->dbi_records == 0)
+		ident_setname(dbi, i);
+
+	MTX_UNLOCK(dbi, dbi_mtx);
+	RW_UNLOCK(dbr, dbr_lock);
+	return (0);
+out:
+	RW_UNLOCK(dbr, dbr_lock);
+	return (-1);
+}
+
+/*
+ * Remove a record name from a record set
+ *  dbr   - Database record handle
+ *  ident - Record set identifier
+ *  name  - Record name to remove
+ */
+int
+dbr_name_del(struct dbr *dbr, char *ident, wchar_t *name)
+{
+	struct dbr_ident *dbi;
+	size_t ilen;
+	int i, next;
+
+	ilen = strlen(ident);
+	RW_WLOCK(dbr, dbr_lock);
+	dbi = hashtbl_find(&dbr->dbr_ident, ident, ilen);
+	if (dbi == NULL)
+		goto out;
 
-	if (shared)
-		dr->dr_flags |= DR_SHARED;
-	TAILQ_INIT(&dr->dr_res_ptr);
-	MDNS_INIT_SET(dr, dr_magic);
+	MTX_LOCK(dbi, dbi_mtx);
 
-	do {
-		wp = names[i++];
-		if (wp == NULL)
+	for (i = 0; i < dbi->dbi_numnam; i++) {
+		if (wcscmp(name, dbi->dbi_names[i]) == 0)
 			break;
+	}
+
+	/* Not found */	
+	if (i == dbi->dbi_numnam) {
+		MTX_UNLOCK(dbi, dbi_mtx);
+		goto out;
+	}
+
+	if (i == dbi->dbi_curnam) {
+		next = (dbi->dbi_curnam + 1) % dbi->dbi_numnam;
+		if (next != i)
+			ident_setname(dbi, next);
+		else {
+			rec_update(dbi, NULL, 0);
+		}
+	}
+
+	free(dbi->dbi_names[i]);
+	dbi->dbi_numnam--;
+
+	/* Overwrite entry if it's in the middle of array */
+	if (i < dbi->dbi_numnam) {
+		memmove(dbi->dbi_names[i], dbi->dbi_names[i + 1],
+		    (dbi->dbi_numnam - i) * sizeof(wchar_t));
+	}
+
+	if (dbi->dbi_numnam > 0)
+		dbi->dbi_names = realloc(dbi->dbi_names,
+		    dbi->dbi_numnam * sizeof(wchar_t));
+	else {
+		free(dbi->dbi_names);
+		dbi->dbi_names = NULL;
+	}
+
+	MTX_UNLOCK(dbi, dbi_mtx);
+	RW_UNLOCK(dbr, dbr_lock);
+	return (0);
+out:
+	RW_UNLOCK(dbr, dbr_lock);
+	return (-1);
+}
+
+/*
+ * Return an array of names assigned to an identifier
+ *   dbr    - Record database handle
+ *   ident  - Identifier
+ *   namlen - Will be set to array length
+ */
+struct dbr_name *
+dbr_name_list(struct dbr *dbr, char *ident, size_t *namlen)
+{
+	struct dbr_ident *dbi;
+	struct dbr_name *dn, *dnp;
+	struct dbr_rec *dr;
+	size_t ilen, sz;
+	int i, j;
+
+	ilen = strlen(ident);
+	RW_WLOCK(dbr, dbr_lock);
+	dbi = hashtbl_find(&dbr->dbr_ident, ident, ilen);
+	if (dbi == NULL)
+		goto out;
+
+	MTX_LOCK(dbi, dbi_mtx);
+	sz = dbi->dbi_numnam;
+
+	for (i = 0; i < dbi->dbi_numnam; i++)
+		sz += dbi->dbi_records;
+
+	dn = malloc(sizeof(struct dbr_name) * sz);
+	if (dn == NULL)
+		goto out2;
 
-		vtd = var_expand(&dbr->dbr_vars, wp, &vtd_len);
-		if (vtd_len > 0) {
-			var_reg(&dbr->dbr_vars, wp, rec_var_update, dr);
-			rec_update(dr, vtd, vtd_len);
+	for (i = 0; i < dbi->dbi_numnam; i++) {
+		if (dbi->dbi_records == 0) {
+			if (dbi->dbi_curnam == i)
+				dn[i].dn_curnam = 1;
+			dn[i].dn_ename = NULL;
+			dn[i].dn_name = _wcsdup(dbi->dbi_names[i]);
+			continue;
 		}
-		else {
-			var_vtdfree(vtd, vtd_len);
+
+		j = 0;
+		TAILQ_FOREACH(dr, &dbi->dbi_rech, dr_next) {
+			dnp = &dn[i + j];
+			dnp->dn_name = _wcsdup(dbi->dbi_names[i]);
+			if (dbi->dbi_curnam == i)
+				dnp->dn_curnam = 1;
+			dnp->dn_ename = _wcsdup(dr->dr_name);
+			j++;
 		}
-	} while (vtd_len == 0);
+	}
+
+	*namlen = sz;
+
+	MTX_UNLOCK(dbi, dbi_mtx);
+	RW_UNLOCK(dbr, dbr_lock);
+	return (dn);
+out2:
+	MTX_UNLOCK(dbi, dbi_mtx);
+out:
+	RW_UNLOCK(dbr, dbr_lock);
+	*namlen = 0;
+	return (NULL);
+}
+
+/*
+ * Free an array of names allocated with dbr_name_list()
+ *   dn     - Array pointer
+ *   namlen - Array length
+ */
+void
+dbr_name_list_free(struct dbr_name *dn, size_t namlen)
+{
+	size_t i;
+
+	for (i = 0; i < namlen; i++) {
+		free(dn[i].dn_name);
+		if (dn[i].dn_ename != NULL)
+			free(dn[i].dn_ename);
+		i++;
+	}
+	free(dn);
+}
+
+/*
+ * Add a resource to a record identifier
+ */
+int
+dbr_res_add(struct dbr *dbr, char *ident, uint16_t class, uint16_t type,
+    uint32_t ttl, void *res, int ptr)
+{
+	struct dbr_ident *dbi, *dbip;
+	struct dbr_ident_res *dir;
+	struct dbr_rec *dr, *dr2;
+	struct dbr_res *dsh;
+	struct vt_data *vtd;
+	size_t ilen, vtd_len;
+	uint32_t i;
+	char *iptr;
+
+	ilen = strlen(ident);
+	RW_RLOCK(dbr, dbr_lock);
+	dbi = hashtbl_find(&dbr->dbr_ident, ident, ilen);
+	if (dbi == NULL)
+		goto out;
+
+	if (ptr) {
+		iptr = res;
+		dbip = hashtbl_find(&dbr->dbr_ident, iptr, strlen(iptr));
+		if (dbip == NULL)
+			goto out;
+	}
+
+	dir = malloc(sizeof(struct dbr_ident_res));
+	if (dir == NULL)
+		goto out;
+
+	bzero(dir, sizeof(struct dbr_ident_res));
+	dir->dir_class = class;
+	dir->dir_type = type;
+	dir->dir_ttl = ttl;
+	dir->dir_dbi = dbi;
+	TAILQ_INIT(&dir->dir_resh);
+	MTX_INIT(dir, dir_mtx, NULL);
+	MDNS_INIT_SET(dir, dir_magic);
 
-	/*
-	 * If all alternative names fail to expand just set it to the
-	 * first name and mark the record as invalid.
-	 */
-	if (vtd_len == 0) {
-		wp = names[0];
-		var_reg(&dbr->dbr_vars, wp, rec_var_update, dr);
-		dr->dr_cur = 0;
+	if (ptr) {
+		dir->dir_flags |= DIR_POINTER;
+		dir->dir_data.dbi = dbip;
 	}
 	else {
-		dr->dr_cur = i - 1;
+		dir->dir_data.wp = res;
+	}
+
+	MTX_LOCK(dbi, dbi_mtx);
+	TAILQ_INSERT_TAIL(&dbi->dbi_res, dir, dir_next);
+
+	if (ptr) {
+		MTX_LOCK(dbip, dbi_mtx);
+		TAILQ_FOREACH(dr, &dbi->dbi_rech, dr_next) {
+			dr2 = TAILQ_FIRST(&dbip->dbi_rech);
+			dsh = res_add(dr, dir, NULL, dr2->dr_name);
+			while ((dr2 = TAILQ_NEXT(dr2, dr_next)) != NULL) {
+				res_add(dr, dir, dsh, dr2->dr_name);
+			}
+		}
+		TAILQ_INSERT_TAIL(&dbip->dbi_res_ptr, dir, dir_ptr_next);
+		MTX_UNLOCK(dbip, dbi_mtx);
 	}
+	else {
+		vtd = var_expand(&dbr->dbr_vars, dir->dir_data.wp, &vtd_len);
+		TAILQ_FOREACH(dr, &dbi->dbi_rech, dr_next) {
+			if (vtd_len > 0)
+				dsh = res_add(dr, dir, NULL, vtd[0].vtd_str);
+			for (i = 1; i < vtd_len; i++)
+				res_add(dr, dir, dsh, vtd[i].vtd_str);
+		}
 
-	dr->dr_flags &= ~DR_OK;
-	hashtbl_add(&dbr->dbr_ident, dr->dr_ident, strlen(dr->dr_ident), dr, 0);
+		var_vtdfree(vtd, vtd_len);
+		var_reg(&dbr->dbr_vars, dir->dir_data.wp, res_var_update, dir);
+	}
 
-	if ((dr->dr_flags & DR_SHARED) && !(dr->dr_flags & DR_INVALID))
-		dr->dr_flags |= DR_OK;
+	dprintf(DEBUG_DBR, "Added resource res=%x to ident %s, ptr=%x",
+	    res, dbi->dbi_ident, ptr);
 
-	dprintf(DEBUG_DBR,
-	    "New database record ident=%s, dr=%x, name=%ls, clones=%d, "
-	    "flags=%x", dr->dr_ident, dr, dr->dr_names[dr->dr_cur],
-	    dr->dr_clones, dr->dr_flags);
-	return (dr);
+	MTX_UNLOCK(dbi, dbi_mtx);
+	RW_UNLOCK(dbr, dbr_lock);
+	return (0);
+out:
+	RW_UNLOCK(dbr, dbr_lock);
+	return (-1);
 }
 
-static void
-record_res_del_cb(struct record_res *rr, __unused void *arg)
+/*
+ * Remove a resource from an identifier
+ */
+int
+dbr_res_del(struct dbr *dbr, char *ident, uint16_t class, uint16_t type,
+    void *res, int ptr)
 {
-	struct dbr_res *ds;
+	struct dbr_ident *dbi;
+	struct dbr_ident_res *dir;
+	size_t ilen;
+	int error;
+	char *ires;
+	wchar_t *wres;
+
+	ilen = strlen(ident);
+	RW_RLOCK(dbr, dbr_lock);
+	dbi = hashtbl_find(&dbr->dbr_ident, ident, ilen);
+	if (dbi == NULL)
+		goto out;
+	MTX_LOCK(dbi, dbi_mtx);
+
+	ires = res;
+	wres = res;
+
+	TAILQ_FOREACH(dir, &dbi->dbi_res, dir_next) {
+		if (dir->dir_class != class || dir->dir_type != type)
+			continue;
+		if (ptr && !(dir->dir_flags & DIR_POINTER))
+			continue;
+
+		if (ptr) {
+			if (strcmp(dir->dir_data.dbi->dbi_ident, ires) == 0)
+				break;
+		}
+		else {
+			if (wcscmp(dir->dir_data.wp, wres) == 0)
+				break;
+		}
+	}
+
+	if (dir != NULL)
+		error = ident_res_del(dbr, dir);
+	else
+		error = -1;
 
-	ds = record_res_getparent(rr);
-	MDNS_INIT_ASSERT(ds, ds_magic);
-	if (!(ds->ds_flags & DS_CLONE))
-		dbr_res_del(ds);
+	MTX_UNLOCK(dbi, dbi_mtx);
+	RW_UNLOCK(dbr, dbr_lock);
+	return (error);
+out:
+	RW_UNLOCK(dbr, dbr_lock);
+	return (-1);
 }
 
-static void
-record_type_del_cb(struct record_type *rt, __unused void *arg)
+/*
+ * Return an array of resources assigned to an identifer
+ *   dbr    - Record database handle
+ *   ident  - Identifer
+ *   reslen - Will be set to array length
+ */
+struct dbr_resource *
+dbr_res_list(struct dbr *dbr, char *ident, size_t *reslen)
 {
-	struct dbr_type *dt;

>>> TRUNCATED FOR MAIL (1000 lines) <<<


More information about the p4-projects mailing list