[SCM] Samba Shared Repository - branch master updated - release-4-0-0alpha7-12-g170830c

Michael Adam obnox at samba.org
Thu Feb 26 10:07:26 GMT 2009


The branch, master has been updated
       via  170830c0089088e7e30a3aa2d0c6d65b01ab83a0 (commit)
       via  5c91cdcc47dc22330839113b37d250b472fb0487 (commit)
       via  1b1aac412c1cff1ac969ae07a0fe085b80476c9e (commit)
       via  aeb26fe9118ac8b479b2052a722b21e6404c0f00 (commit)
       via  9475e88beadd19c245ca4010c398652a85ccfd78 (commit)
       via  16f61a6f90060d40f0348cb433e3b900ae05fcba (commit)
       via  26f238466caa1d40edf74d4678c2e981ec9018bd (commit)
      from  8e4816f0078fd94a1b83798f52a63dc679eed47e (commit)

http://gitweb.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit 170830c0089088e7e30a3aa2d0c6d65b01ab83a0
Author: Volker Lendecke <vl at samba.org>
Date:   Sun Feb 22 10:11:29 2009 +0100

    Wrap creating the sorted subkey cache in a transaction
    
    Signed-off-by: Michael Adam <obnox at samba.org>

commit 5c91cdcc47dc22330839113b37d250b472fb0487
Author: Volker Lendecke <vl at samba.org>
Date:   Sun Feb 22 01:11:51 2009 +0100

    Add a comment describing the sorted subkeys
    
    Signed-off-by: Michael Adam <obnox at samba.org>

commit 1b1aac412c1cff1ac969ae07a0fe085b80476c9e
Author: Volker Lendecke <vl at samba.org>
Date:   Fri Feb 20 06:01:16 2009 +0100

    Add sorted subkey cache
    
    On my box this gets net conf list for 1000 records down to .1 seconds
    
    Signed-off-by: Michael Adam <obnox at samba.org>

commit aeb26fe9118ac8b479b2052a722b21e6404c0f00
Author: Volker Lendecke <vl at samba.org>
Date:   Sun Feb 22 00:47:54 2009 +0100

    Add db_tdb_parse
    
    Signed-off-by: Michael Adam <obnox at samba.org>

commit 9475e88beadd19c245ca4010c398652a85ccfd78
Author: Volker Lendecke <vl at samba.org>
Date:   Sun Feb 22 00:18:05 2009 +0100

    Add dbwrap->parse_record
    
    Signed-off-by: Michael Adam <obnox at samba.org>

commit 16f61a6f90060d40f0348cb433e3b900ae05fcba
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Feb 21 18:00:42 2009 +0100

    Speed up "net conf list"
    
    For 1000 shares this speeds up net conf list from .6 to .25 seconds on my box
    
    Signed-off-by: Michael Adam <obnox at samba.org>

commit 26f238466caa1d40edf74d4678c2e981ec9018bd
Author: Volker Lendecke <vl at samba.org>
Date:   Sat Feb 21 17:01:58 2009 +0100

    Speed up "net conf list"
    
    With 1000 shares in the registry, this changed the time of "net conf list" from
    1.1 seconds to .6 seconds.
    
    Signed-off-by: Michael Adam <obnox at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 lib/smbconf/smbconf.c             |    4 -
 source3/include/dbwrap.h          |    4 +
 source3/include/reg_db.h          |    1 +
 source3/lib/dbwrap.c              |   26 ++++
 source3/lib/dbwrap_tdb.c          |   12 ++
 source3/lib/smbconf/smbconf_reg.c |  159 +++++++-----------------
 source3/registry/reg_backend_db.c |  244 ++++++++++++++++++++++++++++++++++---
 7 files changed, 312 insertions(+), 138 deletions(-)


Changeset truncated at 500 lines:

