]> git.ipfire.org Git - thirdparty/openldap.git/commitdiff
ITS#10308 Implement cn=monitor for back-asyncmeta
authorNadezhda Ivanova <nivanova@symas.com>
Tue, 24 Jun 2025 15:35:34 +0000 (18:35 +0300)
committerQuanah Gibson-Mount <quanah@openldap.org>
Thu, 31 Jul 2025 19:01:56 +0000 (19:01 +0000)
Provide some target connection statistics such as target connections
status and target status

servers/slapd/back-asyncmeta/Makefile.in
servers/slapd/back-asyncmeta/back-asyncmeta.h
servers/slapd/back-asyncmeta/init.c
servers/slapd/back-asyncmeta/monitor.c [new file with mode: 0644]

index b0cd90e94a0b946ac82666a2aa81a17d90b51ca7..a5a7ceea9731ea7a3f243d914634b6c7af4ed414 100644 (file)
 
 SRCS   = init.c config.c search.c message_queue.c bind.c add.c compare.c \
                delete.c modify.c modrdn.c map.c \
-               conn.c candidates.c dncache.c meta_result.c
+               conn.c candidates.c dncache.c meta_result.c monitor.c
 OBJS   = init.lo config.lo search.lo message_queue.lo bind.lo add.lo compare.lo \
                delete.lo modify.lo modrdn.lo map.lo \
-               conn.lo candidates.lo dncache.lo meta_result.lo
+               conn.lo candidates.lo dncache.lo meta_result.lo monitor.lo
 
 LDAP_INCDIR= ../../../include
 LDAP_LIBDIR= ../../../libraries
