|
|
dc8c34 |
From 7d4c51ed99704e6b8e8aab1b1d6a80157af48784 Mon Sep 17 00:00:00 2001
|
|
|
dc8c34 |
From: "Thierry bordaz (tbordaz)" <tbordaz@redhat.com>
|
|
|
dc8c34 |
Date: Thu, 14 Mar 2013 18:35:21 +0100
|
|
|
dc8c34 |
Subject: [PATCH 241/243] Ticket 616 - High contention on computed attribute
|
|
|
dc8c34 |
lock
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Bug Description:
|
|
|
dc8c34 |
On search request, some requested attributes are computed:
|
|
|
dc8c34 |
- subschemasubentry
|
|
|
dc8c34 |
- nscpentrywsi
|
|
|
dc8c34 |
- numsubordinates
|
|
|
dc8c34 |
- hassubordinates
|
|
|
dc8c34 |
This is done with a linked list of registered callback.
|
|
|
dc8c34 |
When sending the results, each requested attribute is evaluated against all the callbacks.
|
|
|
dc8c34 |
When going through the callbacks list the thread hold the lock on the list.
|
|
|
dc8c34 |
Currently all the server callbacks are registered at startup time with only
|
|
|
dc8c34 |
one thread registering them (main).
|
|
|
dc8c34 |
|
|
|
dc8c34 |
A custom plugin may register custom callback using slapi_compute_add_evaluator
|
|
|
dc8c34 |
|
|
|
dc8c34 |
The important point is that callback are only added to the list.
|
|
|
dc8c34 |
Also on standard deployment without custom plugin adding new computed attribute,
|
|
|
dc8c34 |
this list is built at startup.
|
|
|
dc8c34 |
|
|
|
dc8c34 |
The problem on computed attribute is that it can create contention between search threads
|
|
|
dc8c34 |
trying to evaluate/compute the requested attributes
|
|
|
dc8c34 |
|
|
|
dc8c34 |
The same description applies to computed filters. For example with 'views' or
|
|
|
dc8c34 |
filters containing "subordinates", the filter is recomputed.
|
|
|
dc8c34 |
This using a linked list of callbacks registered during startup.
|
|
|
dc8c34 |
A custom plugin may register custom callback using slapi_compute_add_search_rewriter.
|
|
|
dc8c34 |
|
|
|
dc8c34 |
In short:
|
|
|
dc8c34 |
On standard deployment computed filters and computed attributes lists are unchanged
|
|
|
dc8c34 |
after startup.
|
|
|
dc8c34 |
Computed filters/attribute are only added to the lists.
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Fix Description:
|
|
|
dc8c34 |
|
|
|
dc8c34 |
The fix consist to not protect the access to computed filter/attribute unless a
|
|
|
dc8c34 |
computed filter/attribute is added after startup.
|
|
|
dc8c34 |
|
|
|
dc8c34 |
The fix also contains a improvement of rsearch to support filters larger than 256 char
|
|
|
dc8c34 |
|
|
|
dc8c34 |
The fix also contains reworks according to review feedback.
|
|
|
dc8c34 |
Basically using a temporary variable to hold the actual value of require_*
|
|
|
dc8c34 |
|
|
|
dc8c34 |
The benefit is limited to 2% in terms of search throughput (8*4core machine)
|
|
|
dc8c34 |
|
|
|
dc8c34 |
https://fedorahosted.org/389/ticket/616
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Reviewed by: Rich Megginson (thanks Rich !)
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Platforms tested: 1*4cores fedora and 8*4cores RHEL6.4
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Flag Day: no
|
|
|
dc8c34 |
|
|
|
dc8c34 |
Doc impact: no
|
|
|
dc8c34 |
(cherry picked from commit 4b7791f3ab9370ccf30b09077656e247682bf384)
|
|
|
dc8c34 |
(cherry picked from commit ff5a8770da1266d96f5e1b36b026d539cb55ec25)
|
|
|
dc8c34 |
---
|
|
|
dc8c34 |
ldap/servers/slapd/computed.c | 149 +++++++++++++++++++++------
|
|
|
dc8c34 |
ldap/servers/slapd/main.c | 3 +-
|
|
|
dc8c34 |
ldap/servers/slapd/proto-slap.h | 1 +
|
|
|
dc8c34 |
ldap/servers/slapd/tools/rsearch/nametable.c | 4 +-
|
|
|
dc8c34 |
4 files changed, 125 insertions(+), 32 deletions(-)
|
|
|
dc8c34 |
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/computed.c b/ldap/servers/slapd/computed.c
|
|
|
dc8c34 |
index b82e2e8..7c99b45 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/computed.c
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/computed.c
|
|
|
dc8c34 |
@@ -44,6 +44,7 @@
|
|
|
dc8c34 |
/* Handles computed attributes for entries as they're returned to the client */
|
|
|
dc8c34 |
|
|
|
dc8c34 |
#include "slap.h"
|
|
|
dc8c34 |
+#include "proto-slap.h"
|
|
|
dc8c34 |
|
|
|
dc8c34 |
|
|
|
dc8c34 |
/* Structure used to pass the context needed for completing a computed attribute operation */
|
|
|
dc8c34 |
@@ -61,8 +62,11 @@ struct _compute_evaluator {
|
|
|
dc8c34 |
};
|
|
|
dc8c34 |
typedef struct _compute_evaluator compute_evaluator;
|
|
|
dc8c34 |
|
|
|
dc8c34 |
+static PRBool startup_completed = PR_FALSE;
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
static compute_evaluator *compute_evaluators = NULL;
|
|
|
dc8c34 |
static Slapi_RWLock *compute_evaluators_lock = NULL;
|
|
|
dc8c34 |
+static PRBool require_compute_evaluator_lock = PR_FALSE;
|
|
|
dc8c34 |
|
|
|
dc8c34 |
static int
|
|
|
dc8c34 |
compute_stock_evaluator(computed_attr_context *c,char* type,Slapi_Entry *e,slapi_compute_output_t outputfn);
|
|
|
dc8c34 |
@@ -75,6 +79,7 @@ typedef struct _compute_rewriter compute_rewriter;
|
|
|
dc8c34 |
|
|
|
dc8c34 |
static compute_rewriter *compute_rewriters = NULL;
|
|
|
dc8c34 |
static Slapi_RWLock *compute_rewriters_lock = NULL;
|
|
|
dc8c34 |
+static PRBool require_compute_rewriters_lock = PR_FALSE;
|
|
|
dc8c34 |
|
|
|
dc8c34 |
/* Function called by evaluators to have the value output */
|
|
|
dc8c34 |
static int
|
|
|
dc8c34 |
@@ -83,17 +88,36 @@ compute_output_callback(computed_attr_context *c,Slapi_Attr *a , Slapi_Entry *e)
|
|
|
dc8c34 |
return encode_attr (c->pb, c->ber, e, a, c->attrsonly, c->requested_type);
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
+static
|
|
|
dc8c34 |
+int compute_call_evaluators_nolock(computed_attr_context *c,slapi_compute_output_t outfn,char *type,Slapi_Entry *e)
|
|
|
dc8c34 |
+{
|
|
|
dc8c34 |
+ int rc = -1;
|
|
|
dc8c34 |
+ compute_evaluator *current = NULL;
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ for (current = compute_evaluators; (current != NULL) && (-1 == rc); current = current->next) {
|
|
|
dc8c34 |
+ rc = (*(current->function))(c,type,e,outfn);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+ return rc;
|
|
|
dc8c34 |
+}
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
static int
|
|
|
dc8c34 |
compute_call_evaluators(computed_attr_context *c,slapi_compute_output_t outfn,char *type,Slapi_Entry *e)
|
|
|
dc8c34 |
{
|
|
|
dc8c34 |
int rc = -1;
|
|
|
dc8c34 |
- compute_evaluator *current = NULL;
|
|
|
dc8c34 |
+ int need_lock = require_compute_evaluator_lock;
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
/* Walk along the list (locked) calling the evaluator functions util one says yes, an error happens, or we finish */
|
|
|
dc8c34 |
- slapi_rwlock_rdlock(compute_evaluators_lock);
|
|
|
dc8c34 |
- for (current = compute_evaluators; (current != NULL) && (-1 == rc); current = current->next) {
|
|
|
dc8c34 |
- rc = (*(current->function))(c,type,e,outfn);
|
|
|
dc8c34 |
- }
|
|
|
dc8c34 |
- slapi_rwlock_unlock(compute_evaluators_lock);
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ if (need_lock) {
|
|
|
dc8c34 |
+ slapi_rwlock_rdlock(compute_evaluators_lock);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ rc = compute_call_evaluators_nolock(c, outfn, type, e);
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ if (need_lock) {
|
|
|
dc8c34 |
+ slapi_rwlock_unlock(compute_evaluators_lock);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
return rc;
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
@@ -132,25 +156,54 @@ compute_stock_evaluator(computed_attr_context *c,char* type,Slapi_Entry *e,slapi
|
|
|
dc8c34 |
return rc; /* I see no ships */
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
+static void
|
|
|
dc8c34 |
+compute_add_evaluator_nolock(slapi_compute_callback_t function, compute_evaluator *new_eval)
|
|
|
dc8c34 |
+{
|
|
|
dc8c34 |
+ new_eval->next = compute_evaluators;
|
|
|
dc8c34 |
+ new_eval->function = function;
|
|
|
dc8c34 |
+ compute_evaluators = new_eval;
|
|
|
dc8c34 |
+}
|
|
|
dc8c34 |
int slapi_compute_add_evaluator(slapi_compute_callback_t function)
|
|
|
dc8c34 |
{
|
|
|
dc8c34 |
int rc = 0;
|
|
|
dc8c34 |
compute_evaluator *new_eval = NULL;
|
|
|
dc8c34 |
PR_ASSERT(NULL != function);
|
|
|
dc8c34 |
PR_ASSERT(NULL != compute_evaluators_lock);
|
|
|
dc8c34 |
- slapi_rwlock_wrlock(compute_evaluators_lock);
|
|
|
dc8c34 |
+ if (startup_completed) {
|
|
|
dc8c34 |
+ /* We are now in multi-threaded and we still add
|
|
|
dc8c34 |
+ * a attribute evaluator.
|
|
|
dc8c34 |
+ * switch to use locking mechanimsm
|
|
|
dc8c34 |
+ */
|
|
|
dc8c34 |
+ require_compute_evaluator_lock = PR_TRUE;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
new_eval = (compute_evaluator *)slapi_ch_calloc(1,sizeof (compute_evaluator));
|
|
|
dc8c34 |
if (NULL == new_eval) {
|
|
|
dc8c34 |
rc = ENOMEM;
|
|
|
dc8c34 |
} else {
|
|
|
dc8c34 |
- new_eval->next = compute_evaluators;
|
|
|
dc8c34 |
- new_eval->function = function;
|
|
|
dc8c34 |
- compute_evaluators = new_eval;
|
|
|
dc8c34 |
+ int need_lock = require_compute_evaluator_lock;
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ if (need_lock) {
|
|
|
dc8c34 |
+ slapi_rwlock_wrlock(compute_evaluators_lock);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ compute_add_evaluator_nolock(function, new_eval);
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ if (need_lock) {
|
|
|
dc8c34 |
+ slapi_rwlock_unlock(compute_evaluators_lock);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
- slapi_rwlock_unlock(compute_evaluators_lock);
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
return rc;
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
+/* Called when */
|
|
|
dc8c34 |
+void
|
|
|
dc8c34 |
+compute_plugins_started()
|
|
|
dc8c34 |
+{
|
|
|
dc8c34 |
+ startup_completed = PR_TRUE;
|
|
|
dc8c34 |
+}
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
/* Call this on server startup, before the first LDAP operation is serviced */
|
|
|
dc8c34 |
int compute_init()
|
|
|
dc8c34 |
{
|
|
|
dc8c34 |
@@ -200,6 +253,14 @@ int compute_terminate()
|
|
|
dc8c34 |
return 0;
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
+static void
|
|
|
dc8c34 |
+compute_add_search_rewrite_nolock(slapi_search_rewrite_callback_t function, compute_rewriter *new_rewriter)
|
|
|
dc8c34 |
+{
|
|
|
dc8c34 |
+ new_rewriter->next = compute_rewriters;
|
|
|
dc8c34 |
+ new_rewriter->function = function;
|
|
|
dc8c34 |
+ compute_rewriters = new_rewriter;
|
|
|
dc8c34 |
+}
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
/* Functions dealing with re-writing of search filters */
|
|
|
dc8c34 |
|
|
|
dc8c34 |
int slapi_compute_add_search_rewriter(slapi_search_rewrite_callback_t function)
|
|
|
dc8c34 |
@@ -208,36 +269,66 @@ int slapi_compute_add_search_rewriter(slapi_search_rewrite_callback_t function)
|
|
|
dc8c34 |
compute_rewriter *new_rewriter = NULL;
|
|
|
dc8c34 |
PR_ASSERT(NULL != function);
|
|
|
dc8c34 |
PR_ASSERT(NULL != compute_rewriters_lock);
|
|
|
dc8c34 |
+ if (startup_completed) {
|
|
|
dc8c34 |
+ /* We are now in multi-threaded and we still add
|
|
|
dc8c34 |
+ * a filter rewriter.
|
|
|
dc8c34 |
+ * switch to use locking mechanimsm
|
|
|
dc8c34 |
+ */
|
|
|
dc8c34 |
+ require_compute_rewriters_lock = PR_TRUE;
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
new_rewriter = (compute_rewriter *)slapi_ch_calloc(1,sizeof (compute_rewriter));
|
|
|
dc8c34 |
if (NULL == new_rewriter) {
|
|
|
dc8c34 |
rc = ENOMEM;
|
|
|
dc8c34 |
} else {
|
|
|
dc8c34 |
- slapi_rwlock_wrlock(compute_rewriters_lock);
|
|
|
dc8c34 |
- new_rewriter->next = compute_rewriters;
|
|
|
dc8c34 |
- new_rewriter->function = function;
|
|
|
dc8c34 |
- compute_rewriters = new_rewriter;
|
|
|
dc8c34 |
- slapi_rwlock_unlock(compute_rewriters_lock);
|
|
|
dc8c34 |
+ int need_lock = require_compute_rewriters_lock;
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ if (need_lock) {
|
|
|
dc8c34 |
+ slapi_rwlock_wrlock(compute_rewriters_lock);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ compute_add_search_rewrite_nolock(function, new_rewriter);
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ if (need_lock) {
|
|
|
dc8c34 |
+ slapi_rwlock_unlock(compute_rewriters_lock);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
return rc;
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
|
|
|
dc8c34 |
-int compute_rewrite_search_filter(Slapi_PBlock *pb)
|
|
|
dc8c34 |
+static
|
|
|
dc8c34 |
+int compute_rewrite_search_filter_nolock(Slapi_PBlock *pb)
|
|
|
dc8c34 |
+{
|
|
|
dc8c34 |
+ int rc = -1;
|
|
|
dc8c34 |
+ compute_rewriter *current = NULL;
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ for (current = compute_rewriters; (current != NULL) && (-1 == rc); current = current->next) {
|
|
|
dc8c34 |
+ rc = (*(current->function))(pb);
|
|
|
dc8c34 |
+ /* Meaning of the return code :
|
|
|
dc8c34 |
+ -1 : keep looking
|
|
|
dc8c34 |
+ 0 : rewrote OK
|
|
|
dc8c34 |
+ 1 : refuse to do this search
|
|
|
dc8c34 |
+ 2 : operations error
|
|
|
dc8c34 |
+ */
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+ return(rc);
|
|
|
dc8c34 |
+}
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+int compute_rewrite_search_filter(Slapi_PBlock *pb)
|
|
|
dc8c34 |
{
|
|
|
dc8c34 |
/* Iterate through the listed rewriters until one says it matched */
|
|
|
dc8c34 |
int rc = -1;
|
|
|
dc8c34 |
- compute_rewriter *current = NULL;
|
|
|
dc8c34 |
+ int need_lock = require_compute_rewriters_lock;
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
/* Walk along the list (locked) calling the evaluator functions util one says yes, an error happens, or we finish */
|
|
|
dc8c34 |
- slapi_rwlock_rdlock(compute_rewriters_lock);
|
|
|
dc8c34 |
- for (current = compute_rewriters; (current != NULL) && (-1 == rc); current = current->next) {
|
|
|
dc8c34 |
- rc = (*(current->function))(pb);
|
|
|
dc8c34 |
- /* Meaning of the return code :
|
|
|
dc8c34 |
- -1 : keep looking
|
|
|
dc8c34 |
- 0 : rewrote OK
|
|
|
dc8c34 |
- 1 : refuse to do this search
|
|
|
dc8c34 |
- 2 : operations error
|
|
|
dc8c34 |
- */
|
|
|
dc8c34 |
- }
|
|
|
dc8c34 |
- slapi_rwlock_unlock(compute_rewriters_lock);
|
|
|
dc8c34 |
+ if (need_lock) {
|
|
|
dc8c34 |
+ slapi_rwlock_rdlock(compute_rewriters_lock);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ rc = compute_rewrite_search_filter_nolock(pb);
|
|
|
dc8c34 |
+
|
|
|
dc8c34 |
+ if (need_lock) {
|
|
|
dc8c34 |
+ slapi_rwlock_unlock(compute_rewriters_lock);
|
|
|
dc8c34 |
+ }
|
|
|
dc8c34 |
return rc;
|
|
|
dc8c34 |
|
|
|
dc8c34 |
}
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/main.c b/ldap/servers/slapd/main.c
|
|
|
dc8c34 |
index 737da5d..bc07cbb 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/main.c
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/main.c
|
|
|
dc8c34 |
@@ -1171,7 +1171,8 @@ main( int argc, char **argv)
|
|
|
dc8c34 |
slapi_td_dn_init();
|
|
|
dc8c34 |
|
|
|
dc8c34 |
plugin_print_lists();
|
|
|
dc8c34 |
- plugin_startall(argc, argv, 1 /* Start Backends */, 1 /* Start Globals */);
|
|
|
dc8c34 |
+ plugin_startall(argc, argv, 1 /* Start Backends */, 1 /* Start Globals */);
|
|
|
dc8c34 |
+ compute_plugins_started();
|
|
|
dc8c34 |
if (housekeeping_start((time_t)0, NULL) == NULL) {
|
|
|
dc8c34 |
return_value = 1;
|
|
|
dc8c34 |
goto cleanup;
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/proto-slap.h b/ldap/servers/slapd/proto-slap.h
|
|
|
dc8c34 |
index 1fb782b..76489ab 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/proto-slap.h
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/proto-slap.h
|
|
|
dc8c34 |
@@ -248,6 +248,7 @@ void do_compare( Slapi_PBlock *pb );
|
|
|
dc8c34 |
int compute_attribute(char *type, Slapi_PBlock *pb,BerElement *ber,Slapi_Entry *e,int attrsonly,char *requested_type);
|
|
|
dc8c34 |
int compute_init();
|
|
|
dc8c34 |
int compute_terminate();
|
|
|
dc8c34 |
+void compute_plugins_started();
|
|
|
dc8c34 |
|
|
|
dc8c34 |
|
|
|
dc8c34 |
/*
|
|
|
dc8c34 |
diff --git a/ldap/servers/slapd/tools/rsearch/nametable.c b/ldap/servers/slapd/tools/rsearch/nametable.c
|
|
|
dc8c34 |
index 0a4b6fc..e5d04cd 100644
|
|
|
dc8c34 |
--- a/ldap/servers/slapd/tools/rsearch/nametable.c
|
|
|
dc8c34 |
+++ b/ldap/servers/slapd/tools/rsearch/nametable.c
|
|
|
dc8c34 |
@@ -152,8 +152,8 @@ int nt_load(NameTable *nt, const char *filename)
|
|
|
dc8c34 |
if (!fd) return 0;
|
|
|
dc8c34 |
|
|
|
dc8c34 |
while (PR_Available(fd) > 0) {
|
|
|
dc8c34 |
- char temp[256], *s;
|
|
|
dc8c34 |
- if (PR_GetLine(fd, temp, 256)) break;
|
|
|
dc8c34 |
+ char temp[4096], *s;
|
|
|
dc8c34 |
+ if (PR_GetLine(fd, temp, sizeof(temp))) break;
|
|
|
dc8c34 |
s = strdup(temp);
|
|
|
dc8c34 |
if (!s) break;
|
|
|
dc8c34 |
if (!nt_push(nt, s)) break;
|
|
|
dc8c34 |
--
|
|
|
dc8c34 |
1.8.1.4
|
|
|
dc8c34 |
|