diff --git a/lib/smbconf/smbconf.c b/lib/smbconf/smbconf.c
index bcab0b9..595fd23 100644
--- a/lib/smbconf/smbconf.c
+++ b/lib/smbconf/smbconf.c
@@ -203,10 +203,6 @@ WERROR smbconf_get_share(struct smbconf_ctx *ctx,
 			 const char *servicename,
 			 struct smbconf_service **service)
 {
-	if (!smbconf_share_exists(ctx, servicename)) {
-		return WERR_NO_SUCH_SERVICE;
-	}
-
 	return ctx->ops->get_share(ctx, mem_ctx, servicename, service);
 }
 
diff --git a/source3/include/dbwrap.h b/source3/include/dbwrap.h
index aad4ccd..16f10cc 100644
--- a/source3/include/dbwrap.h
+++ b/source3/include/dbwrap.h
@@ -46,6 +46,10 @@ struct db_context {
 	int (*transaction_start)(struct db_context *db);
 	int (*transaction_commit)(struct db_context *db);
 	int (*transaction_cancel)(struct db_context *db);
+	int (*parse_record)(struct db_context *db, TDB_DATA key,
+			    int (*parser)(TDB_DATA key, TDB_DATA data,
+					  void *private_data),
+			    void *private_data);
 	void *private_data;
 	bool persistent;
 };
diff --git a/source3/include/reg_db.h b/source3/include/reg_db.h
index 92448ae..5cafa0a 100644
--- a/source3/include/reg_db.h
+++ b/source3/include/reg_db.h
@@ -26,5 +26,6 @@
 
 #define REG_VALUE_PREFIX    "SAMBA_REGVAL"
 #define REG_SECDESC_PREFIX  "SAMBA_SECDESC"
+#define REG_SORTED_SUBKEYS_PREFIX  "SAMBA_SORTED_SUBKEYS"
 
 #endif /* _REG_DB_H */
diff --git a/source3/lib/dbwrap.c b/source3/lib/dbwrap.c
index a57b7c9..5e7ce60 100644
--- a/source3/lib/dbwrap.c
+++ b/source3/lib/dbwrap.c
@@ -42,6 +42,29 @@ static int dbwrap_fallback_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
 	return 0;
 }
 
+/*
+ * Fall back using fetch if no genuine parse operation is provided
+ */
+
+static int dbwrap_fallback_parse_record(struct db_context *db, TDB_DATA key,
+					int (*parser)(TDB_DATA key,
+						      TDB_DATA data,
+						      void *private_data),
+					void *private_data)
+{
+	TDB_DATA data;
+	int res;
+
+	res = db->fetch(db, talloc_tos(), key, &data);
+	if (res != 0) {
+		return res;
+	}
+
+	res = parser(key, data, private_data);
+	TALLOC_FREE(data.dptr);
+	return res;
+}
+
 /**
  * open a database
  */
@@ -101,6 +124,9 @@ struct db_context *db_open(TALLOC_CTX *mem_ctx,
 	if ((result != NULL) && (result->fetch == NULL)) {
 		result->fetch = dbwrap_fallback_fetch;
 	}
+	if ((result != NULL) && (result->parse_record == NULL)) {
+		result->parse_record = dbwrap_fallback_parse_record;
+	}
 
 	return result;
 }
diff --git a/source3/lib/dbwrap_tdb.c b/source3/lib/dbwrap_tdb.c
index b5eb188..c71e073 100644
--- a/source3/lib/dbwrap_tdb.c
+++ b/source3/lib/dbwrap_tdb.c
@@ -176,6 +176,17 @@ static int db_tdb_fetch(struct db_context *db, TALLOC_CTX *mem_ctx,
 	return 0;
 }
 