index dafc040f64ee3553b7be3256fec7a8a71f89bc8d..9ebdd8ffbf15c04b784bdef7ea9b4960aa8ffe62 100644 (file)
@@ -168,6 +168,8 @@ typedef struct a_metaconn_t {
        struct a_metainfo_t     *mc_info;
 
        int pending_ops;
+       /* numeric id for logging and testing purposes */
+       int mc_id;
        ldap_pvt_thread_mutex_t mc_om_mutex;
        /* queue for pending operations */
        LDAP_STAILQ_HEAD(BCList, bm_context_t) mc_om_list;
@@ -358,6 +360,15 @@ typedef int (*asyncmeta_quarantine_f)( struct a_metainfo_t *, int target, void *
 
 struct meta_out_message_t;
 
+/* data for cn=monitor */
+typedef struct asyncmeta_monitor_info_t {
+       monitor_subsys_t        *mi_conn_mss;
+       monitor_subsys_t    *mi_targets_mss;
+       struct berval           mi_ndn;
+       struct berval           mi_conn_rdn;
+       struct berval           mi_targets_rdn;
+} asycnmeta_monitor_info_t;
+
 typedef struct a_metainfo_t {
        int                     mi_ntargets;
        int                     mi_defaulttarget;
@@ -420,6 +431,8 @@ typedef struct a_metainfo_t {
        int                    mi_max_timeout_ops;
        int                    mi_max_pending_ops;
        int                    mi_max_target_conns;
+
+       asycnmeta_monitor_info_t mi_monitor_info;
        /* mutex for access to the connection structures */
        ldap_pvt_thread_mutex_t mi_mc_mutex;
        int                    mi_num_conns;
@@ -784,6 +797,19 @@ asyncmeta_target_free(a_metatarget_t *mt);
 void
 asyncmeta_back_clear_miconns(a_metainfo_t *mi);
 
+/* cn=monitor */
+int
+asyncmeta_back_monitor_db_init( BackendDB *be );
+
+int
+asyncmeta_back_monitor_db_open( BackendDB *be );
+
+int
+asyncmeta_back_monitor_db_close( BackendDB *be );
+
+int
+asyncmeta_back_monitor_db_destroy( BackendDB *be );
+
 /* The the maximum time in seconds after a result has been received on a connection,
  * after which it can be reset if a sender error occurs. Should this be configurable? */
 #define META_BACK_RESULT_INTERVAL (2)
index ba95f60735dc41efc5edd4a864ea0f36d307673c..f4cfdad40749313976fa82ddb156d821496c9a43 100644 (file)
@@ -160,12 +160,15 @@ asyncmeta_back_db_init(
        mi->mi_conn_priv_max = LDAP_BACK_CONN_PRIV_DEFAULT;
 
        mi->mi_ldap_extra = (ldap_extra_t *)bi->bi_extra;
+       /* only so that the first chosen connection is the first in the
+          array, for test purposes */
+       mi->mi_next_conn = -1;
        ldap_pvt_thread_mutex_init( &mi->mi_mc_mutex);
 
        be->be_private = mi;
        be->be_cf_ocs = be->bd_info->bi_cf_ocs;
 
-       return 0;
+       return asyncmeta_back_monitor_db_init( be );
 }
 
 int
@@ -262,6 +265,7 @@ asyncmeta_back_db_open(
                for (i = 0; i < mi->mi_num_conns; i++) {
                        a_metaconn_t *mc = &mi->mi_conns[i];
                        ldap_pvt_thread_mutex_init( &mc->mc_om_mutex);
+                       mc->mc_id = i+1;
                        mc->mc_authz_target = META_BOUND_NONE;
 
                        if ( mi->mi_ntargets > 0 ) {
@@ -284,7 +288,8 @@ asyncmeta_back_db_open(
                        ldap_pvt_thread_mutex_unlock( &slapd_rq.rq_mutex );
                }
        }
-       return 0;
+
+       return asyncmeta_back_monitor_db_open( be );
 }
 
 /*
@@ -410,7 +415,7 @@ asyncmeta_back_db_close(
                                }
                }
        }
-       return 0;
+       return asyncmeta_back_monitor_db_close( be );
 }
 
 int
@@ -419,7 +424,7 @@ asyncmeta_back_db_destroy(
        ConfigReply     *cr )
 {
        a_metainfo_t    *mi;
-
+       int rc = 0;
        if ( be->be_private ) {
                int i;
 
@@ -467,10 +472,10 @@ asyncmeta_back_db_destroy(
                asyncmeta_back_clear_miconns(mi);
                ldap_pvt_thread_mutex_unlock( &mi->mi_mc_mutex );
                ldap_pvt_thread_mutex_destroy( &mi->mi_mc_mutex );
-
+               rc = asyncmeta_back_monitor_db_destroy( be );
                free( be->be_private );
        }
-       return 0;
+       return rc;
 }
 
 #if SLAPD_ASYNCMETA == SLAPD_MOD_DYNAMIC
diff --git a/servers/slapd/back-asyncmeta/monitor.c b/servers/slapd/back-asyncmeta/monitor.c
new file mode 100644 (file)
index 0000000..0cc4557
--- /dev/null
@@ -0,0 +1,1210 @@
+/* monitor.c - monitor asyncmeta backend */
+/* $OpenLDAP$ */
+/* This work is part of OpenLDAP Software <http://www.openldap.org/>.
+ * * Copyright 2016-2025 The OpenLDAP Foundation.
+ * Portions Copyright 2016 Symas Corporation.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted only as authorized by the OpenLDAP
+ * Public License.
+ *
+ * A copy of this license is available in the file LICENSE in the
+ * top-level directory of the distribution or, alternatively, at
+ * <http://www.OpenLDAP.org/license.html>.
+ */
+
+/* ACKNOWLEDGEMENTS:
+ * This work was developed by Symas Corporation
+ * based on back-meta module for inclusion in OpenLDAP Software.
+ * This work was sponsored by Ericsson. */
+
+
+#include "portable.h"
+
+#include <stdio.h>
+#include <ac/string.h>
+#include <ac/unistd.h>
+#include <ac/stdlib.h>
+#include <ac/errno.h>
+#include <sys/stat.h>
+#include "lutil.h"
+#include "slap.h"
+#include "../back-ldap/back-ldap.h"
+#include "back-asyncmeta.h"
+
+#include "slap-config.h"
+
+static ObjectClass             *oc_olmAsyncmetaDatabase;
+static ObjectClass             *oc_olmAsyncmetaTarget;
+static ObjectClass             *oc_olmAsyncmetaConnectionGroup;
+static ObjectClass             *oc_olmAsyncmetaTargetConnection;
+
+static ObjectClass             *oc_monitorContainer;
+static ObjectClass             *oc_monitorCounterObject;
+/* Database Attributes */
+static AttributeDescription    *ad_olmDbNextConnectionGroup; /*mi_next_conn*/
+/* Target Attributes */
+static AttributeDescription    *ad_olmTgtURIList; /* mt_uri */
+static AttributeDescription    *ad_olmTgtQuarantined; /*mt_isquarantined*/
+static AttributeDescription    *ad_olmTgtTimeoutOps; /*mt_timeout_ops*/
+/* Connection Group (a_metaconn_t) attributes */
+static AttributeDescription    *ad_olmCGID;
+static AttributeDescription    *ad_olmCGPendingOps;
+/* individual target connections, one per each target per connection group (a_metasingleconn_t) */
+static AttributeDescription    *ad_olmTargetConnLastUseTime; /* msc_time */
+static AttributeDescription    *ad_olmTargetConnBoundTime; /* msc_binding_time */
+static AttributeDescription    *ad_olmTargetConnResultTime; /* msc_result_time */
+static AttributeDescription    *ad_olmTargetConnFlags; /* msc_mscflags */
+static AttributeDescription    *ad_olmTargetConnURI;
+static AttributeDescription    *ad_olmTargetConnPeerAddress;
+
+
+/* Corresponds to connection flags in back-ldap.h and back-asyncmeta.h */
+static struct {
+       unsigned        flag;
+       struct berval   name;
+}              s_flag[] = {
+       { LDAP_BACK_FCONN_ISBOUND,      BER_BVC( "bound" ) },
+       { LDAP_BACK_FCONN_ISANON,       BER_BVC( "anonymous" ) },
+       { LDAP_BACK_FCONN_ISPRIV,       BER_BVC( "privileged" ) },
+       { LDAP_BACK_FCONN_ISTLS,        BER_BVC( "TLS" ) },
+       { LDAP_BACK_FCONN_BINDING,      BER_BVC( "binding" ) },
+       { LDAP_BACK_FCONN_TAINTED,      BER_BVC( "tainted" ) },
+       { LDAP_BACK_FCONN_ABANDON,      BER_BVC( "abandon" ) },
+       { LDAP_BACK_FCONN_ISIDASR,      BER_BVC( "idassert" ) },
+       { LDAP_BACK_FCONN_CACHED,       BER_BVC( "cached" ) },
+       { META_BACK_FCONN_INITED,       BER_BVC( "initialized" ) },
+       { META_BACK_FCONN_CREATING,     BER_BVC( "creating" ) },
+       { META_BACK_FCONN_INVALID,      BER_BVC( "invalid" ) },
+       { 0 }
+};
+
+
+/*
+ * NOTE: there's some confusion in monitor OID arc;
+ * by now, let's consider:
+ *
+ * Subsystems monitor attributes       1.3.6.1.4.1.4203.666.1.55.0
+ * Databases monitor attributes                1.3.6.1.4.1.4203.666.1.55.0.1
+ * Asyncmeta database monitor attributes       1.3.6.1.4.1.4203.666.1.55.0.1.4
+ *
+ * Subsystems monitor objectclasses    1.3.6.1.4.1.4203.666.3.16.0
+ * Databases monitor objectclasses     1.3.6.1.4.1.4203.666.3.16.0.1
+ * Asyncmeta database monitor objectclasses    1.3.6.1.4.1.4203.666.3.16.0.1.4
+ */
+
+static struct {
+       char                    *name;
+       char                    *oid;
+}              s_oid[] = {
+       { "olmAsyncmetaAttributes",                     "olmDatabaseAttributes:4" },
+       { "olmAsyncmetaObjectClasses",          "olmDatabaseObjectClasses:4" },
+
+       { NULL }
+};
+
+static struct {
+       char                    *desc;
+       AttributeDescription    **ad;
+}              s_at[] = {
+       { "( olmAsyncmetaAttributes:1 "
+         "NAME ( 'olmDbNextConnectionGroup' ) "
+         "DESC 'ID of the next connection group to be used' "
+         "SUP monitorCounter "
+         "SINGLE-VALUE "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmDbNextConnectionGroup },
+       { "( olmAsyncmetaAttributes:2 "
+         "NAME ( 'olmTgtURIList' ) "
+         "DESC 'List of URIs a target is serving' "
+         "SUP monitoredInfo    "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTgtURIList },
+       { "( olmAsyncmetaAttributes:3 "
+         "NAME ( 'olmTgtQuarantined' ) "
+         "DESC 'Is this target quanatined' "
+         "EQUALITY booleanMatch "
+         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.7 "
+         "SINGLE-VALUE "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTgtQuarantined },
+       { "( olmAsyncmetaAttributes:4 "
+         "NAME ( 'olmTgtTimeoutOps' ) "
+         "DESC 'Total number of timed out operations for this target since it was last quarantined' "
+         "SUP monitorCounter "
+         "SINGLE-VALUE "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTgtTimeoutOps },
+       { "( olmAsyncmetaAttributes:5 "
+         "NAME ( 'olmCGID' ) "
+         "DESC 'Connection Group ID' "
+         "SUP monitorCounter "
+         "SINGLE-VALUE "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmCGID },
+       { "( olmAsyncmetaAttributes:6 "
+         "NAME ( 'olmCGPendingOps' ) "
+         "DESC 'Operations waiting for a result in this connection group queue' "
+         "SUP monitorCounter "
+         "SINGLE-VALUE "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmCGPendingOps },
+       { "( olmAsyncmetaAttributes:7 "
+         "NAME ( 'olmTargetConnLastUseTime' ) "
+         "DESC 'Time the connection was last used to proxy an operation, 0 if the connection is not established' "
+         "EQUALITY integerMatch "
+         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
+         "SINGLE-VALUE "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTargetConnLastUseTime },
+       { "( olmAsyncmetaAttributes:8 "
+         "NAME ( 'olmTargetConnBoundTime' ) "
+         "DESC 'Time the connection was bound, 0 if the connection is not established' "
+         "EQUALITY integerMatch "
+         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
+         "SINGLE-VALUE "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTargetConnBoundTime },
+       { "( olmAsyncmetaAttributes:9 "
+         "NAME ( 'olmTargetConnResultTime' ) "
+         "DESC 'Last time a result was received, 0 if the connection is not established' "
+         "EQUALITY integerMatch "
+         "SYNTAX 1.3.6.1.4.1.1466.115.121.1.27 "
+         "SINGLE-VALUE "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTargetConnResultTime },
+       { "( olmAsyncmetaAttributes:10 "
+         "NAME ( 'olmTargetConnFlags' ) "
+         "DESC 'Target Connection Flags' "
+         "SUP monitoredInfo "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTargetConnFlags },
+       { "( olmAsyncmetaAttributes:11 "
+         "NAME ( 'olmTargetConnURI' ) "
+         "DESC 'Target connection URI' "
+         "SUP monitorConnectionPeerAddress "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTargetConnURI },
+       { "( olmAsyncmetaAttributes:12 "
+         "NAME ( 'olmTargetConnPeerAddress' ) "
+         "DESC 'Target connection peer address' "
+         "SUP monitorConnectionPeerAddress "
+         "NO-USER-MODIFICATION "
+         "USAGE dSAOperation )",
+         &ad_olmTargetConnPeerAddress },
+       { NULL }
+};
+
+static struct {
+       char            *name;
+       ObjectClass     **oc;
+}              s_moc[] = {
+       { "monitorContainer", &oc_monitorContainer },
+       { "monitorCounterObject", &oc_monitorCounterObject },
+
+       { NULL }
+};
+
+static struct {
+       char            *desc;
+       ObjectClass     **oc;
+}              s_oc[] = {
+       /* augments an existing object, so it must be AUXILIARY */
+       { "( olmAsyncmetaObjectClasses:1 "
+               "NAME ( 'olmAsyncmetaDatabase' ) "
+               "SUP top AUXILIARY "
+               "MAY ( "
+                       "olmDbNextConnectionGroup "
+                       ") )",
+               &oc_olmAsyncmetaDatabase },
+       { "( olmAsyncmetaObjectClasses:2 "
+               "NAME ( 'olmAsyncmetaTarget' ) "
+               "SUP monitorConnection STRUCTURAL "
+               "MAY ( "
+                "olmTgtURIList "
+                "$ olmTgtQuarantined "
+                "$ olmTgtTimeoutOps "
+                       ") )",
+               &oc_olmAsyncmetaTarget },
+       { "( olmAsyncmetaObjectClasses:3 "
+               "NAME ( 'olmAsyncmetaConnectionGroup' ) "
+               "SUP monitorConnection STRUCTURAL "
+               "MAY ( "
+                "olmCGID "
+                "$ olmCGPendingOps "
+                       ") )",
+               &oc_olmAsyncmetaConnectionGroup },
+       { "( olmAsyncmetaObjectClasses:4 "
+               "NAME ( 'olmAsyncmetaTargetConnection' ) "
+               "SUP monitorConnection STRUCTURAL "
+               "MAY ( "
+                "olmTargetConnLastUseTime "
+                "$ olmTargetConnBoundTime "
+                "$ olmTargetConnResultTime "
+                        "$ olmTargetConnFlags "
+                        "$ olmTargetConnURI "
+                        "$ olmTargetConnPeerAddress"
+                       ") )",
+               &oc_olmAsyncmetaTargetConnection },
+
+       { NULL }
+};
+
+/* stolen from mdb_monitor_free */
+static int
+asyncmeta_monitor_free(
+       Entry           *e,
+       ObjectClass *oc,
+       void            **priv )
+{
+       struct berval   values[ 2 ];
+       Modification    mod = { 0 };
+
+       const char      *text;
+       char            textbuf[ SLAP_TEXT_BUFLEN ];
+
+       int             i;
+
+       /* NOTE: if slap_shutdown != 0, priv might have already been freed */
+       *priv = NULL;
+
+       /* Remove objectClass */
+       mod.sm_op = LDAP_MOD_DELETE;
+       mod.sm_desc = slap_schema.si_ad_objectClass;
+       mod.sm_values = values;
+       mod.sm_numvals = 1;
+       values[ 0 ] = oc->soc_cname;
+       BER_BVZERO( &values[ 1 ] );
+
+        modify_delete_values( e, &mod, 1, &text,
+               textbuf, sizeof( textbuf ) );
+
+       /* remove attrs */
+       mod.sm_values = NULL;
+       mod.sm_numvals = 0;
+       for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
+               mod.sm_desc = *s_at[ i ].ad;
+               modify_delete_values( e, &mod, 1, &text,
+                       textbuf, sizeof( textbuf ) );
+       }
+
+       return SLAP_CB_CONTINUE;
+}
+
+
+static int
+asyncmeta_back_monitor_subsystem_destroy(
+       BackendDB               *be,
+       monitor_subsys_t        *ms)
+{
+       free(ms->mss_dn.bv_val);
+       BER_BVZERO(&ms->mss_dn);
+
+       free(ms->mss_ndn.bv_val);
+       BER_BVZERO(&ms->mss_ndn);
+
+       return LDAP_SUCCESS;
+}
+
+
+/* code stolen from back-ldap, stolen from daemon.c */
+static int
+asyncmeta_back_monitor_conn_peername(
+       LDAP            *ld,
+       struct berval   *bv)
+{
+       Sockbuf *sockbuf;
+       ber_socket_t socket;
+       Sockaddr sa;
+       socklen_t salen = sizeof(sa);
+       const char *peeraddr = NULL;
+       /* we assume INET6_ADDRSTRLEN > INET_ADDRSTRLEN */
+       char addr[INET6_ADDRSTRLEN];
+#ifdef LDAP_PF_LOCAL
+       char peername[MAXPATHLEN + sizeof("PATH=")];
+#elif defined(LDAP_PF_INET6)
+       char peername[sizeof("IP=[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff]:65535")];
+#else /* ! LDAP_PF_LOCAL && ! LDAP_PF_INET6 */
+       char peername[sizeof("IP=255.255.255.255:65336")];
+#endif /* LDAP_PF_LOCAL */
+
+       assert( bv != NULL );
+
+       ldap_get_option( ld, LDAP_OPT_SOCKBUF, (void **)&sockbuf );
+       ber_sockbuf_ctrl( sockbuf, LBER_SB_OPT_GET_FD, &socket );
+       getpeername( socket, (struct sockaddr *)&sa, &salen );
+
+       switch ( sa.sa_addr.sa_family ) {
+#ifdef LDAP_PF_LOCAL
+               case AF_LOCAL:
+                       sprintf( peername, "PATH=%s", sa.sa_un_addr.sun_path );
+                       break;
+#endif /* LDAP_PF_LOCAL */
+
+#ifdef LDAP_PF_INET6
+               case AF_INET6:
+                       if ( IN6_IS_ADDR_V4MAPPED(&sa.sa_in6_addr.sin6_addr) ) {
+#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
+                               peeraddr = inet_ntop( AF_INET,
+                                               ((struct in_addr *)&sa.sa_in6_addr.sin6_addr.s6_addr[12]),
+                                               addr, sizeof(addr) );
+#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
+                               peeraddr = inet_ntoa( *((struct in_addr *)
+                                                       &sa.sa_in6_addr.sin6_addr.s6_addr[12]) );
+#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
+                               if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
+                               sprintf( peername, "IP=%s:%d", peeraddr,
+                                               (unsigned) ntohs( sa.sa_in6_addr.sin6_port ) );
+                       } else {
+                               peeraddr = inet_ntop( AF_INET6,
+                                               &sa.sa_in6_addr.sin6_addr,
+                                               addr, sizeof addr );
+                               if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
+                               sprintf( peername, "IP=[%s]:%d", peeraddr,
+                                               (unsigned) ntohs( sa.sa_in6_addr.sin6_port ) );
+                       }
+                       break;
+#endif /* LDAP_PF_INET6 */
+
+               case AF_INET: {
+#if defined( HAVE_GETADDRINFO ) && defined( HAVE_INET_NTOP )
+                                     peeraddr = inet_ntop( AF_INET, &sa.sa_in_addr.sin_addr,
+                                                     addr, sizeof(addr) );
+#else /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
+                                     peeraddr = inet_ntoa( sa.sa_in_addr.sin_addr );
+#endif /* ! HAVE_GETADDRINFO || ! HAVE_INET_NTOP */
+                                     if ( !peeraddr ) peeraddr = SLAP_STRING_UNKNOWN;
+                                     sprintf( peername, "IP=%s:%d", peeraddr,
+                                                     (unsigned) ntohs( sa.sa_in_addr.sin_port ) );
+                             } break;
+
+               default:
+                             sprintf( peername, SLAP_STRING_UNKNOWN );
+       }
+
+       ber_str2bv( peername, 0, 1, bv );
+       return LDAP_SUCCESS;
+}
+
+
+static int
+asyncmeta_back_monitor_target_conn_update(
+       Operation       *op,
+       SlapReply       *rs,
+       Entry *e,
+       void *priv)
+{
+       a_metasingleconn_t *msc = ( a_metasingleconn_t* )priv;
+       Attribute *a;
+       char buf[ BUFSIZ ];
+       struct berval bv;
+       char *ptr;
+       int i;
+
+       a = attr_find( e->e_attrs, ad_olmTargetConnLastUseTime );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", msc->msc_time );
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+       a = attr_find( e->e_attrs, ad_olmTargetConnBoundTime );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", msc->msc_binding_time );
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+       a = attr_find( e->e_attrs, ad_olmTargetConnResultTime );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", msc->msc_result_time );
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+       a = attr_find( e->e_attrs, ad_olmTargetConnFlags );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       bv.bv_len = 0;
+       ptr = bv.bv_val;
+
+       if ( msc->msc_mscflags == 0 ) {
+               bv.bv_len = snprintf( bv.bv_val, sizeof( buf ), "closed" );
+       } else {
+               for ( i = 0; s_flag[i].flag; i++ ) {
+                       int len = 0;
+                       if ( msc->msc_mscflags & s_flag[i].flag ) {
+                               if ( bv.bv_len == 0 )
+                                       len = snprintf( ptr, sizeof( buf ), "%s", s_flag[i].name.bv_val );
+                               else
+                                       len = snprintf( ptr, sizeof( buf )-bv.bv_len, ",%s", s_flag[i].name.bv_val );
+                               bv.bv_len += len;
+                               ptr += len;
+                       }
+               }
+       }
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+       bv.bv_len = 0;
+
+       if ( msc->msc_ld ) {
+               a = attr_find( e->e_attrs, ad_olmTargetConnURI );
+               ldap_get_option( msc->msc_ld, LDAP_OPT_URI, &bv.bv_val );
+               ptr = strchr( bv.bv_val, ' ' );
+               bv.bv_len = ptr ? ptr - bv.bv_val : strlen(bv.bv_val);
+               ber_bvreplace( &a->a_vals[ 0 ], &bv );
+               ch_free( bv.bv_val );
+
+               asyncmeta_back_monitor_conn_peername( msc->msc_ld, &bv );
+               a = attr_find( e->e_attrs, ad_olmTargetConnPeerAddress );
+               ber_bvreplace( &a->a_vals[ 0 ], &bv );
+               ch_free( bv.bv_val );
+       } else {
+               a = attr_find( e->e_attrs, ad_olmTargetConnURI );
+               ber_bvreplace( &a->a_vals[ 0 ], &bv );
+               a = attr_find( e->e_attrs, ad_olmTargetConnPeerAddress );
+               ber_bvreplace( &a->a_vals[ 0 ], &bv );
+       }
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+asyncmeta_back_monitor_target_conn_free(
+       Entry *e,
+       void **priv)
+{
+       return asyncmeta_monitor_free( e, oc_olmAsyncmetaTargetConnection, priv );
+}
+
+static int
+asyncmeta_back_monitor_target_conn_init(
+       BackendDB               *be,
+       monitor_subsys_t        *ms,
+       Entry *parent,
+       a_metaconn_t *mc )
+{
+       a_metainfo_t    *mi = (a_metainfo_t *) ms->mss_private;
+       monitor_extra_t *mbe;
+
+       Entry           *e;
+       int             rc = 0;
+       int i;
+
+       assert( be != NULL );
+       mbe = (monitor_extra_t *) be->bd_info->bi_extra;
+
+       for ( i = 0; i < mi->mi_ntargets; i++ )
+       {
+               monitor_callback_t *cb;
+               char                        buf[ BACKMONITOR_BUFSIZE ];
+               struct berval       conn_rdn;
+               Attribute               *a, *next;
+               struct berval bv = BER_BVC( "0" );
+
+               snprintf( buf, sizeof( buf ),
+                                 "cn=Target Connection %d", i+1 );
+               ber_str2bv( buf, 0, 0, &conn_rdn );
+
+               e = mbe->entry_stub( &parent->e_name, &parent->e_nname,
+                       &conn_rdn,
+                       oc_olmAsyncmetaTargetConnection, NULL, NULL );
+               if ( e == NULL ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_target_conn_init: "
+                               "unable to create entry \"%s,%s\"\n",
+                               conn_rdn.bv_val,
+                               parent->e_nname.bv_val );
+                       return( -1 );
+               }
+
+               cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
+               cb->mc_update = asyncmeta_back_monitor_target_conn_update;
+               cb->mc_free = asyncmeta_back_monitor_target_conn_free;
+               cb->mc_private = (void *)&mc->mc_conns[i];
+
+               a = attrs_alloc( 1 + 6 );
+
+               a->a_desc = slap_schema.si_ad_objectClass;
+               attr_valadd( a, &oc_olmAsyncmetaTargetConnection->soc_cname, NULL, 1 );
+               next = a->a_next;
+
+               next->a_desc = ad_olmTargetConnLastUseTime;
+               attr_valadd( next, &bv, NULL, 1 );
+               next = next->a_next;
+
+               next->a_desc = ad_olmTargetConnBoundTime;
+               attr_valadd( next, &bv, NULL, 1 );
+               next = next->a_next;
+
+               next->a_desc = ad_olmTargetConnResultTime;
+               attr_valadd( next, &bv, NULL, 1 );
+               next = next->a_next;
+
+               next->a_desc = ad_olmTargetConnFlags;
+               attr_valadd( next, &bv, NULL, 1 );
+               next = next->a_next;
+
+               next->a_desc = ad_olmTargetConnURI;
+               attr_valadd( next, &bv, NULL, 1 );
+               next = next->a_next;
+
+               next->a_desc = ad_olmTargetConnPeerAddress;
+               attr_valadd( next, &bv, NULL, 1 );
+
+               rc = mbe->register_entry( e, NULL, ms, MONITOR_F_PERSISTENT_CH );
+               if ( rc != LDAP_SUCCESS )
+               {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_target_conn_init: "
+                               "unable to register entry \"%s\" for monitoring\n",
+                               e->e_name.bv_val );
+                       ch_free( cb );
+                       attrs_free( a );
+                       entry_free( e );
+                       break;
+               }
+
+               rc = mbe->register_entry_attrs( &e->e_nname, a, cb,
+                                                                                       NULL, -1, NULL );
+               if ( rc != LDAP_SUCCESS )
+               {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_target_conn_init: "
+                               "unable to register entry attributes \"%s\" for monitoring\n",
+                               e->e_name.bv_val );
+               }
+               attrs_free( a );
+               entry_free( e );
+       }
+
+       return rc;
+}
+
+static int
+asyncmeta_back_monitor_conn_group_update(
+       Operation       *op,
+       SlapReply       *rs,
+       Entry *e,
+       void *priv)
+{
+       a_metaconn_t *mc = ( a_metaconn_t* )priv;
+       Attribute *a;
+       char buf[ BUFSIZ ];
+       struct berval bv;
+
+       a = attr_find( e->e_attrs, ad_olmCGPendingOps );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       bv.bv_len = snprintf( buf, sizeof( buf ), "%i", mc->pending_ops );
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+/* FIXME!!! */
+       a = attr_find( e->e_attrs, ad_olmCGID );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       bv.bv_len = snprintf( buf, sizeof( buf ), "%i", mc->pending_ops );
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+       return SLAP_CB_CONTINUE;
+}
+
+
+static int
+asyncmeta_back_monitor_conn_group_free(
+       Entry *e,
+       void **priv)
+{
+       return asyncmeta_monitor_free( e, oc_olmAsyncmetaConnectionGroup, priv );
+}
+
+static int
+asyncmeta_back_monitor_conn_init(
+       BackendDB               *be,
+       monitor_subsys_t        *ms )
+{
+       a_metainfo_t    *mi = (a_metainfo_t *) ms->mss_private;
+       monitor_extra_t *mbe;
+
+       Entry           *e, *parent;
+       int             rc;
+       int i;
+
+       assert( be != NULL );
+       mbe = (monitor_extra_t *) be->bd_info->bi_extra;
+
+       ms->mss_dn = ms->mss_ndn = mi->mi_monitor_info.mi_ndn;
+       ms->mss_destroy = asyncmeta_back_monitor_subsystem_destroy;
+
+       parent = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn,
+               &mi->mi_monitor_info.mi_conn_rdn, oc_monitorContainer, NULL, NULL );
+       if ( parent == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "asyncmeta_back_monitor_conn_init: "
+                       "unable to create entry \"%s,%s\"\n",
+                       mi->mi_monitor_info.mi_conn_rdn.bv_val,
+                       ms->mss_ndn.bv_val );
+               return( -1 );
+       }
+
+       ber_dupbv( &ms->mss_dn, &parent->e_name );
+       ber_dupbv( &ms->mss_ndn, &parent->e_nname );
+       ber_dupbv( &ms->mss_rdn, &mi->mi_monitor_info.mi_conn_rdn );
+
+       rc = mbe->register_entry( parent, NULL, ms, MONITOR_F_PERSISTENT_CH );
+
+       for ( i = 0; i < mi->mi_num_conns; i++ )
+       {
+               monitor_callback_t *cb;
+               char                        buf[ BACKMONITOR_BUFSIZE ];
+               struct berval       conn_group_rdn;
+               Attribute               *a,  *next;
+               struct berval bv = BER_BVC( "0" );
+
+               snprintf( buf, sizeof( buf ),
+                                 "cn=Connection Group %d", i+1 );
+               ber_str2bv( buf, 0, 0, &conn_group_rdn );
+
+               e = mbe->entry_stub( &parent->e_name, &parent->e_nname,
+                       &conn_group_rdn,
+                       oc_olmAsyncmetaConnectionGroup, NULL, NULL );
+               if ( e == NULL ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_conn_init: "
+                               "unable to create entry \"%s,%s\"\n",
+                               conn_group_rdn.bv_val,
+                               parent->e_nname.bv_val );
+                       return( -1 );
+               }
+
+               cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
+               cb->mc_update = asyncmeta_back_monitor_conn_group_update;
+               cb->mc_free = asyncmeta_back_monitor_conn_group_free;
+               cb->mc_private = (void *)&mi->mi_conns[i];
+               cb->mc_next = NULL;
+
+               a = attrs_alloc( 1 + 2 );
+
+               a->a_desc = slap_schema.si_ad_objectClass;
+               attr_valadd( a, &oc_olmAsyncmetaConnectionGroup->soc_cname, NULL, 1 );
+               next = a->a_next;
+
+               next->a_desc = ad_olmCGID;
+               attr_valadd( next, &bv, NULL, 1 );
+               next = next->a_next;
+
+               next->a_desc = ad_olmCGPendingOps;
+               attr_valadd( next, &bv, NULL, 1 );
+
+               rc = mbe->register_entry( e, NULL, ms, MONITOR_F_PERSISTENT_CH );
+               if ( rc != LDAP_SUCCESS )
+               {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_conn_init: "
+                               "unable to register entry \"%s\" for monitoring\n",
+                               e->e_name.bv_val );
+                       ch_free( cb );
+                       attrs_free( a );
+                       entry_free( e );
+                       break;
+               }
+
+               rc = mbe->register_entry_attrs( &e->e_nname, a, cb,
+                                                                                       NULL, -1, NULL );
+               if ( rc != LDAP_SUCCESS )
+               {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_conn_init: "
+                               "unable to register entry attributes \"%s\" for monitoring\n",
+                               e->e_name.bv_val );
+               }
+
+               rc = asyncmeta_back_monitor_target_conn_init( be, ms, e, &mi->mi_conns[i] );
+               if ( rc != LDAP_SUCCESS )
+               {
+                       ch_free( cb );
+                       attrs_free( a );
+                       entry_free( e );
+                       break;
+               }
+               attrs_free( a );
+               entry_free( e );
+       }
+
+       entry_free( parent );
+
+       return rc;
+}
+
+/*
+ * Targets monitoring subsystem:
+ * Is target quarantined, last time a connection to it was reset, etc
+ */
+
+static int
+asyncmeta_back_monitor_targets_free(
+       Entry *e,
+       void **priv)
+{
+       return asyncmeta_monitor_free( e, oc_olmAsyncmetaTarget, priv );
+}
+
+static int
+asyncmeta_back_monitor_targets_update(
+       Operation       *op,
+       SlapReply       *rs,
+       Entry           *e,
+       void            *priv )
+{
+       a_metatarget_t *mt = ( a_metatarget_t* )priv;
+       Attribute *a;
+       char buf[ BUFSIZ ];
+       struct berval bv;
+
+       a = attr_find( e->e_attrs, ad_olmTgtURIList );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       /* todo mutex*/
+       bv.bv_len = snprintf( buf, sizeof( buf ), "%s", mt->mt_uri );
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+       a = attr_find( e->e_attrs, ad_olmTgtQuarantined );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       if ( mt->mt_isquarantined > 0 ) {
+               bv.bv_len = snprintf( buf, sizeof( buf ), "%s", "TRUE" );
+       } else {
+               bv.bv_len = snprintf( buf, sizeof( buf ), "%s", "FALSE" );
+       }
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+       a = attr_find( e->e_attrs, ad_olmTgtTimeoutOps );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       bv.bv_len = snprintf( buf, sizeof( buf ), "%i", mt->mt_timeout_ops );
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+asyncmeta_back_monitor_targets_init(
+       BackendDB               *be,
+       monitor_subsys_t        *ms )
+{
+       a_metainfo_t    *mi = (a_metainfo_t *) ms->mss_private;
+       monitor_extra_t *mbe;
+       Entry           *e, *parent;
+       int             rc;
+       int i;
+
+       assert( be != NULL );
+
+       mbe = (monitor_extra_t *) be->bd_info->bi_extra;
+
+       ms->mss_dn = ms->mss_ndn = mi->mi_monitor_info.mi_ndn;
+       ms->mss_destroy = asyncmeta_back_monitor_subsystem_destroy;
+
+       parent = mbe->entry_stub( &ms->mss_dn, &ms->mss_ndn,
+               &mi->mi_monitor_info.mi_targets_rdn, oc_monitorContainer, NULL, NULL );
+       if ( parent == NULL ) {
+               Debug( LDAP_DEBUG_ANY,
+                       "asyncmeta_back_monitor_targets_init: "
+                       "unable to create entry \"%s,%s\"\n",
+                       mi->mi_monitor_info.mi_targets_rdn.bv_val,
+                       ms->mss_ndn.bv_val );
+               return( -1 );
+       }
+
+       ber_dupbv( &ms->mss_dn, &parent->e_name );
+       ber_dupbv( &ms->mss_ndn, &parent->e_nname );
+       ber_dupbv( &ms->mss_rdn, &mi->mi_monitor_info.mi_conn_rdn );
+       
+       rc = mbe->register_entry( parent, NULL, ms, MONITOR_F_PERSISTENT_CH );
+       if ( rc != LDAP_SUCCESS )
+       {
+               Debug( LDAP_DEBUG_ANY,
+                       "asyncmeta_back_monitor_target_init: "
+                       "unable to register entry \"%s\" for monitoring\n",
+                       parent->e_name.bv_val );
+               goto done;
+       }
+
+       for ( i = 0; i < mi->mi_ntargets; i++ )
+       {
+               monitor_callback_t *cb;
+               char                        buf[ BACKMONITOR_BUFSIZE ];
+               struct berval       target_rdn;
+               Attribute               *a, *next;
+               struct berval bv = BER_BVC( "0" );
+
+               snprintf( buf, sizeof( buf ),
+                                 "cn=Target %d", i+1 );
+               ber_str2bv( buf, 0, 0, &target_rdn );
+
+               e = mbe->entry_stub( &parent->e_name, &parent->e_nname,
+                       &target_rdn,
+                       oc_olmAsyncmetaTarget, NULL, NULL );
+               if ( e == NULL ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_targets_init: "
+                               "unable to create entry \"%s,%s\"\n",
+                               target_rdn.bv_val,
+                               parent->e_nname.bv_val );
+                       return( -1 );
+               }
+
+               cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
+               cb->mc_update = asyncmeta_back_monitor_targets_update;
+               cb->mc_free = asyncmeta_back_monitor_targets_free;
+               cb->mc_private = (void *)&mi->mi_targets[i];
+
+               a = attrs_alloc( 1 + 3 );
+
+               a->a_desc = slap_schema.si_ad_objectClass;
+               attr_valadd( a, &oc_olmAsyncmetaTarget->soc_cname, NULL, 1 );
+               next = a->a_next;
+
+               next->a_desc = ad_olmTgtURIList;
+               attr_valadd( next, &bv, NULL, 1 );
+               next = next->a_next;
+
+               next->a_desc = ad_olmTgtQuarantined;
+               attr_valadd( next, &bv, NULL, 1 );
+               next = next->a_next;
+
+               next->a_desc = ad_olmTgtTimeoutOps;
+               attr_valadd( next, &bv, NULL, 1 );
+
+               rc = mbe->register_entry( e, NULL, ms, MONITOR_F_PERSISTENT_CH );
+               if ( rc != LDAP_SUCCESS )
+               {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_targets_init: "
+                               "unable to register entry \"%s\" for monitoring\n",
+                               e->e_name.bv_val );
+                       ch_free( cb );
+                       attrs_free( a );
+                       entry_free( e );
+                       break;
+               }
+
+               rc = mbe->register_entry_attrs( &e->e_nname, a, cb,
+                                                                                       NULL, -1, NULL );
+               if ( rc != LDAP_SUCCESS )
+               {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_targets_init: "
+                               "unable to register entry attributes \"%s\" for monitoring\n",
+                               e->e_name.bv_val );
+               }
+               attrs_free( a );
+               entry_free( e );
+       }
+
+done:
+       entry_free( parent );
+
+       return rc;
+}
+
+/*
+ * call from within asyncmeta_back_initialize()
+ */
+static int
+asyncmeta_back_monitor_initialize( void )
+{
+       int             i, code;
+       ConfigArgs c;
+       char    *argv[ 3 ];
+
+       static int      asyncmeta_back_monitor_initialized = 0;
+
+       /* set to 0 when successfully initialized; otherwise, remember failure */
+       static int      asyncmeta_back_monitor_initialized_failure = 1;
+
+       /* register schema here */
+
+       if ( asyncmeta_back_monitor_initialized++ ) {
+               return asyncmeta_back_monitor_initialized_failure;
+       }
+
+       if ( backend_info( "monitor" ) == NULL ) {
+               return -1;
+       }
+
+       argv[ 0 ] = "back-asyncmeta monitor";
+       c.argv = argv;
+       c.argc = 3;
+       c.fname = argv[0];
+       for ( i = 0; s_oid[ i ].name; i++ ) {
+
+               argv[ 1 ] = s_oid[ i ].name;
+               argv[ 2 ] = s_oid[ i ].oid;
+
+               if ( parse_oidm( &c, 0, NULL ) != 0 ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_initialize: unable to add "
+                               "objectIdentifier \"%s=%s\"\n",
+                               s_oid[ i ].name, s_oid[ i ].oid );
+                       return 2;
+               }
+       }
+
+       for ( i = 0; s_at[ i ].desc != NULL; i++ ) {
+               code = register_at( s_at[ i ].desc, s_at[ i ].ad, 1 );
+               if ( code != LDAP_SUCCESS ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_initialize: register_at failed for attributeType (%s)\n",
+                               s_at[ i ].desc );
+                       return 3;
+
+               } else {
+                       (*s_at[ i ].ad)->ad_type->sat_flags |= SLAP_AT_HIDE;
+               }
+       }
+
+       for ( i = 0; s_oc[ i ].desc != NULL; i++ ) {
+               code = register_oc( s_oc[ i ].desc, s_oc[ i ].oc, 1 );
+               if ( code != LDAP_SUCCESS ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_initialize: register_oc failed for objectClass (%s)\n",
+                               s_oc[ i ].desc );
+                       return 4;
+
+               } else {
+                       (*s_oc[ i ].oc)->soc_flags |= SLAP_OC_HIDE;
+               }
+       }
+
+       for ( i = 0; s_moc[ i ].name != NULL; i++ ) {
+               *s_moc[i].oc = oc_find( s_moc[ i ].name );
+               if ( ! *s_moc[i].oc ) {
+                       Debug( LDAP_DEBUG_ANY,
+                               "asyncmeta_back_monitor_initialize: failed to find objectClass (%s)\n",
+                               s_moc[ i ].name );
+                       return 5;
+
+               }
+       }
+
+       return ( asyncmeta_back_monitor_initialized_failure = LDAP_SUCCESS );
+}
+
+/*
+ * call from within asyncmeta_back_db_init()
+ */
+int
+asyncmeta_back_monitor_db_init( BackendDB *be )
+{
+       int     rc;
+
+       rc = asyncmeta_back_monitor_initialize();
+       if ( rc != LDAP_SUCCESS ) {
+               return rc;
+       }
+
+       return 0;
+}
+
+/* adapted from mdb_monitor_update */
+static int
+asyncmeta_monitor_db_update(
+       Operation       *op,
+       SlapReply       *rs,
+       Entry           *e,
+       void            *priv )
+{
+       struct a_metainfo_t             *mi = (struct a_metainfo_t *) priv;
+       Attribute *a;
+       char buf[ BUFSIZ ];
+       struct berval bv;
+
+       a = attr_find( e->e_attrs, ad_olmDbNextConnectionGroup );
+       assert( a != NULL );
+       bv.bv_val = buf;
+       bv.bv_len = snprintf( buf, sizeof( buf ), "%i", mi->mi_next_conn+1 );
+       ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+       return SLAP_CB_CONTINUE;
+}
+
+static int
+asyncmeta_monitor_db_free
+(
+       Entry           *e,
+       void            **priv )
+{
+       return asyncmeta_monitor_free( e, oc_olmAsyncmetaDatabase, priv );
+}
+
+/*
+ * call from within asyncmeta_back_db_open()
+ */
+int
+asyncmeta_back_monitor_db_open( BackendDB *be )
+{
+       a_metainfo_t            *mi = (a_metainfo_t *) be->be_private;
+       monitor_subsys_t        *mss;
+       int                     rc = 0;
+       BackendInfo             *bi;
+       monitor_extra_t         *mbe;
+       Attribute *a, *next;
+       monitor_callback_t *cb;
+
+       struct berval bv = BER_BVC( "0" );
+
+       if ( !SLAP_DBMONITORING( be ) ) {
+               return 0;
+       }
+
+       /* check if monitor is configured and usable */
+       bi = backend_info( "monitor" );
+       if ( !bi || !bi->bi_extra ) {
+               SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
+               return 0;
+       }
+       mbe = bi->bi_extra;
+
+       /* don't bother if monitor is not configured */
+       if ( !mbe->is_configured() ) {
+               static int warning = 0;
+
+               if ( warning++ == 0 ) {
+                       Debug( LDAP_DEBUG_CONFIG, "back_asyncmeta_monitor_db_open: "
+                               "monitoring disabled; "
+                               "configure monitor database to enable\n" );
+               }
+
+               return 0;
+       }
+
+       if ( BER_BVISNULL( &mi->mi_monitor_info.mi_ndn ) ) {
+               rc = mbe->register_database( be, &mi->mi_monitor_info.mi_ndn );
+               if ( rc != 0 ) {
+                       Debug( LDAP_DEBUG_ANY, "back_asyncmeta_monitor_db_open: "
+                               "failed to register the database with back-monitor\n" );
+               }
+       }
+       a = attrs_alloc( 2 );
+       if ( a == NULL ) {
+               return -1;
+       }
+
+       a->a_desc = slap_schema.si_ad_objectClass;
+       attr_valadd( a, &oc_olmAsyncmetaDatabase->soc_cname, NULL, 1 );
+       next = a->a_next;
+
+       next->a_desc = ad_olmDbNextConnectionGroup;
+       attr_valadd( next, &bv, NULL, 1 );
+
+       cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
+       cb->mc_update = asyncmeta_monitor_db_update;
+       cb->mc_free = asyncmeta_monitor_db_free;
+       cb->mc_private = (void *)mi;
+
+       rc = mbe->register_entry_attrs( &mi->mi_monitor_info.mi_ndn, a, cb,
+                       NULL, -1, NULL );
+       attrs_free( a );
+       if ( rc != 0 ) {
+                       Debug( LDAP_DEBUG_ANY, "back_asyncmeta_monitor_db_open: "
+                                  "failed to register entry %s with back-monitor\n",
+                                  mi->mi_monitor_info.mi_ndn.bv_val );
+                       return rc;
+       }
+       if ( BER_BVISNULL( &mi->mi_monitor_info.mi_conn_rdn ) ) {
+               ber_str2bv( "cn=Connections", 0, 1,
+                       &mi->mi_monitor_info.mi_conn_rdn );
+       }
+       if ( BER_BVISNULL( &mi->mi_monitor_info.mi_targets_rdn ) ) {
+               ber_str2bv( "cn=Targets", 0, 1,
+                       &mi->mi_monitor_info.mi_targets_rdn );
+       }
+
+       /* set up the subsystems used to create the targets and
+        * connection entries */
+       /* unlike back-ldap, these entries are persistent,
+        * since asyncmeta maintains the data structures regardless of
+        * the ldap connection state */
+
+       /* this will leak at monitor_db_destroy, but it can't be helped */
+       mi->mi_monitor_info.mi_conn_mss = (monitor_subsys_t *)ch_calloc( 1, sizeof( monitor_subsys_t ) );
+       /* just for clarity */
+       mss = mi->mi_monitor_info.mi_conn_mss;
+       mss->mss_name = "back-asyncmeta connections";
+       mss->mss_flags = MONITOR_F_PERSISTENT_CH;
+       mss->mss_open = asyncmeta_back_monitor_conn_init;
+       mss->mss_private = mi;
+
+       if ( mbe->register_subsys_late( mss ) )
+       {
+               Debug( LDAP_DEBUG_ANY,
+                       "back_asyncmeta_monitor_db_open: "
+                       "failed to register connections subsystem" );
+               return -1;
+       }
+
+       mi->mi_monitor_info.mi_targets_mss = (monitor_subsys_t *)ch_calloc( 1, sizeof( monitor_subsys_t ) );
+       mss = mi->mi_monitor_info.mi_targets_mss;
+       mss->mss_name = "back-asyncmeta targets";
+       mss->mss_flags = MONITOR_F_PERSISTENT_CH;
+       mss->mss_open = asyncmeta_back_monitor_targets_init;
+       mss->mss_private = mi;
+
+       if ( mbe->register_subsys_late( mss ) )
+       {
+               Debug( LDAP_DEBUG_ANY,
+                       "ldap_back_monitor_db_open: "
+                       "failed to register operation subsystem" );
+               return -1;
+       }
+
+       return rc;
+}
+
+/*
+ * call from within asyncmeta_back_db_close()
+ */
+int
+asyncmeta_back_monitor_db_close( BackendDB *be )
+{
+       a_metainfo_t            *mi = (a_metainfo_t *) be->be_private;
+       int rc = 0;
+       if ( mi && !BER_BVISNULL( &mi->mi_monitor_info.mi_ndn ) ) {
+               BackendInfo             *bi;
+               monitor_extra_t         *mbe;
+
+               /* check if monitor is configured and usable */
+               bi = backend_info( "monitor" );
+               if ( bi && bi->bi_extra ) {
+                       mbe = bi->bi_extra;
+                       rc = mbe->unregister_entry( &mi->mi_monitor_info.mi_ndn );
+               }
+       }
+       return rc;
+}
+
+/*
+ * call from within asyncmeta_back_db_destroy()
+ */
+int
+asyncmeta_back_monitor_db_destroy( BackendDB *be )
+{
+       a_metainfo_t            *mi = (a_metainfo_t *) be->be_private;
+       if ( mi ) {
+               if ( mi->mi_monitor_info.mi_targets_rdn.bv_len > 0 ) {
+                       ch_free( mi->mi_monitor_info.mi_targets_rdn.bv_val );
+               }
+               if ( mi->mi_monitor_info.mi_conn_rdn.bv_len > 0 ) {
+                       ch_free( mi->mi_monitor_info.mi_conn_rdn.bv_val );
+               }
+       }
+       return 0;
+}