+
+static int
+pcache_entry_release( Operation *op, Entry *e, int rw )
+{
+ slap_overinst *on = (slap_overinst *)op->o_bd->bd_info;
+ cache_manager *cm = on->on_bi.bi_private;
+ BackendDB *db = op->o_bd;
+ int rc;
+
+ op->o_bd = &cm->db;
+ rc = be_entry_release_rw( op, e, rw );
+ op->o_bd = db;
+ return rc;
+}
+
+#ifdef PCACHE_MONITOR
+
+static int
+pcache_monitor_update(
+ Operation *op,
+ SlapReply *rs,
+ Entry *e,
+ void *priv )
+{
+ cache_manager *cm = (cache_manager *) priv;
+ query_manager *qm = cm->qm;
+
+ CachedQuery *qc;
+ BerVarray vals = NULL;
+
+ attr_delete( &e->e_attrs, ad_cachedQueryURL );
+ if ( ( SLAP_OPATTRS( rs->sr_attr_flags ) || ad_inlist( ad_cachedQueryURL, rs->sr_attrs ) )
+ && qm->templates != NULL )
+ {
+ QueryTemplate *tm;
+
+ for ( tm = qm->templates; tm != NULL; tm = tm->qmnext ) {
+ for ( qc = tm->query; qc; qc = qc->next ) {
+ struct berval bv;
+
+ if ( query2url( op, qc, &bv, 1 ) == 0 ) {
+ ber_bvarray_add_x( &vals, &bv, op->o_tmpmemctx );
+ }
+ }
+ }
+
+
+ if ( vals != NULL ) {
+ attr_merge_normalize( e, ad_cachedQueryURL, vals, NULL );
+ ber_bvarray_free_x( vals, op->o_tmpmemctx );
+ }
+ }
+
+ {
+ Attribute *a;
+ char buf[ SLAP_TEXT_BUFLEN ];
+ struct berval bv;
+
+ /* number of cached queries */
+ a = attr_find( e->e_attrs, ad_numQueries );
+ assert( a != NULL );
+
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%lu", cm->num_cached_queries );
+
+ if ( a->a_nvals != a->a_vals ) {
+ ber_bvreplace( &a->a_nvals[ 0 ], &bv );
+ }
+ ber_bvreplace( &a->a_vals[ 0 ], &bv );
+
+ /* number of cached entries */
+ a = attr_find( e->e_attrs, ad_numEntries );
+ assert( a != NULL );
+
+ bv.bv_val = buf;
+ bv.bv_len = snprintf( buf, sizeof( buf ), "%d", cm->cur_entries );
+
+ if ( a->a_nvals != a->a_vals ) {
+ ber_bvreplace( &a->a_nvals[ 0 ], &bv );
+ }
+ ber_bvreplace( &a->a_vals[ 0 ], &bv );
+ }
+
+ return SLAP_CB_CONTINUE;
+}
+
+static int
+pcache_monitor_free(
+ Entry *e,
+ void **priv )
+{
+ struct berval values[ 2 ];
+ Modification mod = { 0 };
+
+ const char *text;
+ char textbuf[ SLAP_TEXT_BUFLEN ];
+
+ int rc;
+
+ /* 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_olmPCache->soc_cname;
+ BER_BVZERO( &values[ 1 ] );
+
+ rc = modify_delete_values( e, &mod, 1, &text,
+ textbuf, sizeof( textbuf ) );
+ /* don't care too much about return code... */
+
+ /* remove attrs */
+ mod.sm_values = NULL;
+ mod.sm_desc = ad_cachedQueryURL;
+ mod.sm_numvals = 0;
+ rc = modify_delete_values( e, &mod, 1, &text,
+ textbuf, sizeof( textbuf ) );
+ /* don't care too much about return code... */
+
+ /* remove attrs */
+ mod.sm_values = NULL;
+ mod.sm_desc = ad_numQueries;
+ mod.sm_numvals = 0;
+ rc = modify_delete_values( e, &mod, 1, &text,
+ textbuf, sizeof( textbuf ) );
+ /* don't care too much about return code... */
+
+ /* remove attrs */
+ mod.sm_values = NULL;
+ mod.sm_desc = ad_numEntries;
+ mod.sm_numvals = 0;
+ rc = modify_delete_values( e, &mod, 1, &text,
+ textbuf, sizeof( textbuf ) );
+ /* don't care too much about return code... */
+
+ return SLAP_CB_CONTINUE;
+}
+
+/*
+ * call from within pcache_initialize()
+ */
+static int
+pcache_monitor_initialize( void )
+{
+ static int pcache_monitor_initialized = 0;
+
+ if ( backend_info( "monitor" ) == NULL ) {
+ return -1;
+ }
+
+ if ( pcache_monitor_initialized++ ) {
+ return 0;
+ }
+
+ return 0;
+}
+
+static int
+pcache_monitor_db_init( BackendDB *be )
+{
+ if ( pcache_monitor_initialize() == LDAP_SUCCESS ) {
+ SLAP_DBFLAGS( be ) |= SLAP_DBFLAG_MONITORING;
+ }
+
+ return 0;
+}
+
+static int
+pcache_monitor_db_open( BackendDB *be )
+{
+ slap_overinst *on = (slap_overinst *)be->bd_info;
+ cache_manager *cm = on->on_bi.bi_private;
+ Attribute *a, *next;
+ monitor_callback_t *cb = NULL;
+ int rc = 0;
+ BackendInfo *mi;
+ monitor_extra_t *mbe;
+ struct berval dummy = BER_BVC( "" );
+
+ if ( !SLAP_DBMONITORING( be ) ) {
+ return 0;
+ }
+
+ mi = backend_info( "monitor" );
+ if ( !mi || !mi->bi_extra ) {
+ SLAP_DBFLAGS( be ) ^= SLAP_DBFLAG_MONITORING;
+ return 0;
+ }
+ mbe = mi->bi_extra;
+
+ /* don't bother if monitor is not configured */
+ if ( !mbe->is_configured() ) {
+ static int warning = 0;
+
+ if ( warning++ == 0 ) {
+ Debug( LDAP_DEBUG_ANY, "pcache_monitor_db_open: "
+ "monitoring disabled; "
+ "configure monitor database to enable\n",
+ 0, 0, 0 );
+ }
+
+ return 0;
+ }
+
+ /* alloc as many as required (plus 1 for objectClass) */
+ a = attrs_alloc( 1 + 2 );
+ if ( a == NULL ) {
+ rc = 1;
+ goto cleanup;
+ }
+
+ a->a_desc = slap_schema.si_ad_objectClass;
+ attr_valadd( a, &oc_olmPCache->soc_cname, NULL, 1 );
+ next = a->a_next;
+
+ {
+ struct berval bv = BER_BVC( "0" );
+
+ next->a_desc = ad_numQueries;
+ attr_valadd( next, &bv, NULL, 1 );
+ next = next->a_next;
+
+ next->a_desc = ad_numEntries;
+ attr_valadd( next, &bv, NULL, 1 );
+ next = next->a_next;
+ }
+
+ cb = ch_calloc( sizeof( monitor_callback_t ), 1 );
+ cb->mc_update = pcache_monitor_update;
+ cb->mc_free = pcache_monitor_free;
+ cb->mc_private = (void *)cm;
+
+ /* make sure the database is registered; then add monitor attributes */
+ BER_BVZERO( &cm->monitor_ndn );
+ rc = mbe->register_overlay( be, on, &cm->monitor_ndn );
+ if ( rc == 0 ) {
+ rc = mbe->register_entry_attrs( &cm->monitor_ndn, a, cb,
+ &dummy, -1, &dummy);
+ }
+
+cleanup:;
+ if ( rc != 0 ) {
+ if ( cb != NULL ) {
+ ch_free( cb );
+ cb = NULL;
+ }
+
+ if ( a != NULL ) {
+ attrs_free( a );
+ a = NULL;
+ }
+ }
+
+ /* store for cleanup */
+ cm->monitor_cb = (void *)cb;
+
+ /* we don't need to keep track of the attributes, because
+ * bdb_monitor_free() takes care of everything */
+ if ( a != NULL ) {
+ attrs_free( a );
+ }
+
+ return rc;
+}
+
+static int
+pcache_monitor_db_close( BackendDB *be )
+{
+ slap_overinst *on = (slap_overinst *)be->bd_info;
+ cache_manager *cm = on->on_bi.bi_private;
+
+ if ( cm->monitor_cb != NULL ) {
+ BackendInfo *mi = backend_info( "monitor" );
+ monitor_extra_t *mbe;
+
+ if ( mi && &mi->bi_extra ) {
+ mbe = mi->bi_extra;
+ mbe->unregister_entry_callback( &cm->monitor_ndn,
+ (monitor_callback_t *)cm->monitor_cb,
+ NULL, 0, NULL );
+ }
+ }
+
+ return 0;
+}
+
+static int
+pcache_monitor_db_destroy( BackendDB *be )
+{
+ return 0;
+}
+
+#endif /* PCACHE_MONITOR */