+static int db_tdb_parse(struct db_context *db, TDB_DATA key,
+			int (*parser)(TDB_DATA key, TDB_DATA data,
+				      void *private_data),
+			void *private_data)
+{
+	struct db_tdb_ctx *ctx = talloc_get_type_abort(
+		db->private_data, struct db_tdb_ctx);
+
+	return tdb_parse_record(ctx->wtdb->tdb, key, parser, private_data);
+}
+
 static NTSTATUS db_tdb_store(struct db_record *rec, TDB_DATA data, int flag)
 {
 	struct db_tdb_ctx *ctx = talloc_get_type_abort(rec->private_data,
@@ -351,6 +362,7 @@ struct db_context *db_open_tdb(TALLOC_CTX *mem_ctx,
 	result->fetch = db_tdb_fetch;
 	result->traverse = db_tdb_traverse;
 	result->traverse_read = db_tdb_traverse_read;
+	result->parse_record = db_tdb_parse;
 	result->get_seqnum = db_tdb_get_seqnum;
 	result->get_flags = db_tdb_get_flags;
 	result->persistent = ((tdb_flags & TDB_CLEAR_IF_FIRST) == 0);
diff --git a/source3/lib/smbconf/smbconf_reg.c b/source3/lib/smbconf/smbconf_reg.c
index e36fa8a..b1e34e5 100644
--- a/source3/lib/smbconf/smbconf_reg.c
+++ b/source3/lib/smbconf/smbconf_reg.c
@@ -23,7 +23,7 @@
 #define INCLUDES_VALNAME "includes"
 
 struct reg_private_data {
-	NT_USER_TOKEN *token;
+	struct registry_key *base_key;
 	bool open;		/* did _we_ open the registry? */
 };
 
@@ -72,54 +72,6 @@ static bool smbconf_reg_valname_valid(const char *valname)
 }
 
 /**
- * Open a registry key specified by "path"
- */
-static WERROR smbconf_reg_open_path(TALLOC_CTX *mem_ctx,
-				    struct smbconf_ctx *ctx,
-				    const char *path,
-				    uint32 desired_access,
-				    struct registry_key **key)
-{
-	WERROR werr = WERR_OK;
-
-	if (ctx == NULL) {
-		DEBUG(1, ("Error: configuration is not open!\n"));
-		werr = WERR_INVALID_PARAM;
-		goto done;
-	}
-
-	if (rpd(ctx)->token == NULL) {
-		DEBUG(1, ("Error: token missing from smbconf_ctx. "
-			  "was smbconf_init() called?\n"));
-		werr = WERR_INVALID_PARAM;
-		goto done;
-	}
-
-	werr = ctx->ops->open_conf(ctx);
-	if (!W_ERROR_IS_OK(werr)) {
-		DEBUG(1, ("Error opening the registry.\n"));
-		goto done;
-	}
-
-	if (path == NULL) {
-		DEBUG(1, ("Error: NULL path string given\n"));
-		werr = WERR_INVALID_PARAM;
-		goto done;
-	}
-
-	werr = reg_open_path(mem_ctx, path, desired_access, rpd(ctx)->token,
-			     key);
-
-	if (!W_ERROR_IS_OK(werr)) {
-		DEBUG(5, ("Error opening registry path '%s': %s\n",
-			  path, win_errstr(werr)));
-	}
-
-done:
-	return werr;
-}
-
-/**
  * Open a subkey of the base key (i.e a service)
  */
 static WERROR smbconf_reg_open_service_key(TALLOC_CTX *mem_ctx,
@@ -128,37 +80,12 @@ static WERROR smbconf_reg_open_service_key(TALLOC_CTX *mem_ctx,
 					   uint32 desired_access,
 					   struct registry_key **key)
 {
-	WERROR werr = WERR_OK;
-	char *path = NULL;
-
 	if (servicename == NULL) {
-		path = talloc_strdup(mem_ctx, ctx->path);
-	} else {
-		path = talloc_asprintf(mem_ctx, "%s\\%s", ctx->path,
-				       servicename);
-	}
-	if (path == NULL) {
-		werr = WERR_NOMEM;
-		goto done;
+		*key = rpd(ctx)->base_key;
+		return WERR_OK;
 	}
-
-	werr = smbconf_reg_open_path(mem_ctx, ctx, path, desired_access, key);
-
-done:
-	talloc_free(path);
-	return werr;
-}
-
-/**
- * open the base key
- */
-static WERROR smbconf_reg_open_base_key(TALLOC_CTX *mem_ctx,
-					struct smbconf_ctx *ctx,
-					uint32 desired_access,
-					struct registry_key **key)
-{
-	return smbconf_reg_open_path(mem_ctx, ctx, ctx->path, desired_access,
-				     key);
+	return reg_openkey(mem_ctx, rpd(ctx)->base_key, servicename,
+			   desired_access, key);
 }
 
 /**
@@ -189,7 +116,6 @@ static WERROR smbconf_reg_create_service_key(TALLOC_CTX *mem_ctx,
 					     struct registry_key **newkey)
 {
 	WERROR werr = WERR_OK;
-	struct registry_key *create_parent = NULL;
 	TALLOC_CTX *create_ctx;
 	enum winreg_CreateAction action = REG_ACTION_NONE;
 
@@ -198,13 +124,7 @@ static WERROR smbconf_reg_create_service_key(TALLOC_CTX *mem_ctx,
 	 * and will be destroyed when leaving this function... */
 	create_ctx = talloc_stackframe();
 
-	werr = smbconf_reg_open_base_key(create_ctx, ctx, REG_KEY_WRITE,
-					 &create_parent);
-	if (!W_ERROR_IS_OK(werr)) {
-		goto done;
-	}
-
-	werr = reg_createkey(mem_ctx, create_parent, subkeyname,
+	werr = reg_createkey(mem_ctx, rpd(ctx)->base_key, subkeyname,
 			     REG_KEY_WRITE, newkey, &action);
 	if (W_ERROR_IS_OK(werr) && (action != REG_CREATED_NEW_KEY)) {
 		DEBUG(10, ("Key '%s' already exists.\n", subkeyname));
@@ -215,7 +135,6 @@ static WERROR smbconf_reg_create_service_key(TALLOC_CTX *mem_ctx,
 			 subkeyname, win_errstr(werr)));
 	}
 
-done:
 	talloc_free(create_ctx);
 	return werr;
 }
@@ -608,6 +527,7 @@ done:
 static WERROR smbconf_reg_init(struct smbconf_ctx *ctx, const char *path)
 {
 	WERROR werr = WERR_OK;
+	struct nt_user_token *token;
 
 	if (path == NULL) {
 		path = KEY_SMBCONF;
@@ -620,8 +540,7 @@ static WERROR smbconf_reg_init(struct smbconf_ctx *ctx, const char *path)
 
 	ctx->data = TALLOC_ZERO_P(ctx, struct reg_private_data);
 
-	werr = ntstatus_to_werror(registry_create_admin_token(ctx,
-							&(rpd(ctx)->token)));
+	werr = ntstatus_to_werror(registry_create_admin_token(ctx, &token));
 	if (!W_ERROR_IS_OK(werr)) {
 		DEBUG(1, ("Error creating admin token\n"));
 		goto done;
@@ -633,6 +552,19 @@ static WERROR smbconf_reg_init(struct smbconf_ctx *ctx, const char *path)
 		goto done;
 	}
 
+	werr = ctx->ops->open_conf(ctx);
+	if (!W_ERROR_IS_OK(werr)) {
+		DEBUG(1, ("Error opening the registry.\n"));
+		goto done;
+	}
+
+	werr = reg_open_path(ctx, ctx->path,
+			     SEC_RIGHTS_ENUM_SUBKEYS | REG_KEY_WRITE,
+			     token, &rpd(ctx)->base_key);
+	if (!W_ERROR_IS_OK(werr)) {
+		goto done;
+	}
+
 done:
 	return werr;
 }
@@ -723,6 +655,13 @@ static WERROR smbconf_reg_drop(struct smbconf_ctx *ctx)
 	struct registry_key *new_key = NULL;
 	TALLOC_CTX* mem_ctx = talloc_stackframe();
 	enum winreg_CreateAction action;
+	struct nt_user_token *token;
+
+	werr = ntstatus_to_werror(registry_create_admin_token(ctx, &token));
+	if (!W_ERROR_IS_OK(werr)) {
+		DEBUG(1, ("Error creating admin token\n"));
+		goto done;
+	}
 
 	path = talloc_strdup(mem_ctx, ctx->path);
 	if (path == NULL) {
@@ -731,8 +670,8 @@ static WERROR smbconf_reg_drop(struct smbconf_ctx *ctx)
 	}
 	p = strrchr(path, '\\');
 	*p = '\0';
-	werr = smbconf_reg_open_path(mem_ctx, ctx, path, REG_KEY_WRITE,
-				     &parent_key);
+	werr = reg_open_path(mem_ctx, path, REG_KEY_WRITE, token,
+			     &parent_key);
 
 	if (!W_ERROR_IS_OK(werr)) {
 		goto done;
@@ -765,7 +704,6 @@ static WERROR smbconf_reg_get_share_names(struct smbconf_ctx *ctx,
 	uint32_t added_count = 0;
 	TALLOC_CTX *tmp_ctx = NULL;
 	WERROR werr = WERR_OK;
-	struct registry_key *key = NULL;
 	char *subkey_name = NULL;
 	char **tmp_share_names = NULL;
 
@@ -777,13 +715,8 @@ static WERROR smbconf_reg_get_share_names(struct smbconf_ctx *ctx,
 	tmp_ctx = talloc_stackframe();
 
 	/* if there are values in the base key, return NULL as share name */
-	werr = smbconf_reg_open_base_key(tmp_ctx, ctx,
-					 SEC_RIGHTS_ENUM_SUBKEYS, &key);
-	if (!W_ERROR_IS_OK(werr)) {
-		goto done;
-	}
 
-	if (smbconf_reg_key_has_values(key)) {
+	if (smbconf_reg_key_has_values(rpd(ctx)->base_key)) {
 		werr = smbconf_add_string_to_array(tmp_ctx, &tmp_share_names,
 						   0, NULL);
 		if (!W_ERROR_IS_OK(werr)) {
@@ -803,7 +736,8 @@ static WERROR smbconf_reg_get_share_names(struct smbconf_ctx *ctx,
 	}
 
 	for (count = 0;
-	     werr = reg_enumkey(tmp_ctx, key, count, &subkey_name, NULL),
+	     werr = reg_enumkey(tmp_ctx, rpd(ctx)->base_key, count,
+				&subkey_name, NULL),
 	     W_ERROR_IS_OK(werr);
 	     count++)
 	{
@@ -865,18 +799,16 @@ static WERROR smbconf_reg_create_share(struct smbconf_ctx *ctx,
 				       const char *servicename)
 {
 	WERROR werr;
-	TALLOC_CTX *mem_ctx = talloc_stackframe();
 	struct registry_key *key = NULL;
 
 	if (servicename == NULL) {
-		werr = smbconf_reg_open_base_key(mem_ctx, ctx, REG_KEY_WRITE,
-						 &key);
-	} else {
-		werr = smbconf_reg_create_service_key(mem_ctx, ctx,
-						      servicename, &key);
+		return WERR_OK;
 	}
 
-	talloc_free(mem_ctx);
+	werr = smbconf_reg_create_service_key(talloc_tos(), ctx,
+					      servicename, &key);
+
+	talloc_free(key);
 	return werr;
 }
 
@@ -896,6 +828,9 @@ static WERROR smbconf_reg_get_share(struct smbconf_ctx *ctx,
 	werr = smbconf_reg_open_service_key(tmp_ctx, ctx, servicename,
 					    REG_KEY_READ, &key);
 	if (!W_ERROR_IS_OK(werr)) {
+		if (W_ERROR_EQUAL(werr, WERR_BADFILE)) {
+			werr = WERR_NO_SUCH_SERVICE;
+		}
 		goto done;
 	}
 
@@ -934,21 +869,15 @@ static WERROR smbconf_reg_delete_share(struct smbconf_ctx *ctx,
 				       const char *servicename)
 {
 	WERROR werr = WERR_OK;
-	struct registry_key *key = NULL;
 	TALLOC_CTX *mem_ctx = talloc_stackframe();
 
-	werr = smbconf_reg_open_base_key(mem_ctx, ctx, REG_KEY_WRITE, &key);
-	if (!W_ERROR_IS_OK(werr)) {
-		goto done;
-	}
-
 	if (servicename != NULL) {
-		werr = reg_deletekey_recursive(key, key, servicename);
+		werr = reg_deletekey_recursive(mem_ctx, rpd(ctx)->base_key,
+					       servicename);
 	} else {
-		werr = smbconf_reg_delete_values(key);
+		werr = smbconf_reg_delete_values(rpd(ctx)->base_key);
 	}
 
-done:
 	talloc_free(mem_ctx);
 	return werr;
 }
diff --git a/source3/registry/reg_backend_db.c b/source3/registry/reg_backend_db.c
index 8ef83a1..689bd10 100644
--- a/source3/registry/reg_backend_db.c
+++ b/source3/registry/reg_backend_db.c
@@ -578,6 +578,16 @@ static bool regdb_store_keys_internal(const char *key, REGSUBKEY_CTR *ctr)
 		goto done;
 	}
 
+	/*
+	 * Delete a sorted subkey cache for regdb_key_exists, will be
+	 * recreated automatically
+	 */
+	keyname = talloc_asprintf(ctx, "%s/%s", REG_SORTED_SUBKEYS_PREFIX,
+				  keyname);
+	if (keyname != NULL) {
+		dbwrap_delete_bystring(regdb, keyname);
+	}
+
 done:
 	TALLOC_FREE(ctx);
 	SAFE_FREE(buffer);
@@ -871,6 +881,220 @@ done:
 	return ret;
 }
 
+/*
+ * regdb_key_exists() is a very frequent operation. It can be quite
+ * time-consuming to fully fetch the parent's subkey list, talloc_strdup all
+ * subkeys and then compare the keyname linearly to all the parent's subkeys.
+ *
+ * The following code tries to make this operation as efficient as possible:
+ * Per registry key we create a list of subkeys that is very efficient to
+ * search for existence of a subkey. Its format is:
+ *
+ * 4 bytes num_subkeys
+ * 4*num_subkey bytes offset into the string array
+ * then follows a sorted list of subkeys in uppercase
+ *
+ * This record is created by create_sorted_subkeys() on demand if it does not
+ * exist. scan_parent_subkeys() uses regdb->parse_record to search the sorted
+ * list, the parsing code and the binary search can be found in
+ * parent_subkey_scanner. The code uses parse_record() to avoid a memcpy of
+ * the potentially large subkey record.
+ *
+ * The sorted subkey record is deleted in regdb_store_keys_internal and
+ * recreated on demand.
+ */
+
+static int cmp_keynames(const void *p1, const void *p2)
+{
+	return StrCaseCmp(*((char **)p1), *((char **)p2));
+}
+
+static bool create_sorted_subkeys(const char *key, const char *sorted_keyname)
+{
+	char **sorted_subkeys;
+	REGSUBKEY_CTR *ctr;
+	bool result = false;
+	NTSTATUS status;
+	char *buf;
+	char *p;
+	int i, res;
+	size_t len;
+
+	if (regdb->transaction_start(regdb) != 0) {
+		DEBUG(0, ("create_sorted_subkeys: transaction_start "
+			  "failed\n"));
+		return false;
+	}
+
+	ctr = talloc(talloc_tos(), REGSUBKEY_CTR);
+	if (ctr == NULL) {
+		goto fail;
+	}
+
+	res = regdb_fetch_keys(key, ctr);
+	if (res == -1) {
+		goto fail;
+	}
+
+	sorted_subkeys = talloc_array(ctr, char *, ctr->num_subkeys);
+	if (sorted_subkeys == NULL) {
+		goto fail;
+	}
+
+	len = 4 + 4*ctr->num_subkeys;
+
+	for (i = 0; i<ctr->num_subkeys; i++) {
+		sorted_subkeys[i] = talloc_strdup_upper(sorted_subkeys,


-- 
Samba Shared Repository


More information about the samba-cvs mailing list